Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2360