Root/
Source at commit 2381 created 10 years 21 days ago. By ifabio, Apply patch: (Credits to Thomas Jansen aka tja) - Reading options from all devices during boot. The options for the boot menu are only read from the devices rd(0,0) or bt(0,0). Consequently, boot menu options (e.g. "Quiet Boot", "Timeout", etc.) in plists on other devices (like most users have) are ignored. This patch extends the list of paths to search for the options plist on all devices that can be found. | |
---|---|
1 | /*␊ |
2 | * usb.c␊ |
3 | * ␊ |
4 | *␊ |
5 | * Created by mackerintel on 12/20/08.␊ |
6 | * Copyright 2008 mackerintel. All rights reserved.␊ |
7 | *␊ |
8 | */␊ |
9 | ␊ |
10 | #include "libsaio.h"␊ |
11 | #include "boot.h"␊ |
12 | #include "bootstruct.h"␊ |
13 | #include "pci.h"␊ |
14 | ␊ |
15 | #ifndef DEBUG_USB␊ |
16 | #define DEBUG_USB 0␊ |
17 | #endif␊ |
18 | ␊ |
19 | #if DEBUG_USB␊ |
20 | #define DBG(x...)␉printf(x)␊ |
21 | #else␊ |
22 | #define DBG(x...)␊ |
23 | #endif␊ |
24 | ␊ |
25 | ␊ |
26 | struct pciList␊ |
27 | {␊ |
28 | ␉pci_dt_t* pciDev;␊ |
29 | ␉struct pciList* next;␊ |
30 | };␊ |
31 | ␊ |
32 | struct pciList* usbList = NULL;␊ |
33 | ␊ |
34 | int legacy_off (pci_dt_t *pci_dev);␊ |
35 | int ehci_acquire (pci_dt_t *pci_dev);␊ |
36 | int uhci_reset (pci_dt_t *pci_dev);␊ |
37 | ␊ |
38 | // Add usb device to the list␊ |
39 | void notify_usb_dev(pci_dt_t *pci_dev)␊ |
40 | {␊ |
41 | ␉struct pciList* current = usbList;␊ |
42 | ␉if(!usbList)␊ |
43 | ␉{␊ |
44 | ␉␉usbList = (struct pciList*)malloc(sizeof(struct pciList));␊ |
45 | ␉␉usbList->next = NULL;␊ |
46 | ␉␉usbList->pciDev = pci_dev;␊ |
47 | ␉␉␊ |
48 | ␉}␊ |
49 | ␉else␊ |
50 | ␉{␊ |
51 | ␉␉while(current != NULL && current->next != NULL)␊ |
52 | ␉␉{␊ |
53 | ␉␉␉current = current->next;␊ |
54 | ␉␉}␊ |
55 | ␉␉current->next = (struct pciList*)malloc(sizeof(struct pciList));␊ |
56 | ␉␉current = current->next;␊ |
57 | ␉␉␊ |
58 | ␉␉current->pciDev = pci_dev;␊ |
59 | ␉␉current->next = NULL;␊ |
60 | ␉}␊ |
61 | }␊ |
62 | ␊ |
63 | // Loop through the list and call the apropriate patch function␊ |
64 | int usb_loop()␊ |
65 | {␊ |
66 | ␉int retVal = 1;␊ |
67 | ␉bool fix_ehci, fix_uhci, fix_usb, fix_legacy;␊ |
68 | ␉fix_ehci = fix_uhci = fix_usb = fix_legacy = false;␊ |
69 | ␉␊ |
70 | ␉if (getBoolForKey(kUSBBusFix, &fix_usb, &bootInfo->chameleonConfig))␊ |
71 | ␉{␊ |
72 | ␉␉fix_ehci = fix_uhci = fix_legacy = fix_usb;␉// Disable all if none set␊ |
73 | ␉}␊ |
74 | ␉else ␊ |
75 | ␉{␊ |
76 | ␉␉getBoolForKey(kEHCIacquire, &fix_ehci, &bootInfo->chameleonConfig);␊ |
77 | ␉␉getBoolForKey(kUHCIreset, &fix_uhci, &bootInfo->chameleonConfig);␊ |
78 | ␉␉getBoolForKey(kLegacyOff, &fix_legacy, &bootInfo->chameleonConfig);␊ |
79 | ␉}␊ |
80 | ␉␊ |
81 | ␉struct pciList* current = usbList;␊ |
82 | ␉␊ |
83 | ␉while(current)␊ |
84 | ␉{␊ |
85 | ␉␉switch (pci_config_read8(current->pciDev->dev.addr, PCI_CLASS_PROG))␊ |
86 | ␉␉{␊ |
87 | ␉␉␉// EHCI␊ |
88 | ␉␉␉case 0x20:␊ |
89 | ␉␉ ␉if(fix_ehci) retVal &= ehci_acquire(current->pciDev);␊ |
90 | ␉␉ ␉if(fix_legacy) retVal &= legacy_off(current->pciDev);␊ |
91 | ␉␉␉␉␊ |
92 | ␉␉␉␉break;␊ |
93 | ␉␉␉␉␊ |
94 | ␉␉␉// UHCI␊ |
95 | ␉␉␉case 0x00:␊ |
96 | ␉␉␉␉if (fix_uhci) retVal &= uhci_reset(current->pciDev);␊ |
97 | ␊ |
98 | ␉␉␉␉break;␊ |
99 | ␉␉}␊ |
100 | ␉␉␊ |
101 | ␉␉current = current->next;␊ |
102 | ␉}␊ |
103 | ␉return retVal;␊ |
104 | }␊ |
105 | ␊ |
106 | int legacy_off (pci_dt_t *pci_dev)␊ |
107 | {␊ |
108 | ␉// Set usb legacy off modification by Signal64␊ |
109 | ␉// NOTE: This *must* be called after the last file is loaded from the drive in the event that we are booting form usb.␊ |
110 | ␉// NOTE2: This should be called after any getc()/getchar() call. (aka, after the Wait=y keyworkd is used)␊ |
111 | ␉// AKA: Make this run immediatly before the kernel is called␊ |
112 | ␉uint32_t␉capaddr, opaddr; ␉␉␊ |
113 | ␉uint8_t␉␉eecp;␉␉␉␊ |
114 | ␉uint32_t␉usbcmd, usbsts, usbintr;␉␉␉␊ |
115 | ␉uint32_t␉usblegsup, usblegctlsts;␉␉␊ |
116 | ␉␊ |
117 | ␉int isOSowned;␊ |
118 | ␉int isBIOSowned;␊ |
119 | ␉␊ |
120 | ␉verbose("Setting Legacy USB Off on controller [%04x:%04x] at %02x:%2x.%x\n", ␊ |
121 | ␉␉␉pci_dev->vendor_id, pci_dev->device_id,␊ |
122 | ␉␉␉pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func);␊ |
123 | ␉␊ |
124 | ␉␊ |
125 | ␉// capaddr = Capability Registers = dev.addr + offset stored in dev.addr + 0x10 (USBBASE)␊ |
126 | ␉capaddr = pci_config_read32(pci_dev->dev.addr, 0x10);␉␊ |
127 | ␉␊ |
128 | ␉// opaddr = Operational Registers = capaddr + offset (8bit CAPLENGTH in Capability Registers + offset 0)␊ |
129 | ␉opaddr = capaddr + *((unsigned char*)(capaddr)); ␉␉␊ |
130 | ␉␊ |
131 | ␉// eecp = EHCI Extended Capabilities offset = capaddr HCCPARAMS bits 15:8␊ |
132 | ␉eecp=*((unsigned char*)(capaddr + 9));␊ |
133 | ␉␊ |
134 | ␉DBG("capaddr=%x opaddr=%x eecp=%x\n", capaddr, opaddr, eecp);␊ |
135 | ␉␊ |
136 | ␉usbcmd = *((unsigned int*)(opaddr));␉␉␉// Command Register␊ |
137 | ␉usbsts = *((unsigned int*)(opaddr + 4));␉␉// Status Register␊ |
138 | ␉usbintr = *((unsigned int*)(opaddr + 8));␉␉// Interrupt Enable Register␊ |
139 | ␉␊ |
140 | ␉DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);␊ |
141 | ␉␊ |
142 | ␉// read PCI Config 32bit USBLEGSUP (eecp+0) ␊ |
143 | ␉usblegsup = pci_config_read32(pci_dev->dev.addr, eecp);␊ |
144 | ␉␊ |
145 | ␉// informational only␊ |
146 | ␉isBIOSowned = !!((usblegsup) & (1 << (16)));␊ |
147 | ␉isOSowned = !!((usblegsup) & (1 << (24)));␊ |
148 | ␉␊ |
149 | ␉// read PCI Config 32bit USBLEGCTLSTS (eecp+4) ␊ |
150 | ␉usblegctlsts = pci_config_read32(pci_dev->dev.addr, eecp + 4);␊ |
151 | ␉␊ |
152 | ␉DBG("usblegsup=%08x isOSowned=%d isBIOSowned=%d usblegctlsts=%08x\n", usblegsup, isOSowned, isBIOSowned, usblegctlsts);␊ |
153 | ␉␊ |
154 | ␉// Reset registers to Legacy OFF␊ |
155 | ␉DBG("Clearing USBLEGCTLSTS\n");␊ |
156 | ␉pci_config_write32(pci_dev->dev.addr, eecp + 4, 0);␉//usblegctlsts␊ |
157 | ␉␊ |
158 | ␉// if delay value is in milliseconds it doesn't appear to work. ␊ |
159 | ␉// setting value to anything up to 65535 does not add the expected delay here.␊ |
160 | ␉delay(100);␊ |
161 | ␉␊ |
162 | ␉usbcmd = *((unsigned int*)(opaddr));␊ |
163 | ␉usbsts = *((unsigned int*)(opaddr + 4));␊ |
164 | ␉usbintr = *((unsigned int*)(opaddr + 8));␊ |
165 | ␉␊ |
166 | ␉DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);␊ |
167 | ␉␊ |
168 | ␉DBG("Clearing Registers\n");␊ |
169 | ␉␊ |
170 | ␉// clear registers to default␊ |
171 | ␉usbcmd = (usbcmd & 0xffffff00);␊ |
172 | ␉*((unsigned int*)(opaddr)) = usbcmd;␊ |
173 | ␉*((unsigned int*)(opaddr + 8)) = 0;␉␉␉␉␉//usbintr - clear interrupt registers␊ |
174 | ␉*((unsigned int*)(opaddr + 4)) = 0x1000;␉␉␉//usbsts - clear status registers ␉␊ |
175 | ␉pci_config_write32(pci_dev->dev.addr, eecp, 1);␉␉//usblegsup␊ |
176 | ␉␊ |
177 | ␉// get the results␊ |
178 | ␉usbcmd = *((unsigned int*)(opaddr));␊ |
179 | ␉usbsts = *((unsigned int*)(opaddr + 4));␊ |
180 | ␉usbintr = *((unsigned int*)(opaddr + 8));␊ |
181 | ␉␊ |
182 | ␉DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);␊ |
183 | ␉␊ |
184 | ␉// read 32bit USBLEGSUP (eecp+0) ␊ |
185 | ␉usblegsup = pci_config_read32(pci_dev->dev.addr, eecp);␊ |
186 | ␉␊ |
187 | ␉// informational only␊ |
188 | ␉isBIOSowned = !!((usblegsup) & (1 << (16)));␊ |
189 | ␉isOSowned = !!((usblegsup) & (1 << (24)));␊ |
190 | ␉␊ |
191 | ␉// read 32bit USBLEGCTLSTS (eecp+4) ␊ |
192 | ␉usblegctlsts = pci_config_read32(pci_dev->dev.addr, eecp + 4);␊ |
193 | ␉␊ |
194 | ␉DBG("usblegsup=%08x isOSowned=%d isBIOSowned=%d usblegctlsts=%08x\n", usblegsup, isOSowned, isBIOSowned, usblegctlsts);␊ |
195 | ␉␊ |
196 | ␉verbose("Legacy USB Off Done\n");␉␊ |
197 | ␉return 1;␊ |
198 | }␊ |
199 | ␊ |
200 | int ehci_acquire (pci_dt_t *pci_dev)␊ |
201 | {␊ |
202 | ␉int␉␉j, k;␊ |
203 | ␉uint32_t␉base;␊ |
204 | ␉uint8_t␉␉eecp;␊ |
205 | ␉uint8_t␉␉legacy[8];␊ |
206 | ␉bool␉␉isOwnershipConflict;␉␊ |
207 | ␉bool␉␉alwaysHardBIOSReset;␊ |
208 | ␊ |
209 | ␉alwaysHardBIOSReset = false;␉␊ |
210 | ␉if (!getBoolForKey(kEHCIhard, &alwaysHardBIOSReset, &bootInfo->chameleonConfig)) {␊ |
211 | ␉␉alwaysHardBIOSReset = true;␊ |
212 | ␉}␊ |
213 | ␊ |
214 | ␉pci_config_write16(pci_dev->dev.addr, 0x04, 0x0002);␊ |
215 | ␉base = pci_config_read32(pci_dev->dev.addr, 0x10);␊ |
216 | ␊ |
217 | ␉verbose("EHCI controller [%04x:%04x] at %02x:%2x.%x DMA @%x\n", ␊ |
218 | ␉␉pci_dev->vendor_id, pci_dev->device_id,␊ |
219 | ␉␉pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func, ␊ |
220 | ␉␉base);␊ |
221 | ␊ |
222 | ␉if (*((unsigned char*)base) < 0xc)␊ |
223 | ␉{␊ |
224 | ␉␉DBG("Config space too small: no legacy implementation\n");␊ |
225 | ␉␉return 1;␊ |
226 | ␉}␊ |
227 | ␉eecp = *((unsigned char*)(base + 9));␊ |
228 | ␉if (!eecp) {␊ |
229 | ␉␉DBG("No extended capabilities: no legacy implementation\n");␊ |
230 | ␉␉return 1;␊ |
231 | ␉}␊ |
232 | ␊ |
233 | ␉DBG("eecp=%x\n",eecp);␊ |
234 | ␊ |
235 | ␉// bad way to do it␊ |
236 | ␉// pci_conf_write(pci_dev->dev.addr, eecp, 4, 0x01000001);␊ |
237 | ␉for (j = 0; j < 8; j++) {␊ |
238 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
239 | ␉␉DBG("%02x ", legacy[j]);␊ |
240 | ␉}␊ |
241 | ␉DBG("\n");␊ |
242 | ␊ |
243 | ␉//Real Job: based on orByte's AppleUSBEHCI.cpp␊ |
244 | ␉//We try soft reset first - some systems hang on reboot with hard reset␊ |
245 | ␉// Definitely needed during reboot on 10.4.6␊ |
246 | ␊ |
247 | ␉isOwnershipConflict = (((legacy[3] & 1) != 0) && ((legacy[2] & 1) != 0));␊ |
248 | ␉if (!alwaysHardBIOSReset && isOwnershipConflict) {␊ |
249 | ␉␉DBG("EHCI - Ownership conflict - attempting soft reset ...\n");␊ |
250 | ␉␉DBG("EHCI - toggle OS Ownership to 0\n");␊ |
251 | ␉␉pci_config_write8(pci_dev->dev.addr, eecp + 3, 0);␊ |
252 | ␉␉for (k = 0; k < 25; k++) {␊ |
253 | ␉␉␉for (j = 0; j < 8; j++) {␊ |
254 | ␉␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
255 | ␉␉␉}␊ |
256 | ␉␉␉if (legacy[3] == 0) {␊ |
257 | ␉␉␉␉break;␊ |
258 | ␉␉␉}␊ |
259 | ␉␉␉delay(10);␊ |
260 | ␉␉}␊ |
261 | ␉}␉␊ |
262 | ␊ |
263 | ␉DBG("Found USBLEGSUP_ID - value %x:%x - writing OSOwned\n", legacy[3],legacy[2]);␊ |
264 | ␉pci_config_write8(pci_dev->dev.addr, eecp + 3, 1);␊ |
265 | ␊ |
266 | ␉// wait for kEHCI_USBLEGSUP_BIOSOwned bit to clear␊ |
267 | ␉for (k = 0; k < 25; k++) {␊ |
268 | ␉␉for (j = 0;j < 8; j++) {␊ |
269 | ␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
270 | ␉␉}␊ |
271 | ␉␉DBG ("%x:%x,",legacy[3],legacy[2]);␊ |
272 | ␉␉if (legacy[2] == 0) {␊ |
273 | ␉␉␉break;␊ |
274 | ␉␉}␊ |
275 | ␉␉delay(10);␊ |
276 | ␉}␊ |
277 | ␊ |
278 | ␉for (j = 0;j < 8; j++) {␊ |
279 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
280 | ␉}␊ |
281 | ␉isOwnershipConflict = ((legacy[2]) != 0);␊ |
282 | ␉if (isOwnershipConflict) {␊ |
283 | ␉␉// Soft reset has failed. Assume SMI being ignored␊ |
284 | ␉␉// Hard reset␊ |
285 | ␉␉// Force Clear BIOS BIT␊ |
286 | ␉␉DBG("EHCI - Ownership conflict - attempting hard reset ...\n");␉␉␉␊ |
287 | ␉␉DBG ("%x:%x\n",legacy[3],legacy[2]);␊ |
288 | ␉␉DBG("EHCI - Force BIOS Ownership to 0\n");␊ |
289 | ␊ |
290 | ␉␉pci_config_write8(pci_dev->dev.addr, eecp + 2, 0);␊ |
291 | ␉␉for (k = 0; k < 25; k++) {␊ |
292 | ␉␉␉for (j = 0; j < 8; j++) {␊ |
293 | ␉␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
294 | ␉␉␉}␊ |
295 | ␉␉␉DBG ("%x:%x,",legacy[3],legacy[2]);␊ |
296 | ␊ |
297 | ␉␉␉if ((legacy[2]) == 0) {␊ |
298 | ␉␉␉␉break;␊ |
299 | ␉␉␉}␊ |
300 | ␉␉␉delay(10);␉␊ |
301 | ␉␉}␉␉␊ |
302 | ␉␉// Disable further SMI events␊ |
303 | ␉␉for (j = 4; j < 8; j++) {␊ |
304 | ␉␉␉pci_config_write8(pci_dev->dev.addr, eecp + j, 0);␊ |
305 | ␉␉}␊ |
306 | ␉}␊ |
307 | ␊ |
308 | ␉for (j = 0; j < 8; j++) {␊ |
309 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
310 | ␉}␊ |
311 | ␊ |
312 | ␉DBG ("%x:%x\n",legacy[3],legacy[2]);␊ |
313 | ␊ |
314 | ␉// Final Ownership Resolution Check...␊ |
315 | ␉if (legacy[2] & 1) {␉␉␉␉␉␊ |
316 | ␉␉DBG("EHCI controller unable to take control from BIOS\n");␊ |
317 | ␉␉return 0;␊ |
318 | ␉}␊ |
319 | ␊ |
320 | ␉DBG("EHCI Acquire OS Ownership done\n");␉␊ |
321 | ␉return 1;␊ |
322 | }␊ |
323 | ␊ |
324 | int uhci_reset (pci_dt_t *pci_dev)␊ |
325 | {␊ |
326 | ␉uint32_t base, port_base;␊ |
327 | ␉␊ |
328 | ␉base = pci_config_read32(pci_dev->dev.addr, 0x20);␊ |
329 | ␉port_base = (base >> 5) & 0x07ff;␊ |
330 | ␊ |
331 | ␉verbose("UHCI controller [%04x:%04x] at %02x:%2x.%x base %x(%x)\n", ␊ |
332 | ␉␉pci_dev->vendor_id, pci_dev->device_id,␊ |
333 | ␉␉pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func, ␊ |
334 | ␉␉port_base, base);␊ |
335 | ␉␊ |
336 | ␉pci_config_write16(pci_dev->dev.addr, 0xc0, 0x8f00);␊ |
337 | ␊ |
338 | ␉outw (port_base, 0x0002);␊ |
339 | ␉delay(10);␊ |
340 | ␉outw (port_base+4,0);␊ |
341 | ␉delay(10);␊ |
342 | ␉outw (port_base,0);␊ |
343 | ␉return 1;␊ |
344 | }␊ |
345 |