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