Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 150