Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2182