Chameleon

Chameleon Svn Source Tree

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

Source at commit 429 created 13 years 9 months ago.
By meklort, Updated module system. Hooks can now be used within modules when cetaion functions are called in chameleon. Note that onle two hooks currently exist, more need to be added. I also updated the HelloWorld module to use a hook instead of print out right away.
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: 429