Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 495