Chameleon

Chameleon Svn Source Tree

Root/branches/i386/libsaio/usb.c

Source at commit 162 created 13 years 10 months ago.
By valv, Corrected branch root
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
25int ehci_acquire (pci_dt_t *pci_dev)
26{
27intj, k;
28uint32_tbase;
29uint8_teecp;
30uint8_tlegacy[8];
31boolisOwnershipConflict;
32boolalwaysHardBIOSReset;
33
34alwaysHardBIOSReset = false;
35if (!getBoolForKey(kEHCIhard, &alwaysHardBIOSReset, &bootInfo->bootConfig)) {
36alwaysHardBIOSReset = true;
37}
38
39pci_config_write16(pci_dev->dev.addr, 0x04, 0x0002);
40base = pci_config_read32(pci_dev->dev.addr, 0x10);
41
42verbose("EHCI controller [%04x:%04x] at %02x:%2x.%x DMA @%x\n",
43pci_dev->vendor_id, pci_dev->device_id,
44pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func,
45base);
46
47if (*((unsigned char*)base) < 0xc)
48{
49DBG("Config space too small: no legacy implementation\n");
50return 1;
51}
52eecp = *((unsigned char*)(base + 9));
53if (!eecp) {
54DBG("No extended capabilities: no legacy implementation\n");
55return 1;
56}
57
58DBG("eecp=%x\n",eecp);
59
60// bad way to do it
61// pci_conf_write(pci_dev->dev.addr, eecp, 4, 0x01000001);
62for (j = 0; j < 8; j++) {
63legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
64DBG("%02x ", legacy[j]);
65}
66DBG("\n");
67
68//Real Job: based on orByte's AppleUSBEHCI.cpp
69//We try soft reset first - some systems hang on reboot with hard reset
70// Definitely needed during reboot on 10.4.6
71
72isOwnershipConflict = ((legacy[3] & 1 != 0) && (legacy[2] & 1 != 0));
73if (!alwaysHardBIOSReset && isOwnershipConflict) {
74DBG("EHCI - Ownership conflict - attempting soft reset ...\n");
75DBG("EHCI - toggle OS Ownership to 0\n");
76pci_config_write8(pci_dev->dev.addr, eecp + 3, 0);
77for (k = 0; k < 25; k++) {
78for (j = 0; j < 8; j++) {
79legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
80}
81if (legacy[3] == 0) {
82break;
83}
84delay(10);
85}
86}
87
88DBG("Found USBLEGSUP_ID - value %x:%x - writing OSOwned\n", legacy[3],legacy[2]);
89pci_config_write8(pci_dev->dev.addr, eecp + 3, 1);
90
91// wait for kEHCI_USBLEGSUP_BIOSOwned bit to clear
92for (k = 0; k < 25; k++) {
93for (j = 0;j < 8; j++) {
94legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
95}
96DBG ("%x:%x,",legacy[3],legacy[2]);
97if (legacy[2] == 0) {
98break;
99}
100delay(10);
101}
102
103for (j = 0;j < 8; j++) {
104legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
105}
106isOwnershipConflict = ((legacy[2]) != 0);
107if (isOwnershipConflict) {
108// Soft reset has failed. Assume SMI being ignored
109// Hard reset
110// Force Clear BIOS BIT
111DBG("EHCI - Ownership conflict - attempting hard reset ...\n");
112DBG ("%x:%x\n",legacy[3],legacy[2]);
113DBG("EHCI - Force BIOS Ownership to 0\n");
114
115pci_config_write8(pci_dev->dev.addr, eecp + 2, 0);
116for (k = 0; k < 25; k++) {
117for (j = 0; j < 8; j++) {
118legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
119}
120DBG ("%x:%x,",legacy[3],legacy[2]);
121
122if ((legacy[2]) == 0) {
123break;
124}
125delay(10);
126}
127// Disable further SMI events
128for (j = 4; j < 8; j++) {
129pci_config_write8(pci_dev->dev.addr, eecp + j, 0);
130}
131}
132
133for (j = 0; j < 8; j++) {
134legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);
135}
136
137DBG ("%x:%x\n",legacy[3],legacy[2]);
138
139// Final Ownership Resolution Check...
140if (legacy[2] & 1) {
141DBG("EHCI controller unable to take control from BIOS\n");
142return 0;
143}
144
145DBG("EHCI Acquire OS Ownership done\n");
146return 1;
147}
148
149int legacy_off (pci_dt_t *pci_dev)
150{
151// Set usb legacy off modification by Signal64
152uint32_tcapaddr, opaddr;
153uint8_teecp;
154uint32_tusbcmd, usbsts, usbintr;
155uint32_tusblegsup, usblegctlsts;
156
157int isOSowned;
158int isBIOSowned;
159
160verbose("Setting Legacy USB Off on controller [%04x:%04x] at %02x:%2x.%x\n",
161pci_dev->vendor_id, pci_dev->device_id,
162pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func);
163
164// capaddr = Capability Registers = dev.addr + offset stored in dev.addr + 0x10 (USBBASE)
165capaddr = pci_config_read32(pci_dev->dev.addr, 0x10);
166
167// opaddr = Operational Registers = capaddr + offset (8bit CAPLENGTH in Capability Registers + offset 0)
168opaddr = capaddr + *((unsigned char*)(capaddr));
169
170// eecp = EHCI Extended Capabilities offset = capaddr HCCPARAMS bits 15:8
171eecp=*((unsigned char*)(capaddr + 9));
172
173DBG("capaddr=%x opaddr=%x eecp=%x\n", capaddr, opaddr, eecp);
174
175usbcmd = *((unsigned int*)(opaddr));// Command Register
176usbsts = *((unsigned int*)(opaddr + 4));// Status Register
177usbintr = *((unsigned int*)(opaddr + 8));// Interrupt Enable Register
178
179DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);
180
181// read PCI Config 32bit USBLEGSUP (eecp+0)
182usblegsup = pci_config_read32(pci_dev->dev.addr, eecp);
183
184// informational only
185isBIOSowned = !!((usblegsup) & (1 << (16)));
186isOSowned = !!((usblegsup) & (1 << (24)));
187
188// read PCI Config 32bit USBLEGCTLSTS (eecp+4)
189usblegctlsts = pci_config_read32(pci_dev->dev.addr, eecp + 4);
190
191DBG("usblegsup=%08x isOSowned=%d isBIOSowned=%d usblegctlsts=%08x\n", usblegsup, isOSowned, isBIOSowned, usblegctlsts);
192
193// Reset registers to Legacy OFF
194DBG("Clearing USBLEGCTLSTS\n");
195pci_config_write32(pci_dev->dev.addr, eecp + 4, 0);//usblegctlsts
196
197// if delay value is in milliseconds it doesn't appear to work.
198// setting value to anything up to 65535 does not add the expected delay here.
199delay(100);
200
201usbcmd = *((unsigned int*)(opaddr));
202usbsts = *((unsigned int*)(opaddr + 4));
203usbintr = *((unsigned int*)(opaddr + 8));
204
205DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);
206
207DBG("Clearing Registers\n");
208
209// clear registers to default
210usbcmd = (usbcmd & 0xffffff00);
211*((unsigned int*)(opaddr)) = usbcmd;
212*((unsigned int*)(opaddr + 8)) = 0;//usbintr - clear interrupt registers
213*((unsigned int*)(opaddr + 4)) = 0x1000;//usbsts - clear status registers
214pci_config_write32(pci_dev->dev.addr, eecp, 1);//usblegsup
215
216// get the results
217usbcmd = *((unsigned int*)(opaddr));
218usbsts = *((unsigned int*)(opaddr + 4));
219usbintr = *((unsigned int*)(opaddr + 8));
220
221DBG("usbcmd=%08x usbsts=%08x usbintr=%08x\n", usbcmd, usbsts, usbintr);
222
223// read 32bit USBLEGSUP (eecp+0)
224usblegsup = pci_config_read32(pci_dev->dev.addr, eecp);
225
226// informational only
227isBIOSowned = !!((usblegsup) & (1 << (16)));
228isOSowned = !!((usblegsup) & (1 << (24)));
229
230// read 32bit USBLEGCTLSTS (eecp+4)
231usblegctlsts = pci_config_read32(pci_dev->dev.addr, eecp + 4);
232
233DBG("usblegsup=%08x isOSowned=%d isBIOSowned=%d usblegctlsts=%08x\n", usblegsup, isOSowned, isBIOSowned, usblegctlsts);
234
235verbose("Legacy USB Off Done\n");
236return 1;
237}
238
239int uhci_reset (pci_dt_t *pci_dev)
240{
241uint32_t base, port_base;
242
243base = pci_config_read32(pci_dev->dev.addr, 0x20);
244port_base = (base >> 5) & 0x07ff;
245
246verbose("UHCI controller [%04x:%04x] at %02x:%2x.%x base %x(%x)\n",
247pci_dev->vendor_id, pci_dev->device_id,
248pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func,
249port_base, base);
250
251pci_config_write16(pci_dev->dev.addr, 0xc0, 0x8f00);
252
253outw (port_base, 0x0002);
254delay(10);
255outw (port_base+4,0);
256delay(10);
257outw (port_base,0);
258return 1;
259}
260

Archive Download this file

Revision: 162