Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/trunk/i386/libsaio/usb.c

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

Archive Download this file

Revision: 173