Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/libsaio/usb.c

Source at commit 307 created 12 years 11 months ago.
By ifabio, merge changes from trunk (929). Also merge the module changes from Azimutz branche (fix compile error) Also edited the info.plist into AHCIPortInjector.kext: http://forum.voodooprojects.org/index.php/topic,1170.0.html
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->bootConfig))
71{
72fix_ehci = fix_uhci = fix_legacy = fix_usb;// Disable all if none set
73}
74else
75{
76getBoolForKey(kEHCIacquire, &fix_ehci, &bootInfo->bootConfig);
77getBoolForKey(kUHCIreset, &fix_uhci, &bootInfo->bootConfig);
78getBoolForKey(kLegacyOff, &fix_legacy, &bootInfo->bootConfig);
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() 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->bootConfig)) {
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: 307