Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 341