Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 321