Chameleon

Chameleon Svn Source Tree

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

Source at commit 158 created 13 years 10 months ago.
By meklort, Update kernel patch routine, works on 10.6.0/1 kernel now. Fixed usb loop, and temperarily disabled legacy_off code
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
38void notify_usb_dev(pci_dt_t *pci_dev)
39{
40struct pciList* current = usbList;
41if(!usbList)
42{
43usbList = (struct pciList*)malloc(sizeof(struct pciList));
44usbList->next = NULL;
45usbList->pciDev = pci_dev;
46}
47else {
48while(current != NULL && current->next != NULL)
49{
50current = current->next;
51}
52current->next = (struct pciList*)malloc(sizeof(struct pciList));
53current = current->next;
54
55current->pciDev = pci_dev;
56current->next = NULL;
57}
58
59
60
61
62}
63
64int usb_loop()
65{
66bool fix_ehci, fix_uhci, fix_usb, fix_legacy;
67fix_ehci = fix_uhci = fix_usb = fix_legacy = true;
68
69
70
71if (!getBoolForKey(kUSBBusFix, &fix_usb, &bootInfo->bootConfig))
72{
73fix_ehci = fix_uhci = fix_legacy = true;// Enable all if none set
74}
75else
76{
77if(!getBoolForKey(kEHCIacquire, &fix_ehci, &bootInfo->bootConfig))
78{
79fix_ehci = false;
80}
81
82if(!getBoolForKey(kUHCIreset, &fix_uhci, &bootInfo->bootConfig))
83{
84fix_uhci = false;
85}
86
87if(!getBoolForKey(kLegacyOff, &fix_legacy, &bootInfo->bootConfig))
88{
89fix_legacy = false;
90}
91
92}
93
94
95struct pciList* current = usbList;
96while(current)
97{
98if(fix_uhci) uhci_reset(current->pciDev);
99if(fix_ehci) ehci_acquire(current->pciDev);
100//if(fix_legacy) legacy_off(current->pciDev);
101
102current = current->next;
103}
104
105return 1;
106}
107
108int legacy_off (pci_dt_t *pci_dev)
109{
110// Set usb legacy off modification by Signal64
111// NOTE: This *must* be called after the last file is loaded from the drive in the event that we are booting form usb.
112// NOTE2: This should be called after any getc() call. (aka, after the Wait=y keyworkd is used)
113// AKA: Make this run immediatly before the kernel is called
114uint32_tcapaddr, opaddr;
115uint8_teecp;
116uint32_tusbcmd, usbsts, usbintr;
117uint32_tusblegsup, usblegctlsts;
118
119int isOSowned;
120int isBIOSowned;
121
122verbose("Setting Legacy USB Off on controller [%04x:%04x] at %02x:%2x.%x\n",
123pci_dev->vendor_id, pci_dev->device_id,
124pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func);
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
201
202
203int ehci_acquire (pci_dt_t *pci_dev)
204{
205intj, k;
206uint32_tbase;
207uint8_teecp;
208uint8_tlegacy[8];
209boolisOwnershipConflict;
210boolalwaysHardBIOSReset;
211
212alwaysHardBIOSReset = false;
213if (!getBoolForKey(kEHCIhard, &alwaysHardBIOSReset, &bootInfo->bootConfig)) {
214alwaysHardBIOSReset = true;
215}
216
217pci_config_write16(pci_dev->dev.addr, 0x04, 0x0002);
218base = pci_config_read32(pci_dev->dev.addr, 0x10);
219
220verbose("EHCI controller [%04x:%04x] at %02x:%2x.%x DMA @%x\n",
221pci_dev->vendor_id, pci_dev->device_id,
222pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func,
223base);
224
225if (*((unsigned char*)base) < 0xc)
226{
227DBG("Config space too small: no legacy implementation\n");
228return 1;
229}
230eecp = *((unsigned char*)(base + 9));
231if (!eecp) {
232DBG("No extended capabilities: no legacy implementation\n");
233return 1;
234}
235
236DBG("eecp=%x\n",eecp);
237
238// bad way to do it
239// pci_conf_write(pci_dev->dev.addr, eecp, 4, 0x01000001);
240for (j = 0; j < 8; j++) {
241legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
242DBG("%02x ", legacy[j]);
243}
244DBG("\n");
245
246//Real Job: based on orByte's AppleUSBEHCI.cpp
247//We try soft reset first - some systems hang on reboot with hard reset
248// Definitely needed during reboot on 10.4.6
249
250isOwnershipConflict = ((legacy[3] & 1 != 0) && (legacy[2] & 1 != 0));
251if (!alwaysHardBIOSReset && isOwnershipConflict) {
252DBG("EHCI - Ownership conflict - attempting soft reset ...\n");
253DBG("EHCI - toggle OS Ownership to 0\n");
254pci_config_write8(pci_dev->dev.addr, eecp + 3, 0);
255for (k = 0; k < 25; k++) {
256for (j = 0; j < 8; j++) {
257legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
258}
259if (legacy[3] == 0) {
260break;
261}
262delay(10);
263}
264}
265
266DBG("Found USBLEGSUP_ID - value %x:%x - writing OSOwned\n", legacy[3],legacy[2]);
267pci_config_write8(pci_dev->dev.addr, eecp + 3, 1);
268
269// wait for kEHCI_USBLEGSUP_BIOSOwned bit to clear
270for (k = 0; k < 25; k++) {
271for (j = 0;j < 8; j++) {
272legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
273}
274DBG ("%x:%x,",legacy[3],legacy[2]);
275if (legacy[2] == 0) {
276break;
277}
278delay(10);
279}
280
281for (j = 0;j < 8; j++) {
282legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
283}
284isOwnershipConflict = ((legacy[2]) != 0);
285if (isOwnershipConflict) {
286// Soft reset has failed. Assume SMI being ignored
287// Hard reset
288// Force Clear BIOS BIT
289DBG("EHCI - Ownership conflict - attempting hard reset ...\n");
290DBG ("%x:%x\n",legacy[3],legacy[2]);
291DBG("EHCI - Force BIOS Ownership to 0\n");
292
293pci_config_write8(pci_dev->dev.addr, eecp + 2, 0);
294for (k = 0; k < 25; k++) {
295for (j = 0; j < 8; j++) {
296legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
297}
298DBG ("%x:%x,",legacy[3],legacy[2]);
299
300if ((legacy[2]) == 0) {
301break;
302}
303delay(10);
304}
305// Disable further SMI events
306for (j = 4; j < 8; j++) {
307pci_config_write8(pci_dev->dev.addr, eecp + j, 0);
308}
309}
310
311for (j = 0; j < 8; j++) {
312legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
313}
314
315DBG ("%x:%x\n",legacy[3],legacy[2]);
316
317// Final Ownership Resolution Check...
318if (legacy[2] & 1) {
319DBG("EHCI controller unable to take control from BIOS\n");
320return 0;
321}
322
323DBG("EHCI Acquire OS Ownership done\n");
324return 1;
325}
326
327int uhci_reset (pci_dt_t *pci_dev)
328{
329uint32_t base, port_base;
330
331base = pci_config_read32(pci_dev->dev.addr, 0x20);
332port_base = (base >> 5) & 0x07ff;
333
334verbose("UHCI controller [%04x:%04x] at %02x:%2x.%x base %x(%x)\n",
335pci_dev->vendor_id, pci_dev->device_id,
336pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func,
337port_base, base);
338
339pci_config_write16(pci_dev->dev.addr, 0xc0, 0x8f00);
340
341outw (port_base, 0x0002);
342delay(10);
343outw (port_base+4,0);
344delay(10);
345outw (port_base,0);
346return 1;
347}
348

Archive Download this file

Revision: 158