Chameleon Applications

Chameleon Applications Svn Source Tree

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

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

Archive Download this file

Revision: 214