PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
hcd.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "usbdpriv.h"
12
13#if 0
14static UsbdMemoryPool_t *memPool_unused = NULL;
15#endif
16
17static void *hcdMemoryBuffer;
18
19void hcdProcessIntr(void)
20{
21 volatile OhciRegs *ohciRegs;
22 volatile HcCA *hcHCCA;
23 int intrFlags;
24 UsbdHcTD_t *doneQueue;
25 UsbdHcTD_t *prev;
26 UsbdHcTD_t *next_tmp1;
27 UsbdHcTD_t *next_tmp2;
28
29 ohciRegs = memPool->m_ohciRegs;
30 memPool->m_interruptCounters[0] += 1;
31 hcHCCA = memPool->m_hcHCCA;
32 intrFlags = ohciRegs->HcInterruptStatus & ohciRegs->HcInterruptEnable;
33 if ( (intrFlags & OHCI_INT_SO) != 0 )
34 {
35 dbg_printf("HC: Scheduling overrun\n");
36 ohciRegs->HcInterruptStatus = OHCI_INT_SO;
37 intrFlags &= ~OHCI_INT_SO;
38 memPool->m_interruptCounters[1] += 1;
39 }
40 doneQueue = (UsbdHcTD_t *)((uiptr)hcHCCA->DoneHead & ~0xF);
41 prev = NULL;
42 if ( doneQueue )
43 {
44 hcHCCA->DoneHead = NULL;
45 ohciRegs->HcInterruptStatus = OHCI_INT_WDH;
46
47 // reverse queue
48 while ( doneQueue )
49 {
50 next_tmp1 = doneQueue;
51 doneQueue = doneQueue->m_next;
52 next_tmp1->m_next = prev;
53 prev = next_tmp1;
54 }
55 for ( ; prev; prev = next_tmp2 )
56 {
57 next_tmp2 = prev->m_next;
58 if ( prev < memPool->m_hcTdBuf || prev >= memPool->m_hcTdBufEnd )
59 {
60 if ( (UsbdHcIsoTD_t *)prev >= memPool->m_hcIsoTdBuf && (UsbdHcIsoTD_t *)prev < memPool->m_hcIsoTdBufEnd )
61 processDoneQueue_IsoTd((UsbdHcIsoTD_t *)prev);
62 }
63 else
64 {
65 processDoneQueue_GenTd(prev);
66 }
67 }
68 intrFlags &= ~OHCI_INT_WDH;
69 memPool->m_interruptCounters[2] += 1;
70 }
71 if ( (intrFlags & OHCI_INT_SF) != 0 )
72 {
73 ohciRegs->HcInterruptStatus = OHCI_INT_SF;
74 handleTimerList();
75 intrFlags &= ~OHCI_INT_SF;
76 memPool->m_interruptCounters[3] += 1;
77 }
78 if ( (intrFlags & OHCI_INT_RD) != 0 )
79 {
80 ohciRegs->HcInterruptStatus = OHCI_INT_RD;
81 intrFlags &= ~OHCI_INT_RD;
82 memPool->m_interruptCounters[4] += 1;
83 }
84 if ( (intrFlags & OHCI_INT_UE) != 0 )
85 {
86 dbg_printf("HC: Unrecoverable error\n");
87 ohciRegs->HcInterruptStatus = OHCI_INT_UE;
88 intrFlags &= ~OHCI_INT_UE;
89 memPool->m_interruptCounters[5] += 1;
90 }
91 if ( (intrFlags & OHCI_INT_FNO) != 0 )
92 {
93 ohciRegs->HcInterruptStatus = OHCI_INT_FNO;
94 intrFlags &= ~OHCI_INT_FNO;
95 memPool->m_interruptCounters[6] += 1;
96 }
97 if ( (intrFlags & OHCI_INT_RHSC) != 0 )
98 {
99 dbg_printf("RHSC\n");
100 ohciRegs->HcInterruptStatus = OHCI_INT_RHSC;
101 handleRhsc();
102 intrFlags &= ~OHCI_INT_RHSC;
103 memPool->m_interruptCounters[7] += 1;
104 }
105 if ( (intrFlags & OHCI_INT_OC) != 0 )
106 {
107 ohciRegs->HcInterruptStatus = OHCI_INT_OC;
108 intrFlags &= ~OHCI_INT_OC;
109 memPool->m_interruptCounters[8] += 1;
110 }
111 intrFlags &= ~OHCI_INT_MIE;
112 if ( intrFlags )
113 {
114 dbg_printf("Disable intr: %d\n", intrFlags);
115 ohciRegs->HcInterruptDisable = intrFlags;
116 }
117}
118
119void PostIntrEnableFunction(void)
120{
121 volatile int lw_busy;
122
123 lw_busy = 0;
124 memPool->m_ohciRegs->HcInterruptDisable = OHCI_INT_MIE;
125 do
126 {
127 u32 val;
128 val = *((volatile u32 *)0xBFC00000);
129 __asm__ __volatile__(" " : "=r"(val));
130 lw_busy -= 1;
131 } while ( lw_busy > 0 );
132 memPool->m_ohciRegs->HcInterruptEnable = OHCI_INT_MIE;
133}
134
135static int initHardware(volatile OhciRegs *ohciRegs)
136{
137 int i;
138
139 dbg_printf("Host Controller...\n");
140 ohciRegs->HcInterruptDisable = ~0;
141 ohciRegs->HcControl &= ~0x3Cu;
142 DelayThread(2000);
143 ohciRegs->HcCommandStatus = OHCI_COM_HCR;
144 ohciRegs->HcControl = 0;
145 for ( i = 1; i < 1000; i += 1 )
146 {
147 volatile int lw_busy;
148
149 if ( (ohciRegs->HcCommandStatus & OHCI_COM_HCR) == 0 )
150 {
151 dbg_printf("HC reset done\n");
152 return 0;
153 }
154
155 lw_busy = 0;
156 do
157 {
158 u32 val;
159 val = *((volatile u32 *)0xBFC00000);
160 __asm__ __volatile__(" " : "=r"(val));
161 lw_busy -= 1;
162 } while ( lw_busy > 0 );
163 }
164 return -1;
165}
166
167int initHcdStructs(void)
168{
169 int memSize;
170 void *memBuf_1;
171 HcCA *hcCommArea;
172 UsbdHcIsoTD_t *hcIsoTdBuf;
173 UsbdHcTD_t *hcTdBuf;
174 int i;
175 UsbdHcED_t *hcEdBufForEndpoint;
176 UsbdHcED_t *hcEdBuf;
177 UsbdEndpoint_t *endpointBuf;
178 UsbdDevice_t *deviceTreeBuf;
179 UsbdIoRequest_t *ioReqBuf;
180 UsbdIoRequest_t **hcIsoTdToIoReqLUT;
181 UsbdIoRequest_t **hcTdToIoReqLUT;
182 UsbdIoRequest_t **devDescBuf;
183 volatile OhciRegs *ohciRegs;
184
185 ohciRegs = (volatile OhciRegs *)OHCI_REG_BASE;
186 if ( initHardware(ohciRegs) < 0 )
187 return -1;
188 *(vu32 *)0xBF801570 |= 0x8000000u;
189 *(vu32 *)0xBF801680 = 1;
190 dbg_printf("Structs...\n");
191 memSize = 0 + 28 + sizeof(HcCA) + sizeof(UsbdHcIsoTD_t) * usbConfig.m_maxIsoTransfDesc
192 + sizeof(UsbdHcTD_t) * usbConfig.m_maxTransfDesc + sizeof(UsbdHcED_t) * usbConfig.m_maxEndpoints
193 + sizeof(UsbdHcED_t) * 66 + sizeof(UsbdEndpoint_t) * usbConfig.m_maxEndpoints
194 + sizeof(UsbdDevice_t) * usbConfig.m_maxDevices + sizeof(UsbdIoRequest_t) * usbConfig.m_maxIoReqs
195 + sizeof(UsbdIoRequest_t *) * usbConfig.m_maxIsoTransfDesc
196 + sizeof(UsbdIoRequest_t *) * usbConfig.m_maxTransfDesc
197 + usbConfig.m_maxStaticDescSize * usbConfig.m_maxDevices;
198 memBuf_1 = AllocSysMemoryWrap(memSize);
199 if ( !memBuf_1 )
200 return -1;
201 if ( ((uiptr)memBuf_1) & 0xFF )
202 {
203 FreeSysMemoryWrap(memBuf_1);
204 return -1;
205 }
206 hcdMemoryBuffer = memBuf_1;
207 hcCommArea = (HcCA *)memBuf_1;
208 bzero(memBuf_1, memSize);
209 hcIsoTdBuf = (UsbdHcIsoTD_t *)(((uiptr)memBuf_1 + (28 + sizeof(HcCA) - 1)) & 0xFFFFFFE0);
210#if 0
211 *(UsbdConfig_t **)((u8 *)hcIsoTdBuf - 28) = &usbConfig;
212#endif
213 hcTdBuf = (UsbdHcTD_t *)&hcIsoTdBuf[usbConfig.m_maxIsoTransfDesc];
214 hcEdBufForEndpoint = (UsbdHcED_t *)&hcTdBuf[usbConfig.m_maxTransfDesc];
215 hcEdBuf = (UsbdHcED_t *)&hcEdBufForEndpoint[usbConfig.m_maxEndpoints];
216 memPool = (UsbdMemoryPool_t *)&hcEdBuf[66];
217#if 0
218 memPool_unused = memPool;
219#endif
220 endpointBuf = (UsbdEndpoint_t *)&memPool[1];
221 deviceTreeBuf = (UsbdDevice_t *)&endpointBuf[usbConfig.m_maxEndpoints];
222 ioReqBuf = (UsbdIoRequest_t *)&deviceTreeBuf[usbConfig.m_maxDevices];
223 hcIsoTdToIoReqLUT = (UsbdIoRequest_t **)&ioReqBuf[usbConfig.m_maxIoReqs];
224 hcTdToIoReqLUT = &hcIsoTdToIoReqLUT[usbConfig.m_maxIsoTransfDesc];
225 devDescBuf = &hcTdToIoReqLUT[usbConfig.m_maxTransfDesc];
226 usbConfig.m_allocatedSize_unused += memSize;
227 memPool->m_ohciRegs = ohciRegs;
228 memPool->m_hcEdBuf = hcEdBuf;
229 memPool->m_hcIsoTdToIoReqLUT = hcIsoTdToIoReqLUT;
230 memPool->m_hcTdToIoReqLUT = hcTdToIoReqLUT;
231 memPool->m_endpointBuf = endpointBuf;
232 memPool->m_hcHCCA = (volatile HcCA *)(((uiptr)memBuf_1 & 0x1FFFFFFF) | 0xA0000000);
233 for ( i = 0; i < usbConfig.m_maxEndpoints; i += 1 )
234 {
235 endpointBuf[i].m_id = i;
236 endpointBuf[i].m_hcEd = &hcEdBufForEndpoint[i];
237 endpointBuf[i].m_prev = memPool->m_freeEpListEnd;
238 if ( memPool->m_freeEpListEnd )
239 memPool->m_freeEpListEnd->m_next = &endpointBuf[i];
240 else
241 memPool->m_freeEpListStart = &endpointBuf[i];
242 endpointBuf[i].m_next = NULL;
243 memPool->m_freeEpListEnd = &endpointBuf[i];
244 }
245 memPool->m_tdQueueEnd = NULL;
246 memPool->m_tdQueueStart = NULL;
247 memPool->m_deviceTreeBuf = deviceTreeBuf;
248 for ( i = 0; i < usbConfig.m_maxDevices; i += 1 )
249 {
250 deviceTreeBuf[i].m_functionAddress = i;
251 deviceTreeBuf[i].m_id = (u8)i;
252 deviceTreeBuf[i].m_staticDeviceDescPtr = (u8 *)devDescBuf + (usbConfig.m_maxStaticDescSize * i);
253 deviceTreeBuf[i].m_prev = memPool->m_freeDeviceListEnd;
254 if ( memPool->m_freeDeviceListEnd )
255 memPool->m_freeDeviceListEnd->m_next = &deviceTreeBuf[i];
256 else
257 memPool->m_freeDeviceListStart = &deviceTreeBuf[i];
258 deviceTreeBuf[i].m_next = NULL;
259 memPool->m_freeDeviceListEnd = &deviceTreeBuf[i];
260 }
261 memPool->m_deviceTreeRoot = attachChildDevice(NULL, 0); // virtual root
262 memPool->m_deviceTreeRoot->m_magicPowerValue = 2;
263 attachChildDevice(memPool->m_deviceTreeRoot, 1u); // root hub port 0
264 attachChildDevice(memPool->m_deviceTreeRoot, 2u); // root hub port 1
265 memPool->m_ioReqBufPtr = ioReqBuf;
266 for ( i = 0; i < usbConfig.m_maxIoReqs; i += 1 )
267 {
268 ioReqBuf[i].m_id = i;
269 ioReqBuf[i].m_prev = memPool->m_freeIoReqListEnd;
270 if ( memPool->m_freeIoReqListEnd )
271 memPool->m_freeIoReqListEnd->m_next = &ioReqBuf[i];
272 else
273 memPool->m_freeIoReqList = &ioReqBuf[i];
274 ioReqBuf[i].m_next = NULL;
275 memPool->m_freeIoReqListEnd = &ioReqBuf[i];
276 }
277 memPool->m_freeHcTdList = hcTdBuf;
278 memPool->m_hcTdBuf = hcTdBuf;
279 memPool->m_hcTdBufEnd = &hcTdBuf[usbConfig.m_maxTransfDesc];
280 for ( i = 0; i < usbConfig.m_maxTransfDesc - 1; i += 1 )
281 {
282 hcTdBuf[i].m_next = &hcTdBuf[i + 1];
283 }
284 memPool->m_freeHcIsoTdList = hcIsoTdBuf;
285 memPool->m_hcIsoTdBuf = hcIsoTdBuf;
286 memPool->m_hcIsoTdBufEnd = &hcIsoTdBuf[usbConfig.m_maxIsoTransfDesc];
287 for ( i = 0; i < usbConfig.m_maxIsoTransfDesc - 1; i += 1 )
288 {
289 hcIsoTdBuf[i].m_next = &hcIsoTdBuf[i + 1];
290 }
291 // build tree for interrupt table
292 for ( i = 0; i < 63; i += 1 )
293 {
294 int intrId;
295 hcEdBuf[i].m_hcArea.asu32 = HCED_SKIP;
296 hcEdBuf[i].m_next = (i > 0) ? &hcEdBuf[(i - 1) >> 1] : NULL;
297 intrId = i - 31;
298 if ( intrId >= 0 )
299 {
300 intrId = ((intrId & 1) << 4) + ((intrId & 2) << 2) + (intrId & 4) + ((intrId & 8) >> 2) + ((intrId & 0x10) >> 4);
301 hcCommArea->InterruptTable[intrId] = &hcEdBuf[i];
302 }
303 }
304 hcEdBuf[TYPE_CONTROL].m_hcArea.asu32 = HCED_SKIP;
305 ohciRegs->HcControlHeadEd = &hcEdBuf[TYPE_CONTROL];
306 hcEdBuf[TYPE_BULK].m_hcArea.asu32 = HCED_SKIP;
307 ohciRegs->HcBulkHeadEd = &hcEdBuf[TYPE_BULK];
308 hcEdBuf[TYPE_ISOCHRON].m_hcArea.asu32 = HCED_SKIP;
309 hcEdBuf[0].m_next = &hcEdBuf[TYPE_ISOCHRON]; // the isochronous endpoint
310 ohciRegs->HcHCCA = hcCommArea;
311 ohciRegs->HcFmInterval = 0x27782EDF;
312 ohciRegs->HcPeriodicStart = 0x2A2F;
313 ohciRegs->HcInterruptEnable = OHCI_INT_SO | OHCI_INT_WDH | OHCI_INT_UE | OHCI_INT_FNO | OHCI_INT_RHSC | OHCI_INT_MIE;
314 ohciRegs->HcControl |=
315 OHCI_CTR_CBSR | OHCI_CTR_PLE | OHCI_CTR_IE | OHCI_CTR_CLE | OHCI_CTR_BLE | OHCI_CTR_USB_OPERATIONAL;
316 return 0;
317}
318
319void deinitHcd(void)
320{
321 UsbdDevice_t *i;
322 UsbdReportDescriptor_t *hidDescriptorStart;
324
325 initHardware((OhciRegs *)OHCI_REG_BASE);
326 for ( i = memPool->m_freeDeviceListStart; i; i = i->m_next )
327 {
328 for ( hidDescriptorStart = i->m_reportDescriptorStart, next = hidDescriptorStart; next; hidDescriptorStart = next )
329 {
330 next = hidDescriptorStart->m_next;
331 FreeSysMemoryWrap(hidDescriptorStart);
332 }
333 }
334 FreeSysMemoryWrap(hcdMemoryBuffer);
335}