2 * @brief Open Host Controller Interface
\r
5 * Copyright(C) NXP Semiconductors, 2012
\r
6 * All rights reserved.
\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
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
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
38 #if (defined(USB_CAN_BE_HOST) && defined(__LPC_OHCI__))
\r
40 #define __LPC_OHCI_C__
\r
41 #include "../../../../../Common/Common.h"
\r
42 #include "../../USBTask.h"
\r
47 OHCI_HOST_DATA_T ohci_data[MAX_USB_CORE] __BSS(USBRAM_SECTION) ATTR_ALIGNED(256);
\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
54 void USB_Host_DeEnumerate(uint8_t HostID);
\r
56 /*********************************************************************
\r
58 **********************************************************************/
\r
59 HCD_STATUS HcdGetDeviceSpeed(uint8_t HostID, HCD_USB_SPEED *DeviceSpeed)
\r
61 if ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_CurrentConnectStatus) { /* If device is connected */
\r
63 ( USB_REG(HostID)->RhPortStatus1 & HC_RH_PORT_STATUS_LowSpeedDeviceAttached) ? LOW_SPEED : FULL_SPEED;
\r
64 return HCD_STATUS_OK;
\r
67 return HCD_STATUS_DEVICE_DISCONNECTED;
\r
71 uint32_t HcdGetFrameNumber(uint8_t HostID)
\r
73 return ohci_data[HostID].hcca.HccaFrameNumber;
\r
76 HCD_STATUS HcdRhPortReset(uint8_t HostID)
\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
83 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PortResetStatusChange;/* Clear Port Reset Status Change */
\r
85 HcdDelayMS(400);// TODO delay should be on Host_LPC
\r
86 return HCD_STATUS_OK;
\r
89 HCD_STATUS HcdRhPortEnable(uint8_t HostID)
\r
91 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_PowerEnableStatus;/* SetPortEnable */
\r
93 return HCD_STATUS_OK;
\r
96 HCD_STATUS HcdRhPortDisable(uint8_t HostID)
\r
98 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_CurrentConnectStatus; /* ClearPortEnable */
\r
100 return HCD_STATUS_OK;
\r
103 HCD_STATUS HcdInitDriver(uint8_t HostID)
\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
112 OHciHostReset(HostID); /* Software Reset */
\r
113 return OHciHostInit(HostID);
\r
116 HCD_STATUS HcdDeInitDriver(uint8_t HostID)
\r
118 USB_REG(HostID)->StCtrl = 0;
\r
119 return HCD_STATUS_OK;
\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
131 uint8_t HSHubDevAddr,
\r
132 uint8_t HSHubPortNum,
\r
133 uint32_t *const PipeHandle)
\r
138 (void) Mult; (void) HSHubDevAddr; (void) HSHubPortNum; /* Disable compiler warnings */
\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
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
152 /********************************* Parameters Verify *********************************/
\r
153 ASSERT_STATUS_OK(OpenPipe_VerifyParameters(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType,
\r
154 TransferDir, MaxPacketSize, Interval, 0) );
\r
156 EndpointNumber &= 0xF; /* Endpoint number is in range 0-15 */
\r
157 MaxPacketSize &= 0x3FF; /* Max Packet Size is in range 0-1024 */
\r
159 switch (TransferType) {
\r
160 case CONTROL_TRANSFER:
\r
161 ListIdx = CONTROL_LIST_HEAD;
\r
164 case BULK_TRANSFER:
\r
165 ListIdx = BULK_LIST_HEAD;
\r
168 case INTERRUPT_TRANSFER:
\r
169 // ListIdx = FindInterruptTransferListIndex(Interval);
\r
170 ListIdx = INTERRUPT_1ms_LIST_HEAD;
\r
173 case ISOCHRONOUS_TRANSFER:
\r
174 ListIdx = ISO_LIST_HEAD;
\r
176 default : // just to clear warning
\r
181 if(ListIdx == 0xFF) return HCD_STATUS_PARAMETER_INVALID;
\r
183 ASSERT_STATUS_OK(AllocEd(DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir, MaxPacketSize,
\r
184 Interval, &EdIdx) );
\r
186 /* Add new ED to the EDs List */
\r
187 HcdED(EdIdx)->ListIndex = ListIdx;
\r
188 InsertEndpoint(HostID, EdIdx, ListIdx);
\r
190 PipehandleCreate(PipeHandle, HostID, EdIdx);
\r
191 return HCD_STATUS_OK;
\r
194 HCD_STATUS HcdCancelTransfer(uint32_t PipeHandle)
\r
196 uint8_t HostID, EdIdx;
\r
198 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );
\r
200 HcdED(EdIdx)->hcED.Skip = 1;
\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
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
214 HcdED(EdIdx)->hcED.HeadP.HeadTD = ((PHCD_GeneralTransferDescriptor) HeadTD)->hcGTD.NextTD;
\r
215 FreeGtd((PHCD_GeneralTransferDescriptor) HeadTD);
\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
221 HcdED(EdIdx)->hcED.Skip = 0;
\r
222 return HCD_STATUS_OK;
\r
225 HCD_STATUS HcdClosePipe(uint32_t PipeHandle)
\r
227 uint8_t HostID, EdIdx;
\r
229 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );
\r
231 ASSERT_STATUS_OK(HcdCancelTransfer(PipeHandle) );
\r
233 HcdED(EdIdx)->hcED.Skip = 1;/* no need for delay, it is already delayed in cancel transfer */
\r
234 RemoveEndpoint(HostID, EdIdx);
\r
238 return HCD_STATUS_OK;
\r
241 HCD_STATUS HcdClearEndpointHalt(uint32_t PipeHandle)
\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
249 HcdED(EdIdx)->status = HCD_STATUS_OK;
\r
251 return HCD_STATUS_OK;
\r
254 HCD_STATUS HcdControlTransfer(uint32_t PipeHandle,
\r
255 const USB_Request_Header_t *const pDeviceRequest,
\r
256 uint8_t *const buffer)
\r
258 uint8_t HostID, EdIdx;
\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
264 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );
\r
266 /************************************************************************/
\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
271 /************************************************************************/
\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
278 /************************************************************************/
\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
283 /* set control list filled */
\r
284 USB_REG(HostID)->CommandStatus |= HC_COMMAND_STATUS_ControlListFilled;
\r
286 HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_QUEUED;
\r
288 /* wait for semaphore compete TDs */
\r
289 ASSERT_STATUS_OK(WaitForTransferComplete(EdIdx) );
\r
291 return HCD_STATUS_OK;
\r
294 static HCD_STATUS QueueOneITD(uint32_t EdIdx, uint8_t *dataBuff, uint32_t TDLen, uint16_t StartingFrame)
\r
297 PHCD_IsoTransferDescriptor pItd = (PHCD_IsoTransferDescriptor) Align16(HcdED(EdIdx)->hcED.TailP);
\r
299 pItd->StartingFrame = StartingFrame;
\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
305 for (i = 0; TDLen > 0 && i < 8; i++) {
\r
306 uint32_t XactLen = MIN(TDLen, HcdED(EdIdx)->hcED.MaxPackageSize);
\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
314 dataBuff += XactLen;
\r
317 /* Create a new place holder TD & link setup TD to the new place holder */
\r
318 ASSERT_STATUS_OK(AllocItdForEd(EdIdx) );
\r
320 return HCD_STATUS_OK;
\r
323 static HCD_STATUS QueueITDs(uint32_t EdIdx, uint8_t *dataBuff, uint32_t xferLen)
\r
326 uint32_t MaxDataSize;
\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
336 FramePeriod = 1 << ( HcdED(EdIdx)->Interval - 4 ); /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/
\r
339 #define MaxXactPerITD 8
\r
340 #define FramePeriod 1
\r
343 MaxDataSize = MaxXactPerITD * HcdED(EdIdx)->hcED.MaxPackageSize;
\r
344 FrameIdx = HcdGetFrameNumber(0) + 1; /* FIXME dual controller */
\r
346 while (xferLen > 0) {
\r
348 uint32_t MaxTDLen = TD_MAX_XFER_LENGTH - Offset4k((uint32_t) dataBuff);
\r
349 MaxTDLen = MIN(MaxDataSize, MaxTDLen);
\r
351 TdLen = MIN(xferLen, MaxTDLen);
\r
354 /*---------- Fill data to Place hodler TD ----------*/
\r
355 ASSERT_STATUS_OK(QueueOneITD(EdIdx, dataBuff, TdLen, FrameIdx) );
\r
357 FrameIdx = (FrameIdx + FramePeriod) % (1 << 16);
\r
360 return HCD_STATUS_OK;
\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
368 uint8_t HostID, EdIdx;
\r
369 uint32_t ExpectedLength;
\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
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
378 ExpectedLength = (length != HCD_ENDPOINT_MAXPACKET_XFER_LEN) ? length : HcdED(EdIdx)->hcED.MaxPackageSize;
\r
380 if ( IsIsoEndpoint(EdIdx) ) { /* Iso Transfer */
\r
381 ASSERT_STATUS_OK(QueueITDs(EdIdx, buffer, ExpectedLength) );
\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
390 HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_QUEUED;
\r
391 HcdED(EdIdx)->pActualTransferCount = pActualTransferred;/* TODO refractor Actual length transfer */
\r
393 return HCD_STATUS_OK;
\r
396 HCD_STATUS HcdGetPipeStatus(uint32_t PipeHandle)
\r
398 uint8_t HostID, EdIdx;
\r
400 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &EdIdx) );
\r
402 return (HCD_STATUS)HcdED(EdIdx)->status;
\r
405 static void OHciRhStatusChangeIsr(uint8_t HostID, uint32_t deviceConnect)
\r
407 if (deviceConnect) {/* Device Attached */
\r
408 USB_Host_Enumerate(HostID);
\r
410 else { /* Device detached */
\r
411 USB_Host_DeEnumerate(HostID);
\r
415 static void ProcessDoneQueue(uint8_t HostID, uint32_t donehead)
\r
417 PHC_GTD pCurTD = (PHC_GTD) donehead;
\r
418 PHC_GTD pTDList = NULL;
\r
420 /* do nothing if done queue is empty */
\r
425 /* reverse done queue order */
\r
427 uint32_t nextTD = pCurTD->NextTD;
\r
428 pCurTD->NextTD = (uint32_t) pTDList;
\r
430 pCurTD = (PHC_GTD) nextTD;
\r
433 while (pTDList != NULL) {
\r
437 pTDList = (PHC_GTD) pTDList->NextTD;
\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
445 PHCD_GeneralTransferDescriptor pGtd = (PHCD_GeneralTransferDescriptor) pCurTD;
\r
446 EdIdx = pGtd->EdIdx;
\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
455 if (HcdED(EdIdx)->pActualTransferCount) {
\r
456 *(HcdED(EdIdx)->pActualTransferCount) = pGtd->TransferCount;/* increase usb request transfer count */
\r
461 if (pCurTD->DelayInterrupt != TD_NoInterruptOnComplete) { /* Update ED status if Interrupt on Complete is set */
\r
462 HcdED(EdIdx)->status = pCurTD->ConditionCode;
\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
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
479 FreeGtd( (PHCD_GeneralTransferDescriptor) pCurTD);
\r
482 /* Post Semaphore to signal TDs are transfer */
\r
486 #if SCHEDULING_OVRERRUN_INTERRUPT
\r
487 static void OHciSchedulingOverrunIsr(uint8_t HostID)
\r
493 static void OHciStartofFrameIsr(uint8_t HostID)
\r
498 #if RESUME_DETECT_INTERRUPT
\r
499 static void OHciResumeDetectedIsr(uint8_t HostID)
\r
504 #if UNRECOVERABLE_ERROR_INTERRUPT
\r
505 static void OHciUnrecoverableErrorIsr(uint8_t HostID)
\r
510 #if FRAMENUMBER_OVERFLOW_INTERRUPT
\r
511 static void OHciFramenumberOverflowIsr(uint8_t HostID)
\r
516 #if OWNERSHIP_CHANGE_INTERRUPT
\r
517 static void OHciOwnershipChangeIsr(uint8_t HostID)
\r
522 void HcdIrqHandler(uint8_t HostID)
\r
524 uint32_t IntStatus;
\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
535 /* disable all interrupt for processing */
\r
536 USB_REG(HostID)->InterruptDisable = HC_INTERRUPT_MasterInterruptEnable;
\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
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
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
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
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
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
570 if (IntStatus & HC_INTERRUPT_WritebackDoneHead) {
\r
571 ProcessDoneQueue(HostID, Align16(ohci_data[HostID].hcca.HccaDoneHead) );
\r
574 #if SCHEDULING_OVRERRUN_INTERRUPT
\r
575 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_SchedulingOverrun) {
\r
576 OHciSchedulingOverrunIsr(HostID);
\r
581 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_StartofFrame) {
\r
582 OHciStartofFrameIsr(HostID);
\r
586 #if RESUME_DETECT_INTERRUPT
\r
587 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_ResumeDetected) {
\r
588 OHciResumeDetectedIsr(HostID);
\r
592 #if UNRECOVERABLE_ERROR_INTERRUPT
\r
593 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_UnrecoverableError) {
\r
594 OHciUnrecoverableErrorIsr(HostID);
\r
598 #if FRAMENUMBER_OVERFLOW_INTERRUPT
\r
599 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_FrameNumberOverflow) {
\r
600 OHciFramenumberOverflowIsr(HostID);
\r
604 #if OWNERSHIP_CHANGE_INTERRUPT
\r
605 if (USB_REG(HostID)->HcInterruptStatus & HC_INTERRUPT_OwnershipChange) {
\r
606 OHciOwnershipChangeIsr(HostID);
\r
609 USB_REG(HostID)->InterruptEnable = HC_INTERRUPT_MasterInterruptEnable;
\r
613 static HCD_STATUS QueueOneGTD(uint32_t EdIdx,
\r
614 uint8_t *const CurrentBufferPointer,
\r
616 uint8_t DirectionPID,
\r
617 uint8_t DataToggle,
\r
620 PHCD_GeneralTransferDescriptor TailP;
\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
629 TailP->hcGTD.DelayInterrupt = TD_NoInterruptOnComplete; /* Delay Interrupt with */
\r
632 /* Create a new place holder TD & link setup TD to the new place holder */
\r
633 ASSERT_STATUS_OK(AllocGtdForEd(EdIdx) );
\r
635 return HCD_STATUS_OK;
\r
638 static HCD_STATUS QueueGTDs(uint32_t EdIdx, uint8_t *dataBuff, uint32_t xferLen, uint8_t Direction)
\r
640 while (xferLen > 0) {
\r
642 uint32_t MaxTDLen = TD_MAX_XFER_LENGTH - Offset4k((uint32_t) dataBuff);
\r
644 TdLen = MIN(xferLen, MaxTDLen);
\r
647 ASSERT_STATUS_OK(QueueOneGTD(EdIdx, dataBuff, TdLen, Direction, 0, (xferLen ? 0 : 1)) );
\r
650 return HCD_STATUS_OK;
\r
653 static HCD_STATUS WaitForTransferComplete(uint8_t EdIdx)
\r
656 while ( HcdED(EdIdx)->status == HCD_STATUS_TRANSFER_QUEUED ) {}
\r
657 return (HCD_STATUS) HcdED(EdIdx)->status;
\r
659 return HCD_STATUS_OK;
\r
663 static __INLINE HCD_STATUS InsertEndpoint(uint8_t HostID, uint32_t EdIdx, uint8_t ListIndex)
\r
666 list_head = &(ohci_data[HostID].staticEDs[ListIndex]);
\r
668 HcdED(EdIdx)->hcED.NextED = list_head->NextED;
\r
669 list_head->NextED = (uint32_t) HcdED(EdIdx);
\r
671 // if ( IsInterruptEndpoint(EdIdx) )
\r
673 // OHCI_HOST_DATA->staticEDs[ListIndex].TailP += HcdED(EdIdx)->hcED.MaxPackageSize; /* increase the bandwidth for the found list */
\r
676 return HCD_STATUS_OK;
\r
679 static __INLINE HCD_STATUS RemoveEndpoint(uint8_t HostID, uint32_t EdIdx)
\r
681 PHCD_EndpointDescriptor prevED;
\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
688 // if ( IsInterruptEndpoint(EdIdx) )
\r
690 // OHCI_HOST_DATA->staticEDs[HcdED(EdIdx)->ListIndex].TailP -= HcdED(EdIdx)->hcED.MaxPackageSize; /* decrease the bandwidth for the removed list */
\r
692 prevED->hcED.NextED = HcdED(EdIdx)->hcED.NextED;
\r
694 return HCD_STATUS_OK;
\r
697 #if 0 /* We dont need to manage bandwidth this hard */
\r
699 __INLINE uint8_t FindInterruptTransferListIndex(uint8_t HostID, uint8_t Interval)
\r
701 uint8_t ListLeastBandwidth;
\r
703 uint8_t ListIdx = INTERRUPT_32ms_LIST_HEAD;
\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
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
715 return ListLeastBandwidth;
\r
718 static __INLINE void BuildPeriodicStaticEdTree(uint8_t HostID)
\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
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
746 static __INLINE void BuildPeriodicStaticEdTree(uint8_t HostID)
\r
748 /* Treat all interrupt interval as 1ms (maximum rate) */
\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
757 static __INLINE uint32_t Align16(uint32_t Value)
\r
759 return Value & 0xFFFFFFF0UL; /* Bit 31 .. 4 */
\r
762 static __INLINE PHCD_EndpointDescriptor HcdED(uint8_t idx)
\r
764 return &(ohci_data[0 /*HostID*/].EDs[idx]);
\r
767 static __INLINE PHCD_GeneralTransferDescriptor HcdGTD(uint8_t idx)
\r
769 return &(ohci_data[0 /*HostID*/].gTDs[idx]);
\r
772 static __INLINE PHCD_IsoTransferDescriptor HcdITD(uint8_t idx)
\r
774 #if ISO_LIST_ENABLE
\r
775 return &(ohci_data[0 /*HostID*/].iTDs[idx]);
\r
781 static __INLINE Bool IsIsoEndpoint(uint8_t EdIdx)
\r
783 return (HcdED(EdIdx)->hcED.Format ==0 ? FALSE : TRUE);
\r
786 #if 0 // just to clear warning
\r
787 static __INLINE Bool IsInterruptEndpoint(uint8_t EdIdx)
\r
789 return (HcdED(EdIdx)->ListIndex < CONTROL_LIST_HEAD) && !IsIsoEndpoint(EdIdx);
\r
793 static void PipehandleCreate(uint32_t *pPipeHandle, uint8_t HostID, uint8_t EdIdx)
\r
795 *pPipeHandle = ((uint32_t) (HostID << 8)) + EdIdx;
\r
798 static HCD_STATUS PipehandleParse(uint32_t Pipehandle, uint8_t *HostID, uint8_t *EdIdx)
\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
806 return HCD_STATUS_OK;
\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
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
825 /* Init Data for new ED */
\r
826 memset(HcdED(*pEdIdx), 0, sizeof(HCD_EndpointDescriptor) );
\r
828 HcdED((*pEdIdx))->inUse = 1;
\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
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
844 ASSERT_STATUS_OK(AllocItdForEd(*pEdIdx) );
\r
847 return HCD_STATUS_OK;
\r
850 static HCD_STATUS AllocGtdForEd(uint8_t EdIdx)
\r
854 /* Allocate new GTD */
\r
855 for (GtdIdx = 0; (GtdIdx < MAX_GTD) && HcdGTD(GtdIdx)->inUse; GtdIdx++) {}
\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
868 HcdGTD(GtdIdx)->inUse = 1;
\r
869 HcdGTD(GtdIdx)->EdIdx = EdIdx;
\r
871 HcdGTD(GtdIdx)->hcGTD.BufferRounding = 1;
\r
872 HcdGTD(GtdIdx)->hcGTD.ConditionCode = (uint32_t) HCD_STATUS_TRANSFER_NotAccessed;
\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
878 else { /* have no dummy TD attached to the ED */
\r
879 HcdED(EdIdx)->hcED.HeadP.HeadTD = ((uint32_t) HcdGTD(GtdIdx));
\r
881 HcdED(EdIdx)->hcED.TailP = (uint32_t) HcdGTD(GtdIdx);
\r
883 return HCD_STATUS_OK;
\r
886 return HCD_STATUS_NOT_ENOUGH_GTD;
\r
891 static HCD_STATUS AllocItdForEd(uint8_t EdIdx)
\r
895 for (ItdIdx = 0; (ItdIdx < MAX_ITD) && HcdITD(ItdIdx)->inUse; ItdIdx++) {}
\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
902 HcdITD(ItdIdx)->ConditionCode = (uint32_t) HCD_STATUS_TRANSFER_NotAccessed;
\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
908 else { /* have no dummy TD attached to the ED */
\r
909 HcdED(EdIdx)->hcED.HeadP.HeadTD = ((uint32_t) HcdITD(ItdIdx));
\r
911 HcdED(EdIdx)->hcED.TailP = (uint32_t) HcdITD(ItdIdx);
\r
913 return HCD_STATUS_OK;
\r
916 return HCD_STATUS_NOT_ENOUGH_ITD;
\r
920 static __INLINE HCD_STATUS FreeED(uint8_t EdIdx)
\r
922 /* Remove Place holder TD */
\r
923 if ( IsIsoEndpoint(EdIdx) ) {
\r
924 FreeItd( (PHCD_IsoTransferDescriptor) HcdED(EdIdx)->hcED.TailP);
\r
927 FreeGtd( (PHCD_GeneralTransferDescriptor) HcdED(EdIdx)->hcED.TailP);
\r
930 HcdED(EdIdx)->status = HCD_STATUS_TRANSFER_NotAccessed;
\r
931 HcdED(EdIdx)->inUse = 0;
\r
933 return HCD_STATUS_OK;
\r
936 static __INLINE HCD_STATUS FreeGtd(PHCD_GeneralTransferDescriptor pGtd)
\r
939 return HCD_STATUS_OK;
\r
942 static __INLINE HCD_STATUS FreeItd(PHCD_IsoTransferDescriptor pItd)
\r
945 return HCD_STATUS_OK;
\r
948 static __INLINE HCD_STATUS OHciHostInit(uint8_t HostID)
\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
956 memset(&ohci_data[HostID], 0, sizeof(OHCI_HOST_DATA_T));
\r
957 /* Skip writing 1s to HcHCCA, assume it is 256 aligned */
\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
963 /* Periodic List Initialization */
\r
964 BuildPeriodicStaticEdTree(HostID);
\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
970 USB_REG(HostID)->FmInterval = HC_FMINTERVAL_DEFAULT;
\r
971 USB_REG(HostID)->PeriodicStart = PERIODIC_START;
\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
976 USB_REG(HostID)->HCCA = (uint32_t) &(ohci_data[HostID].hcca); /* Hook Hcca */
\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
987 /* Set Global Power */
\r
988 USB_REG(HostID)->RhStatus = HC_RH_STATUS_LocalPowerStatusChange;
\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
1004 return HCD_STATUS_OK;
\r
1007 static __INLINE HCD_STATUS OHciHostReset(uint8_t HostID)
\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
1012 return HCD_STATUS_OK;
\r
1015 static __INLINE HCD_STATUS OHciHostOperational(uint8_t HostID)
\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
1022 #if 0 // just to clear warning
\r
1023 static __INLINE HCD_STATUS OHciHostSuspend(uint8_t HostID)
\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
1030 static __INLINE HCD_STATUS OHciRhPortPowerOn(uint8_t HostID, uint8_t uPortNumber)
\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
1035 return HCD_STATUS_OK;
\r
1038 static __INLINE HCD_STATUS OHciRhPortPowerOff(uint8_t HostID, uint8_t uPortNumber)
\r
1040 USB_REG(HostID)->RhPortStatus1 = HC_RH_PORT_STATUS_LowSpeedDeviceAttached; /* ClearPortPower */
\r
1041 return HCD_STATUS_OK;
\r
1044 static __INLINE HCD_STATUS OHciRhPortSuspend(uint8_t HostID, uint8_t uPortNumber)
\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
1049 HcdDelayMS(3); /* FIXME 3ms for device to suspend */
\r
1051 return HCD_STATUS_OK;
\r
1054 static __INLINE HCD_STATUS OHciRhPortResume(uint8_t HostID, uint8_t uPortNumber)
\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
1059 HcdDelayMS(20); /* FIXME 20ms for device to resume */
\r
1061 return HCD_STATUS_OK;
\r
1065 void HcdSetStreamPacketSize(uint32_t PipeHandle, uint16_t packetsize)
\r