Chameleon

Chameleon Svn Source Tree

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

Source at commit 728 created 13 years 2 months ago.
By meklort, Updated Symbols.dylib generation. Module linked list rework beginning. USB Legacy off patch still needs fixing. Added a new tool to generate the symbols.dylib. It's a fairly correct dylib file, however nm complains about it (it still works fine though). Updated Symbols.dylib file is smaller (~13%) that the old method and is a bit cleaner. dylib generation needs a bit of cleaning up though)
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: 728