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

Archive Download this file

Revision: 789