Chameleon

Chameleon Svn Source Tree

Root/branches/meklortOld/i386/modules/USBFix/usb.c

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

Archive Download this file

Revision: 1166