PS2SDK
PS2 Homebrew Libraries
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
14 static UsbdMemoryPool_t *memPool_unused = NULL;
15 #endif
16 
17 static void *hcdMemoryBuffer;
18 
19 void 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 
119 void 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 
135 static 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 
167 int 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 
319 void 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 }
_usbdReportDescriptor
Definition: usbdpriv.h:298
_usbdConfig
Definition: usbdpriv.h:42
_ohciRegs
Definition: usbdpriv.h:229
_hcCA
Definition: usbdpriv.h:219
_hcIsoTd
Definition: usbdpriv.h:144
usbdpriv.h
_hcTd
Definition: usbdpriv.h:136
_hcEd
Definition: usbdpriv.h:165
_memPool
Definition: usbdpriv.h:255
_device
Definition: usbdpriv.h:107
_ioRequest
Definition: usbdpriv.h:82
_endpoint
Definition: usbdpriv.h:173