]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/ThirdParty/LPCOpen/LPCUSBLib/Drivers/USB/Core/HCD/OHCI/OHCI.c
Update LPC18xx FreeRTOS+UDP demo to use LPCOpen USB and Ethernet drivers.
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC / ThirdParty / LPCOpen / LPCUSBLib / Drivers / USB / Core / HCD / OHCI / OHCI.c
1 /*\r
2  * @brief Open Host Controller Interface\r
3  *\r
4  * @note\r
5  * Copyright(C) NXP Semiconductors, 2012\r
6  * All rights reserved.\r
7  *\r
8  * @par\r
9  * Software that is described herein is for illustrative purposes only\r
10  * which provides customers with programming information regarding the\r
11  * LPC products.  This software is supplied "AS IS" without any warranties of\r
12  * any kind, and NXP Semiconductors and its licensor disclaim any and\r
13  * all warranties, express or implied, including all implied warranties of\r
14  * merchantability, fitness for a particular purpose and non-infringement of\r
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility\r
16  * or liability for the use of the software, conveys no license or rights under any\r
17  * patent, copyright, mask work right, or any other intellectual property rights in\r
18  * or to any products. NXP Semiconductors reserves the right to make changes\r
19  * in the software without notification. NXP Semiconductors also makes no\r
20  * representation or warranty that such application will be suitable for the\r
21  * specified use without further testing or modification.\r
22  *\r
23  * @par\r
24  * Permission to use, copy, modify, and distribute this software and its\r
25  * documentation is hereby granted, under NXP Semiconductors' and its\r
26  * licensor's relevant copyrights in the software, without fee, provided that it\r
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This\r
28  * copyright, permission, and disclaimer notice must appear in all copies of\r
29  * this code.\r
30  */\r
31 \r
32 /*=======================================================================*/\r
33 /*        I N C L U D E S                                                */\r
34 /*=======================================================================*/\r
35 #define  __INCLUDE_FROM_USB_DRIVER\r
36 #include "../../USBMode.h"\r
37 \r
38 #if (defined(USB_CAN_BE_HOST) && defined(__LPC_OHCI__))\r
39 \r
40 #define __LPC_OHCI_C__\r
41 #include "../../../../../Common/Common.h"\r
42 #include "../../USBTask.h"\r
43 #include "../HCD.h"\r
44 #include "OHCI.h"\r
45 \r
46 PRAGMA_ALIGN_256\r
47 OHCI_HOST_DATA_T ohci_data[MAX_USB_CORE] __BSS(USBRAM_SECTION) ATTR_ALIGNED(256);\r
48 \r
49 /*=======================================================================*/\r
50 /*  G L O B A L   S Y M B O L   D E C L A R A T I O N S                  */\r
51 /*=======================================================================*/\r
52 void USB_Host_Enumerate (uint8_t HostID);\r
53 \r
54 void USB_Host_DeEnumerate(uint8_t HostID);\r
55 \r
56 /*********************************************************************\r
57  *                                                              IMPLEMENTATION\r
58  **********************************************************************/\r
59 HCD_STATUS HcdGetDeviceSpeed(uint8_t HostID, HCD_USB_SPEED *DeviceSpeed)\r
60 {\r
61         if ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_CurrentConnectStatus) { /* If device is connected */\r
62                 *DeviceSpeed =\r
63                         ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_LowSpeedDeviceAttached) ? LOW_SPEED : FULL_SPEED;\r
64                 return HCD_STATUS_OK;\r
65         }\r
66         else {\r
67                 return HCD_STATUS_DEVICE_DISCONNECTED;\r
68         }\r
69 }\r
70 \r
71 uint32_t HcdGetFrameNumber(uint8_t HostID)\r
72 {\r
73         return ohci_data[HostID].hcca.HccaFrameNumber;\r
74 }\r
75 \r
76 HCD_STATUS HcdRhPortReset(uint8_t HostID)\r
77 {\r
78         HcdDelayMS(400);// TODO delay should be on Host_LPC\r
79         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortResetStatus;     /* SetPortReset */\r
80         /* should have time-out */\r
81         while ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_PortResetStatus) {}\r
82 \r
83         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortResetStatusChange;/* Clear Port Reset Status Change */\r
84 \r
85         HcdDelayMS(400);// TODO delay should be on Host_LPC\r
86         return HCD_STATUS_OK;\r
87 }\r
88 \r
89 HCD_STATUS HcdRhPortEnable(uint8_t HostID)\r
90 {\r
91         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PowerEnableStatus;/* SetPortEnable */\r
92 \r
93         return HCD_STATUS_OK;\r
94 }\r
95 \r
96 HCD_STATUS HcdRhPortDisable(uint8_t HostID)\r
97 {\r
98         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_CurrentConnectStatus;        /* ClearPortEnable */\r
99 \r
100         return HCD_STATUS_OK;\r
101 }\r
102 \r
103 HCD_STATUS HcdInitDriver(uint8_t HostID)\r
104 {\r
105         USB_REG(HostID)->OTGClkCtrl = 0x00000019;                       /* enable Host clock, OTG clock and AHB clock */\r
106         while ((USB_REG(HostID)->OTGClkSt & 0x00000019) != 0x00000019) ;\r
107 #if defined(__LPC175X_6X__)\r
108         USB_REG(HostID)->StCtrl = 0x3;                                  /* ??? */\r
109 #elif defined(__LPC177X_8X__) || defined(__LPC407X_8X__)\r
110         USB_REG(HostID)->StCtrl = 0x1;                                  /* Port 1 is host */\r
111 #endif\r
112         OHciHostReset(HostID);  /* Software Reset */\r
113         return OHciHostInit(HostID);\r
114 }\r
115 \r
116 HCD_STATUS HcdDeInitDriver(uint8_t HostID)\r
117 {\r
118         USB_REG(HostID)->StCtrl = 0;\r
119         return HCD_STATUS_OK;\r
120 }\r
121 \r
122 HCD_STATUS HcdOpenPipe(uint8_t HostID,\r
123                                            uint8_t DeviceAddr,\r
124                                            HCD_USB_SPEED DeviceSpeed,\r
125                                            uint8_t EndpointNumber,\r
126                                            HCD_TRANSFER_TYPE TransferType,\r
127                                            HCD_TRANSFER_DIR TransferDir,\r
128                                            uint16_t MaxPacketSize,\r
129                                            uint8_t Interval,\r
130                                            uint8_t Mult,\r
131                                            uint8_t HSHubDevAddr,\r
132                                            uint8_t HSHubPortNum,\r
133                                            uint32_t *const PipeHandle)\r
134 {\r
135         uint32_t EdIdx;\r
136         uint8_t ListIdx;\r
137 \r
138         (void) Mult; (void) HSHubDevAddr; (void) HSHubPortNum;  /* Disable compiler warnings */\r
139 \r
140 #if !ISO_LIST_ENABLE\r
141         if ( TransferType == ISOCHRONOUS_TRANSFER ) {\r
142                 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set ISO_LIST_ENABLE to YES");\r
143         }\r
144 #endif\r
145 \r
146 #if !INTERRUPT_LIST_ENABLE\r
147         if ( TransferType == INTERRUPT_TRANSFER ) {\r
148                 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set INTERRUPT_LIST_ENABLE to YES");\r
149         }\r
150 #endif\r
151 \r
152         /********************************* Parameters Verify *********************************/\r
153         ASSERT_STATUS_OK(OpenPipe_VerifyParameters(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType,\r
154                                                                                            TransferDir, MaxPacketSize, Interval, 0) );\r
155 \r
156         EndpointNumber &= 0xF;  /* Endpoint number is in range 0-15 */\r
157         MaxPacketSize &= 0x3FF; /* Max Packet Size is in range 0-1024 */\r
158 \r
159         switch (TransferType) {\r
160         case CONTROL_TRANSFER:\r
161                 ListIdx = CONTROL_LIST_HEAD;\r
162                 break;\r
163 \r
164         case BULK_TRANSFER:\r
165                 ListIdx = BULK_LIST_HEAD;\r
166                 break;\r
167 \r
168         case INTERRUPT_TRANSFER:\r
169                 // ListIdx = FindInterruptTransferListIndex(Interval);\r
170                 ListIdx = INTERRUPT_1ms_LIST_HEAD;\r
171                 break;\r
172 \r
173         case ISOCHRONOUS_TRANSFER:\r
174                 ListIdx = ISO_LIST_HEAD;\r
175                 break;\r
176         default :                                                       // just to clear warning\r
177                 ListIdx = 0xFF;\r
178                 break;\r
179         }\r
180         \r
181         if(ListIdx == 0xFF) return HCD_STATUS_PARAMETER_INVALID;\r
182 \r
183         ASSERT_STATUS_OK(AllocEd(DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir, MaxPacketSize,\r
184                                                          Interval, &EdIdx) );\r
185 \r
186         /* Add new ED to the EDs List */\r
187         HcdED(EdIdx)->ListIndex  = ListIdx;\r
188         InsertEndpoint(HostID, EdIdx, ListIdx);\r
189 \r
190         PipehandleCreate(PipeHandle, HostID, EdIdx);\r
191         return HCD_STATUS_OK;\r
192 }\r
193 \r
194 HCD_STATUS HcdCancelTransfer(uint32_t PipeHandle)\r
195 {\r
196         uint8_t HostID, EdIdx;\r
197 \r
198         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
199 \r
200         HcdED(EdIdx)->hcED.Skip = 1;\r
201 \r
202         /* Clear SOF and wait for the next frame */\r
203         USB_REG(HostID)->InterruptStatus = HC_INTERRUPT_StartofFrame;\r
204         while ( !(USB_REG(HostID)->InterruptStatus & HC_INTERRUPT_StartofFrame) )/* TODO Should have timeout */\r
205 \r
206                 /* ISO TD & General TD have the same offset for nextTD, we can use GTD as pointer to travel on TD list */\r
207                 while ( Align16(HcdED(EdIdx)->hcED.HeadP.HeadTD) != Align16(HcdED(EdIdx)->hcED.TailP) ) {\r
208                         uint32_t HeadTD = Align16(HcdED(EdIdx)->hcED.HeadP.HeadTD);\r
209                         if ( IsIsoEndpoint(EdIdx) ) {\r
210                                 HcdED(EdIdx)->hcED.HeadP.HeadTD = ((PHCD_IsoTransferDescriptor) HeadTD)->NextTD;\r
211                                 FreeItd( (PHCD_IsoTransferDescriptor) HeadTD);\r
212                         }\r
213                         else {\r
214                                 HcdED(EdIdx)->hcED.HeadP.HeadTD = ((PHCD_GeneralTransferDescriptor) HeadTD)->hcGTD.NextTD;\r
215                                 FreeGtd((PHCD_GeneralTransferDescriptor) HeadTD);\r
216                         }\r
217                 }\r
218         HcdED(EdIdx)->hcED.HeadP.HeadTD = Align16(HcdED(EdIdx)->hcED.TailP);/*-- Toggle Carry/Halted are also set to 0 --*/\r
219         HcdED(EdIdx)->hcED.HeadP.ToggleCarry = 0;\r
220 \r
221         HcdED(EdIdx)->hcED.Skip = 0;\r
222         return HCD_STATUS_OK;\r
223 }\r
224 \r
225 HCD_STATUS HcdClosePipe(uint32_t PipeHandle)\r
226 {\r
227         uint8_t HostID, EdIdx;\r
228 \r
229         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
230 \r
231         ASSERT_STATUS_OK(HcdCancelTransfer(PipeHandle) );\r
232 \r
233         HcdED(EdIdx)->hcED.Skip = 1;/* no need for delay, it is already delayed in cancel transfer */\r
234         RemoveEndpoint(HostID, EdIdx);\r
235 \r
236         FreeED(EdIdx);\r
237 \r
238         return HCD_STATUS_OK;\r
239 }\r
240 \r
241 HCD_STATUS HcdClearEndpointHalt(uint32_t PipeHandle)\r
242 {\r
243         uint8_t HostID, EdIdx;\r
244         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
245         /* TODO should we call HcdCancelTrnasfer ? */\r
246         HcdED(EdIdx)->hcED.HeadP.Halted = 0;\r
247         HcdED(EdIdx)->hcED.HeadP.ToggleCarry = 0;\r
248 \r
249         HcdED(EdIdx)->status = HCD_STATUS_OK;\r
250 \r
251         return HCD_STATUS_OK;\r
252 }\r
253 \r
254 HCD_STATUS HcdControlTransfer(uint32_t PipeHandle,\r
255                                                           const USB_Request_Header_t *const pDeviceRequest,\r
256                                                           uint8_t *const buffer)\r
257 {\r
258         uint8_t HostID, EdIdx;\r
259 \r
260         if ((pDeviceRequest == NULL) || (buffer == NULL)) {\r
261                 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Device Request or Data Buffer is NULL");\r
262         }\r
263 \r
264         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
265 \r
266         /************************************************************************/\r
267         /* Setup Stage                                                          */\r
268         /************************************************************************/\r
269         ASSERT_STATUS_OK(QueueOneGTD(EdIdx, (uint8_t *) pDeviceRequest, 8, 0, 2, 0) );                  /* Setup TD: DirectionPID=00 - DataToggle=10b (always DATA0) */\r
270 \r
271         /************************************************************************/\r
272         /* Data Stage                                                           */\r
273         /************************************************************************/\r
274         if (pDeviceRequest->wLength) {  /* Could have problem if the wLength is larger than pipe size */\r
275                 ASSERT_STATUS_OK(QueueOneGTD(EdIdx, buffer, pDeviceRequest->wLength,\r
276                                                                          (pDeviceRequest->bmRequestType & 0x80) ? 2 : 1, 3, 0) );                                                                                       /* DataToggle=11b (always DATA1) */\r
277         }\r
278         /************************************************************************/\r
279         /* Status Stage                                                                     */\r
280         /************************************************************************/\r
281         ASSERT_STATUS_OK(QueueOneGTD(EdIdx, NULL, 0, (pDeviceRequest->bmRequestType & 0x80) ? 1 : 2, 3, 1) );   /* Status TD: Direction=opposite of data direction - DataToggle=11b (always DATA1) */\r
282 \r
283         /* set control list filled */\r
284         USB_REG(HostID)->CommandStatus |= HC_COMMAND_STATUS_ControlListFilled;\r
285 \r
286         HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_QUEUED;\r
287 \r
288         /* wait for semaphore compete TDs */\r
289         ASSERT_STATUS_OK(WaitForTransferComplete(EdIdx) );\r
290 \r
291         return HCD_STATUS_OK;\r
292 }\r
293 \r
294 static HCD_STATUS QueueOneITD(uint32_t EdIdx, uint8_t *dataBuff, uint32_t TDLen, uint16_t StartingFrame)\r
295 {\r
296         uint32_t i;\r
297         PHCD_IsoTransferDescriptor pItd = (PHCD_IsoTransferDescriptor) Align16(HcdED(EdIdx)->hcED.TailP);\r
298 \r
299         pItd->StartingFrame = StartingFrame;\r
300         pItd->FrameCount =\r
301                 (TDLen / HcdED(EdIdx)->hcED.MaxPackageSize) + (TDLen % HcdED(EdIdx)->hcED.MaxPackageSize ? 1 : 0) - 1;\r
302         pItd->BufferPage0 = Align4k( (uint32_t) dataBuff);\r
303         pItd->BufferEnd = (uint32_t) (dataBuff + TDLen - 1);\r
304 \r
305         for (i = 0; TDLen > 0 && i < 8; i++) {\r
306                 uint32_t XactLen = MIN(TDLen, HcdED(EdIdx)->hcED.MaxPackageSize);\r
307 \r
308                 pItd->OffsetPSW[i] =\r
309                         (HCD_STATUS_TRANSFER_NotAccessed <<\r
310                 12) | (Align4k((uint32_t) dataBuff) != Align4k(pItd->BufferPage0) ? _BIT(12) : 0) |\r
311                         Offset4k((uint32_t) dataBuff);                                  /*-- FIXME take into cross page account later 15-12: ConditionCode, 11-0: offset --*/\r
312 \r
313                 TDLen -= XactLen;\r
314                 dataBuff += XactLen;\r
315         }\r
316 \r
317         /* Create a new place holder TD & link setup TD to the new place holder */\r
318         ASSERT_STATUS_OK(AllocItdForEd(EdIdx) );\r
319 \r
320         return HCD_STATUS_OK;\r
321 }\r
322 \r
323 static HCD_STATUS QueueITDs(uint32_t EdIdx, uint8_t *dataBuff, uint32_t xferLen)\r
324 {\r
325         uint32_t FrameIdx;\r
326         uint32_t MaxDataSize;\r
327 \r
328 #if 0   /* Maximum bandwidth (Interval = 1) regardless of Interval value */\r
329         uint8_t MaxXactPerITD, FramePeriod;\r
330         if (HcdED(EdIdx)->Interval < 4) {       /*-- Period < 8 --*/\r
331                 MaxXactPerITD = 1 << ( 4 - HcdED(EdIdx)->Interval );    /*-- Interval 1 => 8, 2 => 4, 3 => 2 --*/\r
332                 FramePeriod = 1;\r
333         }\r
334         else {\r
335                 MaxXactPerITD = 1;\r
336                 FramePeriod = 1 << ( HcdED(EdIdx)->Interval - 4 );      /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/\r
337         }\r
338 #else\r
339         #define MaxXactPerITD   8\r
340         #define FramePeriod     1\r
341 #endif\r
342 \r
343         MaxDataSize = MaxXactPerITD * HcdED(EdIdx)->hcED.MaxPackageSize;\r
344         FrameIdx = HcdGetFrameNumber(0) + 1;    /* FIXME dual controller */\r
345 \r
346         while (xferLen > 0) {\r
347                 uint16_t TdLen;\r
348                 uint32_t MaxTDLen = TD_MAX_XFER_LENGTH - Offset4k((uint32_t) dataBuff);\r
349                 MaxTDLen = MIN(MaxDataSize, MaxTDLen);\r
350 \r
351                 TdLen = MIN(xferLen, MaxTDLen);\r
352                 xferLen -= TdLen;\r
353 \r
354                 /*---------- Fill data to Place hodler TD ----------*/\r
355                 ASSERT_STATUS_OK(QueueOneITD(EdIdx, dataBuff, TdLen, FrameIdx) );\r
356 \r
357                 FrameIdx = (FrameIdx + FramePeriod) % (1 << 16);\r
358                 dataBuff += TdLen;\r
359         }\r
360         return HCD_STATUS_OK;\r
361 }\r
362 \r
363 HCD_STATUS HcdDataTransfer(uint32_t PipeHandle,\r
364                                                    uint8_t *const buffer,\r
365                                                    uint32_t const length,\r
366                                                    uint16_t *const pActualTransferred)\r
367 {\r
368         uint8_t HostID, EdIdx;\r
369         uint32_t ExpectedLength;\r
370 \r
371         if ((buffer == NULL) || (length == 0)) {\r
372                 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Data Buffer is NULL or Transfer Length is 0");\r
373         }\r
374 \r
375         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
376         ASSERT_STATUS_OK(HcdED(EdIdx)->hcED.HeadP.Halted ? HCD_STATUS_TRANSFER_Stall : HCD_STATUS_OK);\r
377 \r
378         ExpectedLength = (length != HCD_ENDPOINT_MAXPACKET_XFER_LEN) ? length : HcdED(EdIdx)->hcED.MaxPackageSize;\r
379 \r
380         if ( IsIsoEndpoint(EdIdx) ) {   /* Iso Transfer */\r
381                 ASSERT_STATUS_OK(QueueITDs(EdIdx, buffer, ExpectedLength) );\r
382         }\r
383         else {\r
384                 ASSERT_STATUS_OK(QueueGTDs(EdIdx, buffer, ExpectedLength, 0) );\r
385                 if (HcdED(EdIdx)->ListIndex == BULK_LIST_HEAD) {\r
386                         USB_REG(HostID)->CommandStatus |= HC_COMMAND_STATUS_BulkListFilled;\r
387                 }\r
388         }\r
389 \r
390         HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_QUEUED;\r
391         HcdED(EdIdx)->pActualTransferCount = pActualTransferred;/* TODO refractor Actual length transfer */\r
392 \r
393         return HCD_STATUS_OK;\r
394 }\r
395 \r
396 HCD_STATUS HcdGetPipeStatus(uint32_t PipeHandle)\r
397 {\r
398         uint8_t HostID, EdIdx;\r
399 \r
400         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );\r
401 \r
402         return (HCD_STATUS)HcdED(EdIdx)->status;\r
403 }\r
404 \r
405 static void OHciRhStatusChangeIsr(uint8_t HostID, uint32_t deviceConnect)\r
406 {\r
407         if (deviceConnect) {/* Device Attached */\r
408                 USB_Host_Enumerate(HostID);\r
409         }\r
410         else {  /* Device detached */\r
411                 USB_Host_DeEnumerate(HostID);\r
412         }\r
413 }\r
414 \r
415 static void ProcessDoneQueue(uint8_t HostID, uint32_t donehead)\r
416 {\r
417         PHC_GTD pCurTD = (PHC_GTD) donehead;\r
418         PHC_GTD pTDList = NULL;\r
419 \r
420         /* do nothing if done queue is empty */\r
421         if (!donehead) {\r
422                 return;\r
423         }\r
424 \r
425         /* reverse done queue order */\r
426         do {\r
427                 uint32_t nextTD = pCurTD->NextTD;\r
428                 pCurTD->NextTD = (uint32_t) pTDList;\r
429                 pTDList = pCurTD;\r
430                 pCurTD = (PHC_GTD) nextTD;\r
431         } while (pCurTD);\r
432 \r
433         while (pTDList != NULL) {\r
434                 uint32_t EdIdx;\r
435 \r
436                 pCurTD  = pTDList;\r
437                 pTDList = (PHC_GTD) pTDList->NextTD;\r
438 \r
439                 /* TODO Cannot determine EdIdx because GTD and ITD have different offsets for EdIdx  */\r
440                 if ( ((uint32_t) pCurTD) <=  ((uint32_t) HcdITD(MAX_ITD - 1)) ) {       /* ISO TD address range */\r
441                         PHCD_IsoTransferDescriptor pItd = (PHCD_IsoTransferDescriptor) pCurTD;\r
442                         EdIdx = pItd->EdIdx;\r
443                 }\r
444                 else {  /* GTD */\r
445                         PHCD_GeneralTransferDescriptor pGtd = (PHCD_GeneralTransferDescriptor) pCurTD;\r
446                         EdIdx = pGtd->EdIdx;\r
447 \r
448                         if (pGtd->hcGTD.CurrentBufferPointer) {\r
449                                 pGtd->TransferCount -=\r
450                                         ( Align4k( ((uint32_t) pGtd->hcGTD.BufferEnd) ^\r
451                                                            ((uint32_t) pGtd->hcGTD.CurrentBufferPointer) ) ? 0x00001000 : 0 ) +\r
452                                         Offset4k((uint32_t) pGtd->hcGTD.BufferEnd) - Offset4k(\r
453                                                 (uint32_t) pGtd->hcGTD.CurrentBufferPointer) + 1;\r
454                         }\r
455                         if (HcdED(EdIdx)->pActualTransferCount) {\r
456                                 *(HcdED(EdIdx)->pActualTransferCount) = pGtd->TransferCount;/* increase usb request transfer count */\r
457 \r
458                         }\r
459                 }\r
460 \r
461                 if (pCurTD->DelayInterrupt != TD_NoInterruptOnComplete) {       /* Update ED status if Interrupt on Complete is set */\r
462                         HcdED(EdIdx)->status = pCurTD->ConditionCode;\r
463                 }\r
464 \r
465                 if ( pCurTD->ConditionCode ) {  /* also update ED status if TD complete with error */\r
466                         HcdED(EdIdx)->status =\r
467                                 (HcdED(EdIdx)->hcED.HeadP.Halted == 1) ? HCD_STATUS_TRANSFER_Stall : pCurTD->ConditionCode;\r
468                         HcdED(EdIdx)->hcED.HeadP.Halted = 0;\r
469                         hcd_printf("Error on Endpoint 0x%X has HCD_STATUS code %d\r\n",\r
470                                            HcdED(EdIdx)->hcED.FunctionAddr | (HcdED(EdIdx)->hcED.Direction == 2 ? 0x80 : 0x00),\r
471                                            pCurTD->ConditionCode);\r
472                 }\r
473 \r
474                 /* remove completed TD from usb request list, if request list is now empty complete usb request */\r
475                 if (IsIsoEndpoint(EdIdx)) {\r
476                         FreeItd( (PHCD_IsoTransferDescriptor) pCurTD);\r
477                 }\r
478                 else {\r
479                         FreeGtd( (PHCD_GeneralTransferDescriptor) pCurTD);\r
480                 }\r
481 \r
482                 /* Post Semaphore to signal TDs are transfer */\r
483         }\r
484 }\r
485 \r
486 #if SCHEDULING_OVRERRUN_INTERRUPT\r
487 static void OHciSchedulingOverrunIsr(uint8_t HostID)\r
488 {}\r
489 \r
490 #endif\r
491 \r
492 #if SOF_INTERRUPT\r
493 static void OHciStartofFrameIsr(uint8_t HostID)\r
494 {}\r
495 \r
496 #endif\r
497 \r
498 #if RESUME_DETECT_INTERRUPT\r
499 static void OHciResumeDetectedIsr(uint8_t HostID)\r
500 {}\r
501 \r
502 #endif\r
503 \r
504 #if UNRECOVERABLE_ERROR_INTERRUPT\r
505 static void OHciUnrecoverableErrorIsr(uint8_t HostID)\r
506 {}\r
507 \r
508 #endif\r
509 \r
510 #if FRAMENUMBER_OVERFLOW_INTERRUPT\r
511 static void OHciFramenumberOverflowIsr(uint8_t HostID)\r
512 {}\r
513 \r
514 #endif\r
515 \r
516 #if OWNERSHIP_CHANGE_INTERRUPT\r
517 static void OHciOwnershipChangeIsr(uint8_t HostID)\r
518 {}\r
519 \r
520 #endif\r
521 \r
522 void HcdIrqHandler(uint8_t HostID)\r
523 {\r
524         uint32_t IntStatus;\r
525 \r
526         IntStatus = USB_REG(HostID)->InterruptStatus;\r
527         /* Clear status after read immediately.\r
528                  Then it will be able to record a new status. */\r
529         USB_REG(HostID)->InterruptStatus = IntStatus;/* Clear HcInterruptStatus */\r
530         IntStatus &= USB_REG(HostID)->InterruptEnable;\r
531         if (IntStatus == 0) {\r
532                 return;\r
533         }\r
534 \r
535         /* disable all interrupt for processing */\r
536         USB_REG(HostID)->InterruptDisable = HC_INTERRUPT_MasterInterruptEnable;\r
537 \r
538         /* Process RootHub Status Change */\r
539         if (IntStatus & HC_INTERRUPT_RootHubStatusChange) {\r
540                 for(;USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_StatusChangeMask;){\r
541                         /* only 1 port/host --> skip to get the number of ports */\r
542                         if (USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_ConnectStatusChange) {\r
543                                 if (USB_REG(HostID)->RhStatus & HC_RH_STATUS_DeviceRemoteWakeupEnable) {        /* means a remote wakeup event */\r
544 \r
545                                 }\r
546                                 else {}\r
547 \r
548                                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_ConnectStatusChange; /* clear CSC bit */\r
549                                 OHciRhStatusChangeIsr(HostID, USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_CurrentConnectStatus);\r
550                         }\r
551 \r
552                         if (USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_PortEnableStatusChange) {\r
553                                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortEnableStatusChange;      /* clear PESC */\r
554                         }\r
555 \r
556                         if (USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_PortSuspendStatusChange) {\r
557                                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortSuspendStatusChange;                     /* clear PSSC */\r
558                         }\r
559 \r
560                         if (USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_OverCurrentIndicatorChange) {    /* Over-current handler to avoid physical damage */\r
561                                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_OverCurrentIndicatorChange;                  /* clear OCIC */\r
562                         }\r
563 \r
564                         if (USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_PortResetStatusChange) {\r
565                                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortResetStatusChange;                       /* clear PRSC */\r
566                         }\r
567                 }\r
568         }\r
569 \r
570         if (IntStatus & HC_INTERRUPT_WritebackDoneHead) {\r
571                 ProcessDoneQueue(HostID, Align16(ohci_data[HostID].hcca.HccaDoneHead) );\r
572         }\r
573 \r
574 #if SCHEDULING_OVRERRUN_INTERRUPT\r
575         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_SchedulingOverrun) {\r
576                 OHciSchedulingOverrunIsr(HostID);\r
577         }\r
578 #endif\r
579 \r
580 #if SOF_INTERRUPT\r
581         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_StartofFrame) {\r
582                 OHciStartofFrameIsr(HostID);\r
583         }\r
584 #endif\r
585 \r
586 #if RESUME_DETECT_INTERRUPT\r
587         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_ResumeDetected) {\r
588                 OHciResumeDetectedIsr(HostID);\r
589         }\r
590 #endif\r
591 \r
592 #if UNRECOVERABLE_ERROR_INTERRUPT\r
593         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_UnrecoverableError) {\r
594                 OHciUnrecoverableErrorIsr(HostID);\r
595         }\r
596 #endif\r
597 \r
598 #if FRAMENUMBER_OVERFLOW_INTERRUPT\r
599         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_FrameNumberOverflow) {\r
600                 OHciFramenumberOverflowIsr(HostID);\r
601         }\r
602 #endif\r
603 \r
604 #if OWNERSHIP_CHANGE_INTERRUPT\r
605         if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_OwnershipChange) {\r
606                 OHciOwnershipChangeIsr(HostID);\r
607         }\r
608 #endif\r
609         USB_REG(HostID)->InterruptEnable = HC_INTERRUPT_MasterInterruptEnable;\r
610         \r
611 }\r
612 \r
613 static HCD_STATUS QueueOneGTD(uint32_t EdIdx,\r
614                                                           uint8_t *const CurrentBufferPointer,\r
615                                                           uint32_t xferLen,\r
616                                                           uint8_t DirectionPID,\r
617                                                           uint8_t DataToggle,\r
618                                                           uint8_t IOC)\r
619 {\r
620         PHCD_GeneralTransferDescriptor TailP;\r
621 \r
622         TailP = ( (PHCD_GeneralTransferDescriptor) HcdED(EdIdx)->hcED.TailP );\r
623         TailP->hcGTD.DirectionPID = DirectionPID;\r
624         TailP->hcGTD.DataToggle = DataToggle;\r
625         TailP->hcGTD.CurrentBufferPointer = CurrentBufferPointer;\r
626         TailP->hcGTD.BufferEnd = (xferLen) ? (CurrentBufferPointer + xferLen - 1) : NULL;\r
627         TailP->TransferCount = xferLen;\r
628         if (!IOC) {\r
629                 TailP->hcGTD.DelayInterrupt = TD_NoInterruptOnComplete; /* Delay Interrupt with  */\r
630         }\r
631 \r
632         /* Create a new place holder TD & link setup TD to the new place holder */\r
633         ASSERT_STATUS_OK(AllocGtdForEd(EdIdx) );\r
634 \r
635         return HCD_STATUS_OK;\r
636 }\r
637 \r
638 static HCD_STATUS QueueGTDs(uint32_t EdIdx, uint8_t *dataBuff, uint32_t xferLen, uint8_t Direction)\r
639 {\r
640         while (xferLen > 0) {\r
641                 uint16_t TdLen;\r
642                 uint32_t MaxTDLen   = TD_MAX_XFER_LENGTH - Offset4k((uint32_t) dataBuff);\r
643 \r
644                 TdLen = MIN(xferLen, MaxTDLen);\r
645                 xferLen -= TdLen;\r
646 \r
647                 ASSERT_STATUS_OK(QueueOneGTD(EdIdx, dataBuff, TdLen, Direction, 0, (xferLen ? 0 : 1)) );\r
648                 dataBuff += TdLen;\r
649         }\r
650         return HCD_STATUS_OK;\r
651 }\r
652 \r
653 static HCD_STATUS WaitForTransferComplete(uint8_t EdIdx)\r
654 {\r
655 #ifndef __TEST__\r
656         while ( HcdED(EdIdx)->status == HCD_STATUS_TRANSFER_QUEUED ) {}\r
657         return (HCD_STATUS) HcdED(EdIdx)->status;\r
658 #else\r
659         return HCD_STATUS_OK;\r
660 #endif\r
661 }\r
662 \r
663 static __INLINE HCD_STATUS InsertEndpoint(uint8_t HostID, uint32_t EdIdx, uint8_t ListIndex)\r
664 {\r
665         PHC_ED list_head;\r
666         list_head = &(ohci_data[HostID].staticEDs[ListIndex]);\r
667 \r
668         HcdED(EdIdx)->hcED.NextED = list_head->NextED;\r
669         list_head->NextED = (uint32_t) HcdED(EdIdx);\r
670 \r
671         //  if ( IsInterruptEndpoint(EdIdx) )\r
672         //  {\r
673         //      OHCI_HOST_DATA->staticEDs[ListIndex].TailP += HcdED(EdIdx)->hcED.MaxPackageSize;        /* increase the bandwidth for the found list */\r
674         //  }\r
675 \r
676         return HCD_STATUS_OK;\r
677 }\r
678 \r
679 static __INLINE HCD_STATUS RemoveEndpoint(uint8_t HostID, uint32_t EdIdx)\r
680 {\r
681         PHCD_EndpointDescriptor prevED;\r
682 \r
683         prevED = (PHCD_EndpointDescriptor) & (ohci_data[HostID].staticEDs[HcdED(EdIdx)->ListIndex]);\r
684         while (prevED->hcED.NextED != (uint32_t) HcdED(EdIdx) ) {\r
685                 prevED = (PHCD_EndpointDescriptor) (prevED->hcED.NextED);\r
686         }\r
687 \r
688         //  if ( IsInterruptEndpoint(EdIdx) )\r
689         //  {\r
690         //      OHCI_HOST_DATA->staticEDs[HcdED(EdIdx)->ListIndex].TailP -= HcdED(EdIdx)->hcED.MaxPackageSize;  /* decrease the bandwidth for the removed list */\r
691         //  }\r
692         prevED->hcED.NextED = HcdED(EdIdx)->hcED.NextED;\r
693 \r
694         return HCD_STATUS_OK;\r
695 }\r
696 \r
697 #if 0   /* We dont need to manage bandwidth this hard */\r
698 \r
699 __INLINE uint8_t FindInterruptTransferListIndex(uint8_t HostID, uint8_t Interval)\r
700 {\r
701         uint8_t ListLeastBandwidth;\r
702         uint8_t ListEnd;\r
703         uint8_t ListIdx = INTERRUPT_32ms_LIST_HEAD;\r
704 \r
705         /* Find the correct interval list with right power of 2, i.e: 1,2,4,8,16,32 ms */\r
706         while ( (ListIdx >= Interval) && (ListIdx >>= 1) ) {}\r
707         ListEnd = ListIdx << 1;\r
708 \r
709         /* Find the least bandwidth in the same interval */\r
710         /* Note: For Interrupt Static ED (0 to 62), TailP is used to store the accumulated bandwidth of the list */\r
711         for (ListLeastBandwidth = ListIdx; ListIdx <= ListEnd; ListIdx++ )\r
712                 if ( ohci_data[HostID].staticEDs[ListIdx].TailP < ohci_data[HostID].staticEDs[ListLeastBandwidth].TailP ) {\r
713                         ListLeastBandwidth = ListIdx;\r
714                 }\r
715         return ListLeastBandwidth;\r
716 }\r
717 \r
718 static __INLINE void BuildPeriodicStaticEdTree(uint8_t HostID)\r
719 {\r
720 #if INTERRUPT_LIST_ENABLE\r
721         /* Build full binary tree for interrupt list */\r
722         uint32_t idx, count;\r
723         uint32_t Balance[16] = {0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF};\r
724 \r
725         /* build static tree for 1 -> 16 ms */\r
726         OHCI_HOST_DATA->staticEDs[0].NextED = 0;\r
727         for (idx = 1; idx < INTERRUPT_32ms_LIST_HEAD; idx++)\r
728                 OHCI_HOST_DATA->staticEDs[idx].NextED = (uint32_t) &(OHCI_HOST_DATA->staticEDs[(idx - 1) / 2]);\r
729         /* create 32ms EDs which will be assigned to HccaInterruptTable */\r
730         for (count = 0, idx = INTERRUPT_32ms_LIST_HEAD; count < 32; count++, idx++)\r
731                 OHCI_HOST_DATA->staticEDs[idx].NextED =\r
732                         (uint32_t) &(OHCI_HOST_DATA->staticEDs[Balance[count & 0xF] + INTERRUPT_16ms_LIST_HEAD]);\r
733         /* Hook to HCCA interrupt Table */\r
734         for (idx = 0; idx < 32; idx++)\r
735                 OHCI_HOST_DATA->hcca.HccaIntTable[idx] = (uint32_t) &(OHCI_HOST_DATA->staticEDs[idx + INTERRUPT_32ms_LIST_HEAD]);\r
736         OHCI_HOST_DATA->staticEDs[INTERRUPT_1ms_LIST_HEAD].NextED = (uint32_t) &(OHCI_HOST_DATA->staticEDs[ISO_LIST_HEAD]);\r
737 #elif ISO_LIST_ENABLE\r
738         for (idx = 0; idx < 32; idx++)\r
739                 OHCI_HOST_DATA->hcca.HccaIntTable[idx] = (uint32_t) &(OHCI_HOST_DATA->staticEDs[ISO_LIST_HEAD]);\r
740 \r
741 #endif\r
742 }\r
743 \r
744 #else\r
745 \r
746 static __INLINE void BuildPeriodicStaticEdTree(uint8_t HostID)\r
747 {\r
748         /* Treat all interrupt interval as 1ms (maximum rate) */\r
749         uint32_t idx;\r
750         for (idx = 0; idx < 32; idx++)\r
751                 ohci_data[HostID].hcca.HccaIntTable[idx] = (uint32_t) &(ohci_data[HostID].staticEDs[INTERRUPT_1ms_LIST_HEAD]);\r
752         /* ISO_LIST_HEAD is an alias for INTERRUPT_1ms_LIST_HEAD */\r
753 }\r
754 \r
755 #endif\r
756 \r
757 static __INLINE uint32_t Align16(uint32_t Value)\r
758 {\r
759         return Value & 0xFFFFFFF0UL;    /* Bit 31 .. 4 */\r
760 }\r
761 \r
762 static __INLINE PHCD_EndpointDescriptor HcdED(uint8_t idx)\r
763 {\r
764         return &(ohci_data[0 /*HostID*/].EDs[idx]);\r
765 }\r
766 \r
767 static __INLINE PHCD_GeneralTransferDescriptor HcdGTD(uint8_t idx)\r
768 {\r
769         return &(ohci_data[0 /*HostID*/].gTDs[idx]);\r
770 }\r
771 \r
772 static __INLINE PHCD_IsoTransferDescriptor HcdITD(uint8_t idx)\r
773 {\r
774 #if ISO_LIST_ENABLE\r
775         return &(ohci_data[0 /*HostID*/].iTDs[idx]);\r
776 #else\r
777         return 0;\r
778 #endif\r
779 }\r
780 \r
781 static __INLINE Bool IsIsoEndpoint(uint8_t EdIdx)\r
782 {\r
783         return (HcdED(EdIdx)->hcED.Format ==0 ? FALSE : TRUE);\r
784 }\r
785 \r
786 #if 0   // just to clear warning\r
787 static __INLINE Bool IsInterruptEndpoint(uint8_t EdIdx)\r
788 {\r
789         return (HcdED(EdIdx)->ListIndex < CONTROL_LIST_HEAD) && !IsIsoEndpoint(EdIdx);\r
790 }\r
791 #endif\r
792 \r
793 static void PipehandleCreate(uint32_t *pPipeHandle, uint8_t HostID, uint8_t EdIdx)\r
794 {\r
795         *pPipeHandle = ((uint32_t) (HostID << 8)) + EdIdx;\r
796 }\r
797 \r
798 static HCD_STATUS PipehandleParse(uint32_t Pipehandle, uint8_t *HostID, uint8_t *EdIdx)\r
799 {\r
800         *HostID = Pipehandle >> 8;\r
801         *EdIdx = Pipehandle & 0xFF;\r
802         if ((*HostID >= MAX_USB_CORE) || (*EdIdx >= MAX_ED) || (HcdED(*EdIdx)->inUse == 0)) {\r
803                 return HCD_STATUS_PIPEHANDLE_INVALID;\r
804         }\r
805         else {\r
806                 return HCD_STATUS_OK;\r
807         }\r
808 }\r
809 \r
810 static __INLINE HCD_STATUS AllocEd(uint8_t DeviceAddr,\r
811                                                                    HCD_USB_SPEED DeviceSpeed,\r
812                                                                    uint8_t EndpointNumber,\r
813                                                                    HCD_TRANSFER_TYPE TransferType,\r
814                                                                    HCD_TRANSFER_DIR TransferDir,\r
815                                                                    uint16_t MaxPacketSize,\r
816                                                                    uint8_t Interval,\r
817                                                                    uint32_t *pEdIdx)\r
818 {\r
819         /* Looking for free EDs */\r
820         for ((*pEdIdx) = 0; ((*pEdIdx) < MAX_ED) && HcdED((*pEdIdx))->inUse; (*pEdIdx)++) {}\r
821         if ((*pEdIdx) >= MAX_ED) {\r
822                 return HCD_STATUS_NOT_ENOUGH_ENDPOINT;\r
823         }\r
824 \r
825         /* Init Data for new ED */\r
826         memset(HcdED(*pEdIdx), 0, sizeof(HCD_EndpointDescriptor) );\r
827 \r
828         HcdED((*pEdIdx))->inUse = 1;\r
829 \r
830         HcdED((*pEdIdx))->hcED.FunctionAddr = DeviceAddr;\r
831         HcdED((*pEdIdx))->hcED.EndpointNumber = EndpointNumber; /* Endpoint number only has 4 bits */\r
832         HcdED((*pEdIdx))->hcED.Direction = (TransferType == CONTROL_TRANSFER) ? 0 : ((TransferDir == OUT_TRANSFER) ? 1 : 2 );\r
833         HcdED((*pEdIdx))->hcED.Speed = (DeviceSpeed == FULL_SPEED) ? 0 : 1;\r
834         HcdED((*pEdIdx))->hcED.Skip = 0;\r
835         HcdED((*pEdIdx))->hcED.Format = (TransferType == ISOCHRONOUS_TRANSFER) ? 1 : 0;\r
836         HcdED((*pEdIdx))->hcED.MaxPackageSize = MaxPacketSize;\r
837         HcdED((*pEdIdx))->Interval = Interval;\r
838 \r
839         /* Allocate Place Holder TD as suggested by OHCI 5.2.8 */\r
840         if (TransferType != ISOCHRONOUS_TRANSFER) {\r
841                 ASSERT_STATUS_OK(AllocGtdForEd(*pEdIdx) );\r
842         }\r
843         else {\r
844                 ASSERT_STATUS_OK(AllocItdForEd(*pEdIdx) );\r
845         }\r
846 \r
847         return HCD_STATUS_OK;\r
848 }\r
849 \r
850 static HCD_STATUS AllocGtdForEd(uint8_t EdIdx)\r
851 {\r
852         uint32_t GtdIdx;\r
853 \r
854         /* Allocate new GTD */\r
855         for (GtdIdx = 0; (GtdIdx < MAX_GTD) && HcdGTD(GtdIdx)->inUse; GtdIdx++) {}\r
856 \r
857         if (GtdIdx < MAX_GTD) {\r
858                 /***************    Control (word 0) ****************/\r
859                 /* Buffer rounding:    R = 1b (yes)                 */\r
860                 /* Direction/PID:      DP = 00b (SETUP)             */\r
861                 /* Delay Interrupt:    DI = 000b (interrupt)            */\r
862                 /* Data Toggle:        DT = 00b (from ED)                   */\r
863                 /* Error Count:        EC = 00b                     */\r
864                 /* Condition Code:     CC = 1110b (not accessed)    */\r
865                 /****************************************************/\r
866                 memset(HcdGTD(GtdIdx), 0, sizeof(HCD_GeneralTransferDescriptor));\r
867 \r
868                 HcdGTD(GtdIdx)->inUse = 1;\r
869                 HcdGTD(GtdIdx)->EdIdx = EdIdx;\r
870 \r
871                 HcdGTD(GtdIdx)->hcGTD.BufferRounding = 1;\r
872                 HcdGTD(GtdIdx)->hcGTD.ConditionCode = (uint32_t) HCD_STATUS_TRANSFER_NotAccessed;\r
873 \r
874                 /* link new GTD to the Endpoint */\r
875                 if (HcdED(EdIdx)->hcED.TailP) { /* already have place holder */\r
876                         ( (PHCD_GeneralTransferDescriptor) HcdED(EdIdx)->hcED.TailP )->hcGTD.NextTD = (uint32_t) HcdGTD(GtdIdx);\r
877                 }\r
878                 else {  /* have no dummy TD attached to the ED */\r
879                         HcdED(EdIdx)->hcED.HeadP.HeadTD = ((uint32_t) HcdGTD(GtdIdx));\r
880                 }\r
881                 HcdED(EdIdx)->hcED.TailP = (uint32_t) HcdGTD(GtdIdx);\r
882 \r
883                 return HCD_STATUS_OK;\r
884         }\r
885         else {\r
886                 return HCD_STATUS_NOT_ENOUGH_GTD;\r
887         }\r
888 \r
889 }\r
890 \r
891 static HCD_STATUS AllocItdForEd(uint8_t EdIdx)\r
892 {\r
893         uint32_t ItdIdx;\r
894 \r
895         for (ItdIdx = 0; (ItdIdx < MAX_ITD) && HcdITD(ItdIdx)->inUse; ItdIdx++) {}\r
896 \r
897         if (ItdIdx < MAX_ITD) {\r
898                 memset(HcdITD(ItdIdx), 0, sizeof(HCD_IsoTransferDescriptor) );\r
899                 HcdITD(ItdIdx)->inUse = 1;\r
900                 HcdITD(ItdIdx)->EdIdx = EdIdx;\r
901 \r
902                 HcdITD(ItdIdx)->ConditionCode = (uint32_t) HCD_STATUS_TRANSFER_NotAccessed;\r
903 \r
904                 /* link new ITD to the Endpoint */\r
905                 if (HcdED(EdIdx)->hcED.TailP) { /* already have place holder */\r
906                         ( (PHCD_IsoTransferDescriptor) HcdED(EdIdx)->hcED.TailP )->NextTD = (uint32_t) HcdITD(ItdIdx);\r
907                 }\r
908                 else {  /* have no dummy TD attached to the ED */\r
909                         HcdED(EdIdx)->hcED.HeadP.HeadTD = ((uint32_t) HcdITD(ItdIdx));\r
910                 }\r
911                 HcdED(EdIdx)->hcED.TailP = (uint32_t) HcdITD(ItdIdx);\r
912 \r
913                 return HCD_STATUS_OK;\r
914         }\r
915         else {\r
916                 return HCD_STATUS_NOT_ENOUGH_ITD;\r
917         }\r
918 }\r
919 \r
920 static __INLINE HCD_STATUS FreeED(uint8_t EdIdx)\r
921 {\r
922         /* Remove Place holder TD */\r
923         if ( IsIsoEndpoint(EdIdx) ) {\r
924                 FreeItd( (PHCD_IsoTransferDescriptor) HcdED(EdIdx)->hcED.TailP);\r
925         }\r
926         else {\r
927                 FreeGtd( (PHCD_GeneralTransferDescriptor) HcdED(EdIdx)->hcED.TailP);\r
928         }\r
929 \r
930         HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_NotAccessed;\r
931         HcdED(EdIdx)->inUse = 0;\r
932 \r
933         return HCD_STATUS_OK;\r
934 }\r
935 \r
936 static __INLINE HCD_STATUS FreeGtd(PHCD_GeneralTransferDescriptor pGtd)\r
937 {\r
938         pGtd->inUse = 0;\r
939         return HCD_STATUS_OK;\r
940 }\r
941 \r
942 static __INLINE HCD_STATUS FreeItd(PHCD_IsoTransferDescriptor pItd)\r
943 {\r
944         pItd->inUse = 0;\r
945         return HCD_STATUS_OK;\r
946 }\r
947 \r
948 static __INLINE HCD_STATUS OHciHostInit(uint8_t HostID)\r
949 {\r
950         uint32_t idx,tem;\r
951 \r
952         if ( sizeof(OHCI_HOST_DATA_T) > 0x4000 ) {      /* Host data exceed 16 KB */\r
953                 ASSERT_STATUS_OK(HCD_STATUS_NOT_ENOUGH_MEMORY);\r
954         }\r
955 \r
956         memset(&ohci_data[HostID], 0, sizeof(OHCI_HOST_DATA_T));\r
957         /* Skip writing 1s to HcHCCA, assume it is 256 aligned */\r
958 \r
959         /* set skip bit for all static EDs */\r
960         for (idx = 0; idx < MAX_STATIC_ED; idx++)\r
961                 ohci_data[HostID].staticEDs[idx].Skip = 1;\r
962 \r
963         /* Periodic List Initialization */\r
964         BuildPeriodicStaticEdTree(HostID);\r
965 \r
966         /* Initialize OHCI registers */\r
967         USB_REG(HostID)->Control = 0;\r
968         OHciHostOperational(HostID);/* have to turn HC to operational mode before setting up below registers*/\r
969 \r
970         USB_REG(HostID)->FmInterval = HC_FMINTERVAL_DEFAULT;\r
971         USB_REG(HostID)->PeriodicStart = PERIODIC_START;\r
972 \r
973         USB_REG(HostID)->ControlHeadED = (uint32_t) &(ohci_data[HostID].staticEDs[CONTROL_LIST_HEAD]);\r
974         USB_REG(HostID)->BulkHeadED = (uint32_t) &(ohci_data[HostID].staticEDs[BULK_LIST_HEAD]);\r
975 \r
976         USB_REG(HostID)->HCCA = (uint32_t) &(ohci_data[HostID].hcca);   /* Hook Hcca */\r
977 \r
978         /* Set up HcControl */\r
979         USB_REG(HostID)->Control |= CONTROL_BULK_SERVICE_RATIO |\r
980                                                                    (INTERRUPT_ROUTING ? HC_CONTROL_InterruptRouting : 0) |\r
981                                                                    (REMOTE_WAKEUP_CONNECTED ? HC_CONTROL_RemoteWakeupConnected : 0) |\r
982                                                                    (REMOTE_WAKEUP_ENABLE ? HC_CONTROL_RemoteWakeupEnable : 0) |\r
983                                                                    HC_CONTROL_ControlListEnable | HC_CONTROL_BulkListEnable |\r
984                                                                    (ISO_LIST_ENABLE ? (HC_CONTROL_PeriodListEnable | HC_CONTROL_IsochronousEnable) :\r
985                                                                         (INTERRUPT_LIST_ENABLE ? HC_CONTROL_PeriodListEnable : 0));\r
986 \r
987         /* Set Global Power */\r
988         USB_REG(HostID)->RhStatus = HC_RH_STATUS_LocalPowerStatusChange;\r
989 \r
990         // HcInterrupt Registers Init\r
991         tem = USB_REG(HostID)->InterruptStatus;        // just to clear warning\r
992         USB_REG(HostID)->InterruptStatus |= tem;        /* Clear Interrupt Status */\r
993         USB_REG(HostID)->InterruptDisable = HC_INTERRUPT_ALL;/* Disable all interrupts */\r
994         /* Enable necessary Interrupts */\r
995         USB_REG(HostID)->InterruptEnable = HC_INTERRUPT_MasterInterruptEnable | HC_INTERRUPT_WritebackDoneHead |\r
996                                                                                   HC_INTERRUPT_RootHubStatusChange |\r
997                                                                                   (SCHEDULING_OVRERRUN_INTERRUPT ? HC_INTERRUPT_SchedulingOverrun : 0 ) |\r
998                                                                                   (SOF_INTERRUPT ? HC_INTERRUPT_StartofFrame : 0) |\r
999                                                                                   (RESUME_DETECT_INTERRUPT ? HC_INTERRUPT_ResumeDetected : 0) |\r
1000                                                                                   (UNRECOVERABLE_ERROR_INTERRUPT ? HC_INTERRUPT_UnrecoverableError : 0) |\r
1001                                                                                   (FRAMENUMBER_OVERFLOW_INTERRUPT ? HC_INTERRUPT_FrameNumberOverflow : 0) |\r
1002                                                                                   (OWNERSHIP_CHANGE_INTERRUPT ? HC_INTERRUPT_OwnershipChange : 0 );\r
1003 \r
1004         return HCD_STATUS_OK;\r
1005 }\r
1006 \r
1007 static __INLINE HCD_STATUS OHciHostReset(uint8_t HostID)\r
1008 {\r
1009         USB_REG(HostID)->CommandStatus = HC_COMMAND_STATUS_HostControllerReset;\r
1010         while ( USB_REG(HostID)->CommandStatus & HC_COMMAND_STATUS_HostControllerReset) {}      /* FIXME Wait indefinitely (may need a time-out here) */\r
1011 \r
1012         return HCD_STATUS_OK;\r
1013 }\r
1014 \r
1015 static __INLINE HCD_STATUS OHciHostOperational(uint8_t HostID)\r
1016 {\r
1017         USB_REG(HostID)->Control =\r
1018                 (USB_REG(HostID)->Control & (~HC_CONTROL_HostControllerFunctionalState)) | (HC_HOST_OPERATIONAL << 6);\r
1019         return HCD_STATUS_OK;\r
1020 }\r
1021 \r
1022 #if 0           // just to clear warning\r
1023 static __INLINE HCD_STATUS OHciHostSuspend(uint8_t HostID)\r
1024 {\r
1025         USB_REG(HostID)->Control =\r
1026                 (USB_REG(HostID)->Control & (~HC_CONTROL_HostControllerFunctionalState)) | (HC_HOST_SUSPEND << 6);\r
1027         return HCD_STATUS_OK;\r
1028 }\r
1029 \r
1030 static __INLINE HCD_STATUS OHciRhPortPowerOn(uint8_t HostID, uint8_t uPortNumber)\r
1031 {\r
1032         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortPowerStatus;     /* SetPortPower */\r
1033         HcdDelayMS(2 * ( (USB_REG(HostID)->RhDescriptorA & HC_RH_DESCRIPTORA_PowerOnToPowerGoodTime) >> 24 ) ); /* FIXME need to delay here POTPGT */\r
1034 \r
1035         return HCD_STATUS_OK;\r
1036 }\r
1037 \r
1038 static __INLINE HCD_STATUS OHciRhPortPowerOff(uint8_t HostID, uint8_t uPortNumber)\r
1039 {\r
1040         USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_LowSpeedDeviceAttached;      /* ClearPortPower */\r
1041         return HCD_STATUS_OK;\r
1042 }\r
1043 \r
1044 static __INLINE HCD_STATUS OHciRhPortSuspend(uint8_t HostID, uint8_t uPortNumber)\r
1045 {\r
1046         if ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_CurrentConnectStatus) { /* If device is connected */\r
1047                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortSuspendStatus;/* SetPortSuspend */\r
1048         }\r
1049         HcdDelayMS(3);  /* FIXME 3ms for device to suspend */\r
1050 \r
1051         return HCD_STATUS_OK;\r
1052 }\r
1053 \r
1054 static __INLINE HCD_STATUS OHciRhPortResume(uint8_t HostID, uint8_t uPortNumber)\r
1055 {\r
1056         if ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_CurrentConnectStatus) { /* If port is currently suspended */\r
1057                 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortOverCurrentIndicator;    /* ClearSuspendStatus */\r
1058         }\r
1059         HcdDelayMS(20); /* FIXME 20ms for device to resume */\r
1060 \r
1061         return HCD_STATUS_OK;\r
1062 }\r
1063 #endif\r
1064 \r
1065 void HcdSetStreamPacketSize(uint32_t PipeHandle, uint16_t packetsize)\r
1066 {\r
1067 }\r
1068 \r
1069 #endif\r