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 "bootstruct.h"␊ |
12 | #include "pci.h"␊ |
13 | ␊ |
14 | #ifndef DEBUG_USB␊ |
15 | #define DEBUG_USB 0␊ |
16 | #endif␊ |
17 | ␊ |
18 | #if DEBUG_USB␊ |
19 | #define DBG(x...)␉printf(x)␊ |
20 | #else␊ |
21 | #define DBG(x...)␊ |
22 | #endif␊ |
23 | ␊ |
24 | int ehci_acquire (pci_dt_t *pci_dev)␊ |
25 | {␊ |
26 | ␉int j,k;␊ |
27 | ␉␊ |
28 | ␉uint32_t␉base;␊ |
29 | ␉uint8_t␉␉eecp;␊ |
30 | ␉uint8_t␉␉legacy[8];␊ |
31 | ␉␊ |
32 | ␉bool isOwnershipConflict;␊ |
33 | ␉bool alwaysHardBIOSReset;␊ |
34 | ␊ |
35 | ␉if (!getBoolForKey("EHCIhard", &alwaysHardBIOSReset, &bootInfo->bootConfig))␊ |
36 | ␉␉alwaysHardBIOSReset = 1;␉␊ |
37 | ␉␊ |
38 | ␉pci_config_write16(pci_dev->dev.addr, 0x04, 0x0002);␊ |
39 | ␉base = pci_config_read32(pci_dev->dev.addr, 0x10);␊ |
40 | ␉␊ |
41 | ␉verbose("EHCI controller [%04x:%04x] at %02x:%2x.%x DMA @%x\n", ␊ |
42 | ␉␉pci_dev->vendor_id, pci_dev->device_id,␊ |
43 | ␉␉pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func, ␊ |
44 | ␉␉base);␊ |
45 | ␊ |
46 | ␉if (*((unsigned char*)base) < 0xc)␊ |
47 | ␉{␊ |
48 | ␉␉DBG("Config space too small: no legacy implementation\n");␊ |
49 | ␉␉return 1;␊ |
50 | ␉}␊ |
51 | ␉eecp=*((unsigned char*)(base + 9));␊ |
52 | ␉if (!eecp)␊ |
53 | ␉{␊ |
54 | ␉␉DBG("No extended capabilities: no legacy implementation\n");␊ |
55 | ␉␉return 1;␊ |
56 | ␉}␊ |
57 | ␊ |
58 | ␉DBG("eecp=%x\n",eecp);␊ |
59 | ␊ |
60 | ␉// bad way to do it␊ |
61 | ␉//␉␉␉pci_conf_write(pci_dev->dev.addr, eecp, 4, 0x01000001);␊ |
62 | ␉for (j = 0; j < 8; j++)␊ |
63 | ␉{␊ |
64 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
65 | ␉␉DBG("%02x ",legacy[j]);␊ |
66 | ␉}␊ |
67 | ␉DBG("\n");␊ |
68 | ␊ |
69 | ␉//Real Job: based on orByte's AppleUSBEHCI.cpp␊ |
70 | ␉//We try soft reset first - some systems hang on reboot with hard reset␊ |
71 | ␉// Definitely needed during reboot on 10.4.6␊ |
72 | ␊ |
73 | ␉isOwnershipConflict = ((legacy[3] & 1 != 0) && (legacy[2] & 1 != 0));␊ |
74 | ␉if (!alwaysHardBIOSReset && isOwnershipConflict) ␊ |
75 | ␉{␊ |
76 | ␉␉DBG("EHCI - Ownership conflict - attempting soft reset ...\n");␊ |
77 | ␉␉DBG("EHCI - toggle OS Ownership to 0\n");␊ |
78 | ␉␉pci_config_write8(pci_dev->dev.addr, eecp + 3, 0);␊ |
79 | ␉␉for (k = 0; k < 25; k++)␊ |
80 | ␉␉{␊ |
81 | ␉␉␉for (j = 0; j < 8; j++)␊ |
82 | ␉␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
83 | ␉␉␉if (legacy[3] == 0)␊ |
84 | ␉␉␉␉break;␊ |
85 | ␉␉␉delay(10);␊ |
86 | ␉␉}␊ |
87 | ␉}␉␊ |
88 | ␉␊ |
89 | ␉DBG("Found USBLEGSUP_ID - value %x:%x - writing OSOwned\n", legacy[3],legacy[2]);␊ |
90 | ␉pci_config_write8(pci_dev->dev.addr, eecp + 3, 1);␊ |
91 | ␉␊ |
92 | ␉// wait for kEHCI_USBLEGSUP_BIOSOwned bit to clear␊ |
93 | ␉for (k = 0; k < 25; k++)␊ |
94 | ␉{␊ |
95 | ␉␉for (j = 0;j < 8; j++)␊ |
96 | ␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
97 | ␉␉DBG ("%x:%x,",legacy[3],legacy[2]);␊ |
98 | ␉␉if (legacy[2] == 0)␊ |
99 | ␉␉␉break;␊ |
100 | ␉␉delay(10);␊ |
101 | ␉}␊ |
102 | ␉␊ |
103 | ␉for (j = 0;j < 8; j++)␊ |
104 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
105 | ␉isOwnershipConflict = ((legacy[2]) != 0);␊ |
106 | ␉if (isOwnershipConflict) ␊ |
107 | ␉{␊ |
108 | ␉␉// Soft reset has failed. Assume SMI being ignored␊ |
109 | ␉␉// Hard reset␊ |
110 | ␉␉// Force Clear BIOS BIT␊ |
111 | ␊ |
112 | ␉␉DBG("EHCI - Ownership conflict - attempting hard reset ...\n");␉␉␉␊ |
113 | ␉␉DBG ("%x:%x\n",legacy[3],legacy[2]);␊ |
114 | ␉␉DBG("EHCI - Force BIOS Ownership to 0\n");␊ |
115 | ␊ |
116 | ␉␉pci_config_write8(pci_dev->dev.addr, eecp + 2, 0);␊ |
117 | ␉␉for (k = 0; k < 25; k++)␊ |
118 | ␉␉{␊ |
119 | ␉␉␉for (j = 0; j < 8; j++)␊ |
120 | ␉␉␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
121 | ␉␉␉DBG ("%x:%x,",legacy[3],legacy[2]);␊ |
122 | ␊ |
123 | ␉␉␉if ((legacy[2]) == 0)␊ |
124 | ␉␉␉␉break;␊ |
125 | ␉␉␉delay(10);␉␊ |
126 | ␉␉}␉␉␊ |
127 | ␉␉// Disable further SMI events␊ |
128 | ␉␉for (j = 4; j < 8; j++)␊ |
129 | ␉␉␉pci_config_write8(pci_dev->dev.addr, eecp + j, 0);␊ |
130 | ␉}␊ |
131 | ␉␊ |
132 | ␉for (j = 0; j < 8; j++)␊ |
133 | ␉␉legacy[j] = pci_config_read8(pci_dev->dev.addr, eecp + j);␊ |
134 | ␊ |
135 | ␉DBG ("%x:%x\n",legacy[3],legacy[2]);␊ |
136 | ␊ |
137 | ␉// Final Ownership Resolution Check...␊ |
138 | ␉if (legacy[2]&1)␊ |
139 | ␉{␉␉␉␉␉␊ |
140 | ␉␉DBG("EHCI controller unable to take control from BIOS\n");␊ |
141 | ␉␉return 0;␊ |
142 | ␉}␊ |
143 | ␉␊ |
144 | ␉DBG("EHCI Acquire OS Ownership done\n");␉␊ |
145 | ␉return 1;␊ |
146 | }␊ |
147 | ␊ |
148 | int uhci_reset (pci_dt_t *pci_dev)␊ |
149 | {␊ |
150 | ␉uint32_t base, port_base;␊ |
151 | ␉␊ |
152 | ␉base = pci_config_read32(pci_dev->dev.addr, 0x20);␊ |
153 | ␉port_base = (base >> 5) & 0x07ff;␊ |
154 | ␊ |
155 | ␉verbose("UHCI controller [%04x:%04x] at %02x:%2x.%x base %x(%x)\n", ␊ |
156 | ␉␉pci_dev->vendor_id, pci_dev->device_id,␊ |
157 | ␉␉pci_dev->dev.bits.bus, pci_dev->dev.bits.dev, pci_dev->dev.bits.func, ␊ |
158 | ␉␉port_base, base);␊ |
159 | ␉␊ |
160 | ␉pci_config_write16(pci_dev->dev.addr, 0xc0, 0x8f00);␊ |
161 | ␊ |
162 | ␉outw (port_base, 0x0002);␊ |
163 | ␉delay(10);␊ |
164 | ␉outw (port_base+4,0);␊ |
165 | ␉delay(10);␊ |
166 | ␉outw (port_base,0);␊ |
167 | ␉return 1;␊ |
168 | }␊ |
169 | |