LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
EHCI.c
Go to the documentation of this file.
1 /*
2  * @brief Enhanced 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_EHCI__))
39 
40 #define __LPC_EHCI_C__
41 #include "../../../../../Common/Common.h"
42 #include "../../USBTask.h"
43 #include "../HCD.h"
44 #include "EHCI.h"
45 
46 // === TODO: Unify USBRAM Section ===
48 EHCI_HOST_DATA_T ehci_data[MAX_USB_CORE] __BSS(USBRAM_SECTION);
49 // EHCI_HOST_DATA_T ehci_data __BSS(USBRAM_SECTION);
51 NextLinkPointer PeriodFrameList0[FRAME_LIST_SIZE] ATTR_ALIGNED(4096) __BSS(USBRAM_SECTION); /* Period Frame List */
53 NextLinkPointer PeriodFrameList1[FRAME_LIST_SIZE] ATTR_ALIGNED(4096) __BSS(USBRAM_SECTION); /* Period Frame List */
54 Pipe_Stream_Handle_T PipeStreaming[MAX_USB_CORE];
55 /*=======================================================================*/
56 /* G L O B A L F U N C T I O N S */
57 /*=======================================================================*/
58 HCD_STATUS HcdInitDriver(uint8_t HostID)
59 {
60  EHciHostReset(HostID);
61  return EHciHostInit(HostID);
62 }
63 
64 HCD_STATUS HcdDeInitDriver(uint8_t HostID)
65 {
66  USB_REG(HostID)->USBSTS_H = 0xFFFFFFFF; /* clear all current interrupts */
67  USB_REG(HostID)->PORTSC1_H &= ~(1 << 12); /* clear port power */
68  USB_REG(HostID)->USBMODE_H = (1 << 0); /* set USB mode reserve */
69 
70  return HCD_STATUS_OK;
71 }
72 
73 HCD_STATUS HcdRhPortEnable(uint8_t HostID)
74 {
75  return HCD_STATUS_OK;
76 }
77 
78 HCD_STATUS HcdRhPortDisable(uint8_t HostID)
79 {
80  return HCD_STATUS_OK;
81 }
82 
83 HCD_STATUS HcdRhPortReset(uint8_t HostID)
84 {
86 
87  USB_REG(HostID)->PORTSC1_H &= ~EHC_PORTSC_PortEnable; /* Disable Port first */
88  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortReset; /* Reset port */
89 
90  /* should have time-out */
91  while (USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_PortReset) {}
92 
93  /* PortEnable is always set - Deviation from EHCI */
94 
96  return HCD_STATUS_OK;
97 }
98 
99 HCD_STATUS HcdClearEndpointHalt(uint32_t PipeHandle)// FIXME not implemented
100 {
101  return HCD_STATUS_OK;
102 }
103 
104 uint32_t HcdGetFrameNumber(uint8_t HostID)
105 {
106  return USB_REG(HostID)->FRINDEX_H;
107 }
108 
109 HCD_STATUS HcdGetDeviceSpeed(uint8_t HostID, HCD_USB_SPEED *DeviceSpeed)
110 {
111  if ( USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_CurrentConnectStatus) {/* If device is connected */
112  *DeviceSpeed = (HCD_USB_SPEED) ( (USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_PortSpeed) >> 26 ); /* TODO magic number */
113  return HCD_STATUS_OK;
114  }
115  else {
117  }
118 }
119 
120 HCD_STATUS HcdOpenPipe(uint8_t HostID,
121  uint8_t DeviceAddr,
122  HCD_USB_SPEED DeviceSpeed,
123  uint8_t EndpointNumber,
124  HCD_TRANSFER_TYPE TransferType,
125  HCD_TRANSFER_DIR TransferDir,
126  uint16_t MaxPacketSize,
127  uint8_t Interval,
128  uint8_t Mult,
129  uint8_t HSHubDevAddr,
130  uint8_t HSHubPortNum,
131  uint32_t *const pPipeHandle)
132 {
133  uint32_t HeadIdx;
134 
135 #if !ISO_LIST_ENABLE
136  if ( TransferType == ISOCHRONOUS_TRANSFER ) {
137  ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set ISO_LIST_ENABLE to YES");
138  }
139 #endif
140 
141 #if !INTERRUPT_LIST_ENABLE
142  if ( TransferType == INTERRUPT_TRANSFER ) {
143  ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set INTERRUPT_LIST_ENABLE to YES");
144  }
145 #endif
146 
147  /********************************* Parameters Verify *********************************/
148  ASSERT_STATUS_OK(OpenPipe_VerifyParameters(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType,
149  TransferDir, MaxPacketSize, Interval, Mult) );
150 
151  EndpointNumber &= 0xF; /* Endpoint number is in range 0-15 */
152  MaxPacketSize &= 0x3FF; /* Max Packet Size is in range 0-1024 */
153 
154  switch (TransferType) { // TODO should unify more, perharps later
155  case CONTROL_TRANSFER:
156  case BULK_TRANSFER:
157  ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
158  MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
159  DisableAsyncSchedule(HostID);
160  InsertLinkPointer(&HcdAsyncHead(HostID)->Horizontal, &HcdQHD(HostID, HeadIdx)->Horizontal, QHD_TYPE);
161  EnableAsyncSchedule(HostID);
162  break;
163 
164  case INTERRUPT_TRANSFER:
165  ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
166  MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
167  DisablePeriodSchedule(HostID);
168  InsertLinkPointer(&HcdIntHead(HostID)->Horizontal, &HcdQHD(HostID, HeadIdx)->Horizontal, QHD_TYPE);
169  EnablePeriodSchedule(HostID);
170  memset(&PipeStreaming[HostID], 0, sizeof(Pipe_Stream_Handle_T));
171  break;
172 
174 #ifndef __TEST__
175  if (( DeviceSpeed == HIGH_SPEED) || ( TransferDir == IN_TRANSFER) ) { /* TODO currently not support HS due to lack of device for testing */
177  "Highspeed ISO and ISO IN is not supported yet, due to lack of testing");
178  }
179 #endif
180  ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
181  MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
182  EnablePeriodSchedule(HostID);
183  break;
184  }
185 
186  PipehandleCreate(pPipeHandle, HostID, TransferType, HeadIdx);
187  return HCD_STATUS_OK;
188 }
189 
190 HCD_STATUS HcdClosePipe(uint32_t PipeHandle)
191 {
192  uint8_t HostID, HeadIdx;
193  HCD_TRANSFER_TYPE XferType;
194 
195  ASSERT_STATUS_OK(HcdCancelTransfer(PipeHandle) );
196  ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
197 
198  switch (XferType) {
199  case CONTROL_TRANSFER:
200  case BULK_TRANSFER:
201  case INTERRUPT_TRANSFER:
202  RemoveQueueHead(HostID, HeadIdx);
203  USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_IntAsyncAdvanceDoorbell; /* DoorBell Handshake: Queue Head will only be free in AsyncAdvanceIsr */
204  break;
205 
207  FreeQhd(HostID, HeadIdx);
208  DisablePeriodSchedule(HostID);
209  break;
210  }
211  return HCD_STATUS_OK;
212 }
213 
215 {
216  uint8_t HostID, HeadIdx;
217  HCD_TRANSFER_TYPE XferType;
218 
219  ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
220 
221  DisableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);
222 
223  if (XferType == ISOCHRONOUS_TRANSFER) { /* ISOCHRONOUS_TRANSFER */
224  uint32_t i;
225  for (i = 0; i < FRAME_LIST_SIZE; i++) { /*-- Foreach link in Period List Base --*/
226  NextLinkPointer *pNextPointer = &EHCI_FRAME_LIST(HostID)[i];
227 
228  /*-- Foreach Itd/SItd in the link--*/
229  while ( isValidLink(pNextPointer->Link) && pNextPointer->Type != QHD_TYPE) {
230  if (pNextPointer->Type == ITD_TYPE) { /*-- Highspeed ISO --*/
231  PHCD_HS_ITD pItd = (PHCD_HS_ITD) Align32(pNextPointer->Link);
232 
233  if (HeadIdx == pItd->IhdIdx) {
234  /*-- remove matched ITD --*/
235  pNextPointer->Link = pItd->Horizontal.Link;
236  FreeHsItd(pItd);
237  continue; /*-- skip advance pNextPointer due to TD removal --*/
238  }
239  }
240  else if (pNextPointer->Type == SITD_TYPE) { /*-- Split ISO --*/
241  PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);
242 
243  if (HeadIdx == pSItd->IhdIdx) {
244  /*-- removed matched SITD --*/
245  pNextPointer->Link = pSItd->Horizontal.Link;
246  FreeSItd(pSItd);
247  continue; /*-- skip advance pNextPointer due to TD removal --*/
248  }
249  }
250  pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);
251  }
252  }
253  }
254  else { /*-- Bulk / Control / Interrupt --*/
255  uint32_t TdLink = HcdQHD(HostID, HeadIdx)->FirstQtd;
256 
257  /*-- Foreach Qtd in Qhd --*/ /*---------- Deactivate all queued TDs ----------*/
258  while ( isValidLink(TdLink) ) {
259  PHCD_QTD pQtd = (PHCD_QTD) Align32(TdLink);
260  TdLink = pQtd->NextQtd;
261 
262  pQtd->Active = 0;
263  pQtd->IntOnComplete = 0;/* no interrupt scenario on this TD */
264  FreeQtd(pQtd);
265  }
266  HcdQHD(HostID, HeadIdx)->FirstQtd = LINK_TERMINATE;
267  }
268 
269  EnableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);
270  return HCD_STATUS_OK;
271 }
272 
274  const USB_Request_Header_t *const pDeviceRequest,
275  uint8_t *const buffer)
276 {
277  uint8_t HostID, QhdIdx;
278  HCD_TRANSFER_TYPE XferType;
279  uint32_t SetupTdIdx, DataTdIdx, StatusTdIdx;
280  uint8_t direction;
281  uint32_t Datalength;
282 
283  if ((pDeviceRequest == NULL) || (buffer == NULL)) {
284  ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Device Request or Data Buffer is NULL");
285  }
286 
287  ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &QhdIdx) );
288 
289  Datalength = pDeviceRequest->wLength;
290  direction = pDeviceRequest->bmRequestType & 0x80;
291 
292  /*---------- Setup Stage ----------*/
293  ASSERT_STATUS_OK(AllocQTD(HostID, &SetupTdIdx, (uint8_t *) pDeviceRequest, 8, SETUP_TRANSFER, 0, 0) ); /* Setup TD: DirectionPID=00 - DataToggle=10b (always DATA0) */
294 
295  /*---------- Data Stage ----------*/
296  if (Datalength) {
297  ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, Datalength, direction ? IN_TRANSFER : OUT_TRANSFER, 1, 0) );
298  }
299  else {
300  DataTdIdx = SetupTdIdx; /* Data TD is skipped */
301  }
302 
303  /*---------- Status Stage ----------*/
304  ASSERT_STATUS_OK(AllocQTD(HostID, &StatusTdIdx, NULL, 0, direction ? OUT_TRANSFER : IN_TRANSFER, 1, 1) ); /* Status TD: Direction=opposite of data direction - DataToggle=11b (always DATA1) */
305 
306  /* Hook TDs Together */
307  HcdQTD(HostID, SetupTdIdx)->NextQtd = (uint32_t) HcdQTD(HostID, DataTdIdx);
308  HcdQTD(HostID, DataTdIdx)->NextQtd = (uint32_t) HcdQTD(HostID, StatusTdIdx);
309 
310  HcdQHD(HostID, QhdIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;
311 
312  /* Hook TDs to QHD */
313  HcdQHD(HostID, QhdIdx)->FirstQtd = Align32( (uint32_t) HcdQTD(HostID, SetupTdIdx) );
314  HcdQHD(HostID, QhdIdx)->Overlay.NextQtd = (uint32_t) HcdQTD(HostID, SetupTdIdx);
315 
316  /* wait for semaphore compete TDs */
317  ASSERT_STATUS_OK(WaitForTransferComplete(HostID, QhdIdx) );
318 
319  return HCD_STATUS_OK;
320 }
321 
323  uint8_t *const buffer,
324  uint32_t const length,
325  uint16_t *const pActualTransferred)
326 {
327  uint8_t HostID, HeadIdx;
328  HCD_TRANSFER_TYPE XferType;
329  uint32_t DataTdIdx;
330  uint32_t ExpectedLength;
331 
332  if ((buffer == NULL) || (length == 0)) {
333  ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Data Buffer is NULL or Transfer Length is 0");
334  }
335 
336  ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
337 
338  ExpectedLength = (length != HCD_ENDPOINT_MAXPACKET_XFER_LEN) ? length : HcdQHD(HostID, HeadIdx)->MaxPackageSize;
339 
340  HcdQHD(HostID, HeadIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;
341 
342  if (XferType == ISOCHRONOUS_TRANSFER) {
343  if ( HcdQHD(HostID, HeadIdx)->EndpointSpeed == HIGH_SPEED ) { /*-- Highspeed ISO --*/
344  ASSERT_STATUS_OK(QueueITDs(HostID, HeadIdx, buffer, ExpectedLength) );
345  }
346  else { /*-- Full/Low Speed ISO --*/
347  ASSERT_STATUS_OK(QueueSITDs(HostID, HeadIdx, buffer, ExpectedLength) );
348  }
349  }
350  else { /*-- Control / Bulk / Interrupt --*/
351  if(XferType == BULK_TRANSFER)
352  {
353  ASSERT_STATUS_OK( QueueQTDs(HostID, &DataTdIdx, buffer, ExpectedLength,
354  HcdQHD(HostID,HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0) );
355  }
356  else
357  {
358  ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, ExpectedLength,
359  HcdQHD(HostID, HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0, 1) );
360  }
361  /*---------- Hook to Queue Head ----------*/
362  HcdQHD(HostID, HeadIdx)->FirstQtd = Align32( (uint32_t) HcdQTD(HostID, DataTdIdx) ); /* used as TD head to clean up TD chain when transfer done */
363  HcdQHD(HostID, HeadIdx)->Overlay.NextQtd = (uint32_t) HcdQTD(HostID, DataTdIdx);
364  }
365 
366  HcdQHD(HostID, HeadIdx)->pActualTransferCount = pActualTransferred; /* TODO Actual Length get rid of this */
367  if (HcdQHD(HostID, HeadIdx)->pActualTransferCount) {
368  *(HcdQHD(HostID, HeadIdx)->pActualTransferCount) = ExpectedLength;
369  }
370 
371  return HCD_STATUS_OK;
372 }
373 
374 HCD_STATUS HcdGetPipeStatus(uint32_t PipeHandle)/* TODO can be implemented based on overlay */
375 {
376  uint8_t HostID, HeadIdx;
377  HCD_TRANSFER_TYPE XferType;
378 
379  ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
380 
381  return (HCD_STATUS)HcdQHD(HostID, HeadIdx)->status;
382 }
383 
384 static void FreeQhd(uint8_t HostID, uint8_t QhdIdx)
385 {
386  HcdQHD(HostID, QhdIdx)->status = HCD_STATUS_STRUCTURE_IS_FREE;
387  HcdQHD(HostID, QhdIdx)->Horizontal.Link |= LINK_TERMINATE;
388  HcdQHD(HostID, QhdIdx)->inUse = 0;
389 }
390 
391 static HCD_STATUS AllocQhd(uint8_t HostID,
392  uint8_t DeviceAddr,
393  HCD_USB_SPEED DeviceSpeed,
394  uint8_t EndpointNumber,
395  HCD_TRANSFER_TYPE TransferType,
396  HCD_TRANSFER_DIR TransferDir,
397  uint16_t MaxPacketSize,
398  uint8_t Interval,
399  uint8_t Mult,
400  uint8_t HSHubDevAddr,
401  uint8_t HSHubPortNum,
402  uint32_t *pQhdIdx)
403 {
404  /* Looking for a free QHD */
405  for ( (*pQhdIdx) = 0; (*pQhdIdx) < HCD_MAX_QTD && HcdQHD(HostID, *pQhdIdx)->inUse; (*pQhdIdx)++) {}
406 
407  if ((*pQhdIdx) == HCD_MAX_QTD ) {
409  }
410 
411  memset(HcdQHD(HostID, *pQhdIdx), 0, sizeof(HCD_QHD) );
412 
413  /* Init Data For Queue Head */
414  HcdQHD(HostID, *pQhdIdx)->inUse = 1;
415  HcdQHD(HostID, *pQhdIdx)->Direction = (TransferDir == IN_TRANSFER) ? 1 : 0; /* Control Endpoint should not use this parameter */
416  HcdQHD(HostID, *pQhdIdx)->Interval = Interval;
417  HcdQHD(HostID, *pQhdIdx)->status = HCD_STATUS_OK;
418  HcdQHD(HostID, *pQhdIdx)->FirstQtd = LINK_TERMINATE;
419 
420  HcdQHD(HostID, *pQhdIdx)->Horizontal.Link = LINK_TERMINATE;
421  HcdQHD(HostID, *pQhdIdx)->DeviceAddress = DeviceAddr;
422 
423  HcdQHD(HostID, *pQhdIdx)->InActiveOnNextTransaction = 0;
424  HcdQHD(HostID, *pQhdIdx)->EndpointNumber = EndpointNumber;
425  HcdQHD(HostID, *pQhdIdx)->EndpointSpeed = (uint32_t) DeviceSpeed;
426  HcdQHD(HostID, *pQhdIdx)->DataToggleControl = (TransferType == CONTROL_TRANSFER) ? 1 : 0;
427  HcdQHD(HostID, *pQhdIdx)->HeadReclamationFlag = 0;
428  HcdQHD(HostID, *pQhdIdx)->MaxPackageSize = MaxPacketSize;
429  HcdQHD(HostID,
430  *pQhdIdx)->ControlEndpointFlag = (DeviceSpeed != HIGH_SPEED && TransferType == CONTROL_TRANSFER) ? 1 : 0;
431  HcdQHD(HostID, *pQhdIdx)->NakCountReload = 0; /* infinite NAK/NYET */
432 
433  /*-- Currently All interrupt endpoints will be served as 1 (micro)frame polling, thus Interval parameter is ignored --*/
434  /*-- For High Speed Interval should be used to compute the uFrameSMask --*/
435  HcdQHD(HostID,
436  *pQhdIdx)->uFrameSMask =
437  (TransferType == INTERRUPT_TRANSFER) ? (DeviceSpeed == HIGH_SPEED ? 0xFF : 0x01) : 0;
438  HcdQHD(HostID,
439  *pQhdIdx)->uFrameCMask = (DeviceSpeed != HIGH_SPEED && TransferType == INTERRUPT_TRANSFER) ? 0x1C : 0; /*-- Schedule Complete Split at uFrame2, uFrame3 and uFrame4 --*/
440  HcdQHD(HostID, *pQhdIdx)->HubAddress = HSHubDevAddr;
441  HcdQHD(HostID, *pQhdIdx)->PortNumber = HSHubPortNum;
442  HcdQHD(HostID, *pQhdIdx)->Mult = (DeviceSpeed == HIGH_SPEED ? Mult : 1);
443 
444  HcdQHD(HostID, *pQhdIdx)->Overlay.NextQtd = LINK_TERMINATE;
445  HcdQHD(HostID, *pQhdIdx)->Overlay.AlterNextQtd = LINK_TERMINATE;
446  HcdQHD(HostID, *pQhdIdx)->FirstQtd = LINK_TERMINATE;
447 
448  HcdQHD(HostID,
449  *pQhdIdx)->Overlay.PingState_Err =
450  (DeviceSpeed == HIGH_SPEED && TransferType != INTERRUPT_TRANSFER && TransferDir == OUT_TRANSFER) ? 1 : 0;
451 
452  return HCD_STATUS_OK;
453 }
454 
455 static HCD_STATUS InsertLinkPointer(NextLinkPointer *pList, NextLinkPointer *pNew, uint8_t type)
456 {
457  pNew->Link = pList->Link;
458  pList->Link = Align32( (uint32_t) pNew);
459  pList->Type = type;
460  return HCD_STATUS_OK;
461 }
462 
463 static HCD_STATUS RemoveQueueHead(uint8_t HostID, uint8_t QhdIdx)
464 {
465  PHCD_QHD pQhd = IsInterruptQhd(HostID, QhdIdx) ? HcdIntHead(HostID) : HcdAsyncHead(HostID);
466  /*-- Foreach Qhd in async list --*/
467  while ( isValidLink(pQhd->Horizontal.Link) &&
468  Align32(pQhd->Horizontal.Link) != (uint32_t) HcdQHD(HostID, QhdIdx) &&
469  Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
470  pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
471  }
472  if ( Align32(pQhd->Horizontal.Link) != (uint32_t) HcdQHD(HostID, QhdIdx) ) {
474  }
475 
476  HcdQHD(HostID, QhdIdx)->status = (uint32_t) HCD_STATUS_TO_BE_REMOVED; /* Will be remove in AsyncAdvanceIsr - make use of IAAD */
477  pQhd->Horizontal.Link = HcdQHD(HostID, QhdIdx)->Horizontal.Link;
478 
479  return HCD_STATUS_OK;
480 }
481 
482 /*---------- Queue TD Routines ----------*/
483 static void FreeQtd(PHCD_QTD pQtd)
484 {
485  pQtd->NextQtd |= LINK_TERMINATE;
486  pQtd->inUse = 0;
487 }
488 
490 static HCD_STATUS AllocQTD(uint8_t HostID,
491  uint32_t *pTdIdx,
492  uint8_t *const BufferPointer,
493  uint32_t xferLen,
494  HCD_TRANSFER_DIR PIDCode,
495  uint8_t DataToggle,
496  uint8_t IOC)
497 {
498  for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_QTD && HcdQTD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
499 
500  if ((*pTdIdx) < HCD_MAX_QTD) {
501  uint8_t idx = 1;
502  uint32_t BytesInPage;
503 
504  memset(HcdQTD(HostID, *pTdIdx), 0, sizeof(HCD_QTD));
505 
506  HcdQTD(HostID, *pTdIdx)->NextQtd = 1;
507 
508  HcdQTD(HostID, *pTdIdx)->AlterNextQtd = LINK_TERMINATE;
509  HcdQTD(HostID, *pTdIdx)->inUse = 1;
510 
511  HcdQTD(HostID, *pTdIdx)->Active = 1;
512  HcdQTD(HostID, *pTdIdx)->PIDCode = (PIDCode == SETUP_TRANSFER) ? 2 : (PIDCode == IN_TRANSFER ? 1 : 0);
513  HcdQTD(HostID, *pTdIdx)->TotalBytesToTransfer = xferLen;
514  HcdQTD(HostID, *pTdIdx)->DataToggle = DataToggle;
515  HcdQTD(HostID, *pTdIdx)->IntOnComplete = IOC;
516 
517  HcdQTD(HostID, *pTdIdx)->BufferPointer[0] = (uint32_t) BufferPointer;
518  BytesInPage = 0x1000 - Offset4k((uint32_t) BufferPointer);
519  xferLen -= MIN(xferLen, BytesInPage); /*-- Trim down xferlen to be multiple of 4k --*/
520 
521  for (idx = 1; idx <= 4 && xferLen > 0; idx++) {
522  HcdQTD(HostID,
523  *pTdIdx)->BufferPointer[idx] = Align4k(HcdQTD(HostID, (*pTdIdx))->BufferPointer[idx - 1]) + 0x1000;
524  xferLen -= MIN(xferLen, 0x1000);
525  }
526  return HCD_STATUS_OK;
527  }
528  else {
530  }
531 }
532 
533 static HCD_STATUS QueueQTDs (uint8_t HostID,
534  uint32_t* pTdIdx,
535  uint8_t* dataBuff,
536  uint32_t xferLen,
537  HCD_TRANSFER_DIR PIDCode,
538  uint8_t DataToggle)
539 {
540  uint32_t TailTdIdx=0xFFFFFFFF;
541 
542  while (xferLen > 0)
543  {
544  uint32_t TdLen;
545  uint32_t MaxTDLen = QTD_MAX_XFER_LENGTH - Offset4k((uint32_t)dataBuff);
546 
547  if(PipeStreaming[HostID].PacketSize > 0)
548  TdLen = MIN(xferLen, PipeStreaming[HostID].PacketSize);
549  else
550  TdLen = MIN(xferLen, MaxTDLen);
551  xferLen -= TdLen;
552 
553  if (TailTdIdx == 0xFFFFFFFF)
554  {
555  ASSERT_STATUS_OK ( AllocQTD(HostID, pTdIdx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0) );
556  TailTdIdx = *pTdIdx;
557  }
558  else
559  {
560  uint32_t NewTdIDx;
561  if(HCD_STATUS_OK == AllocQTD(HostID, &NewTdIDx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0))
562  {
563  HcdQTD(HostID,TailTdIdx)->NextQtd = Align32((uint32_t) HcdQTD(HostID,NewTdIDx));
564  TailTdIdx = NewTdIDx;
565  }
566  else
567  {
568  PipeStreaming[HostID].BufferAddress = (uint32_t)dataBuff;
569  PipeStreaming[HostID].RemainBytes = xferLen + TdLen;
570  PipeStreaming[HostID].DataToggle = DataToggle;
571  HcdQTD(HostID,HCD_MAX_QTD - 1)->IntOnComplete = 1;
572  break;
573  }
574  }
575  if(DataToggle == 1) DataToggle = 0;
576  else DataToggle = 1;
577  dataBuff += TdLen;
578  }
579  if(xferLen == 0)
580  {
581  memset(&PipeStreaming[HostID], 0, sizeof(Pipe_Stream_Handle_T));
582  }
583  return HCD_STATUS_OK;
584 }
585 
586 static void FreeHsItd(PHCD_HS_ITD pItd)
587 {
588  pItd->Horizontal.Link |= LINK_TERMINATE;
589  pItd->inUse = 0;
590 }
591 
592 HCD_STATUS AllocHsItd(uint8_t HostID,
593  uint32_t *pTdIdx,
594  uint8_t IhdIdx,
595  uint8_t *dataBuff,
596  uint32_t TDLen,
597  uint8_t XactPerITD,
598  uint8_t IntOnComplete)
599 {
600  for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_HS_ITD && HcdHsITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
601  if ((*pTdIdx) < HCD_MAX_HS_ITD) {
602  uint8_t i;
603  uint8_t XactStep = 8 / XactPerITD;
604  uint32_t MaxXactLen = HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;
605 
606  memset(HcdHsITD(HostID, *pTdIdx), 0, sizeof(HCD_HS_ITD));
607 
608  HcdHsITD(HostID, *pTdIdx)->inUse = 1;
609  HcdHsITD(HostID, *pTdIdx)->IhdIdx = IhdIdx;
610 
611  HcdHsITD(HostID, *pTdIdx)->Horizontal.Link = LINK_TERMINATE;
612  for (i = 0; TDLen > 0 && i < 8; i += XactStep) {
613  uint32_t XactLen = MIN(TDLen, MaxXactLen);
614  TDLen -= XactLen;
615 
616  HcdHsITD(HostID, *pTdIdx)->BufferPointer[i] = Align4k( (uint32_t) dataBuff);
617 
618  HcdHsITD(HostID, *pTdIdx)->Transaction[i].Offset = ( (uint32_t) dataBuff ) & 4095;
619  HcdHsITD(HostID, *pTdIdx)->Transaction[i].PageSelect = i;
620  HcdHsITD(HostID, *pTdIdx)->Transaction[i].IntOnComplete = (IntOnComplete && TDLen == 0) ? 1 : 0;
621  HcdHsITD(HostID, *pTdIdx)->Transaction[i].Length = XactLen;
622  HcdHsITD(HostID, *pTdIdx)->Transaction[i].Active = 1;
623 
624  dataBuff += XactLen;
625  }
626 
627  HcdHsITD(HostID, *pTdIdx)->BufferPointer[0] |= (HcdQHD(HostID, IhdIdx)->EndpointNumber << 8) | HcdQHD(HostID,
628  IhdIdx)->
630  HcdHsITD(HostID,
631  *pTdIdx)->BufferPointer[1] |=
632  (HcdQHD(HostID, IhdIdx)->Direction << 1) | HcdQHD(HostID, IhdIdx)->MaxPackageSize;
633  HcdHsITD(HostID, *pTdIdx)->BufferPointer[2] |= HcdQHD(HostID, IhdIdx)->Mult;
634 
635  return HCD_STATUS_OK;
636  }
637  else {
639  }
640 }
641 
642 static HCD_STATUS QueueITDs(uint8_t HostID, uint8_t IhdIdx, uint8_t *dataBuff, uint32_t xferLen)
643 {
644  uint32_t MaxTDLen;
645  uint32_t FrameIdx;
646 
647 #if 0 /* Maximum bandwidth (Interval = 1) regardless of Interval value */
648  uint8_t XactPerITD;
649  uint32_t FramePeriod;
650  if (HcdQHD(IhdIdx)->Interval < 4) { /*-- Period < 8 --*/
651  XactPerITD = 1 << ( 4 - HcdQHD(IhdIdx)->Interval ); /*-- Interval 1 => 8, 2 => 4, 3 => 2 --*/
652  FramePeriod = 1;
653  }
654  else {
655  XactPerITD = 1;
656  FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 ); /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/
657  }
658 #else
659  #define XactPerITD 8
660  #define FramePeriod 1
661 #endif
662 
663  MaxTDLen = XactPerITD * HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;
664  FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;
665 
666  if (xferLen > MaxTDLen * FRAME_LIST_SIZE) { /*-- Data length overflow the Period FRAME LIST --*/
669  "ISO data length overflows the Period Frame List size, Please increase size by FRAMELIST_SIZE_BITS or reduce data length");
670  }
671 
672  while (xferLen > 0) {
673  uint32_t TdIdx;
674  uint32_t TDLen;
675 
676  TDLen = MIN(xferLen, MaxTDLen);
677  xferLen -= TDLen;
678 
679  ASSERT_STATUS_OK(AllocHsItd(HostID, &TdIdx, IhdIdx, dataBuff, TDLen, XactPerITD, xferLen ? 0 : 1) );
680 
681  FrameIdx = (FrameIdx + FramePeriod) % FRAME_LIST_SIZE;
682  /*-- Hook ITD to Period List Base --*/
683  InsertLinkPointer(&EHCI_FRAME_LIST(HostID)[FrameIdx], &HcdHsITD(HostID, TdIdx)->Horizontal, ITD_TYPE);
684  dataBuff += TDLen;
685  }
686 
687  return HCD_STATUS_OK;
688 }
689 
690 static void FreeSItd(PHCD_SITD pSItd)
691 {
692  pSItd->Horizontal.Link |= LINK_TERMINATE;
693  pSItd->inUse = 0;
694 }
695 
696 static HCD_STATUS AllocSItd(uint8_t HostID,
697  uint32_t *pTdIdx,
698  uint8_t HeadIdx,
699  uint8_t *dataBuff,
700  uint32_t TDLen,
701  uint8_t IntOnComplete)
702 {
703 #define TCount_Pos 0
704 #define TPos_Pos 3
705 
706  for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_SITD && HcdSITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
707 
708  if ((*pTdIdx) < HCD_MAX_SITD) {
709  uint8_t TCount = TDLen / SPLIT_MAX_LEN_UFRAME + (TDLen % SPLIT_MAX_LEN_UFRAME ? 1 : 0); /*-- Number of Split Transactions --*/
710 
711  memset(HcdSITD(HostID, *pTdIdx), 0, sizeof(HCD_SITD) );
712 
713  HcdSITD(HostID, *pTdIdx)->inUse = 1;
714  HcdSITD(HostID, *pTdIdx)->IhdIdx = HeadIdx;
715 
716  /*-- Word 1 --*/
717  HcdSITD(HostID, *pTdIdx)->Horizontal.Link = LINK_TERMINATE;
718  /*-- Word 2 --*/
719  HcdSITD(HostID, *pTdIdx)->DeviceAddress = HcdQHD(HostID, HeadIdx)->DeviceAddress;
720  HcdSITD(HostID, *pTdIdx)->EndpointNumber = HcdQHD(HostID, HeadIdx)->EndpointNumber;
721  HcdSITD(HostID, *pTdIdx)->HubAddress = HcdQHD(HostID, HeadIdx)->HubAddress;
722  HcdSITD(HostID, *pTdIdx)->PortNumber = HcdQHD(HostID, HeadIdx)->PortNumber;
723  HcdSITD(HostID, *pTdIdx)->Direction = HcdQHD(HostID, HeadIdx)->Direction;
724  /*-- Word 3 --*/
725  HcdSITD(HostID, *pTdIdx)->uFrameSMask = (1 << TCount) - 1;
726  HcdSITD(HostID, *pTdIdx)->uFrameCMask = 0;
727  /*-- Word 4 --*/
728  HcdSITD(HostID, *pTdIdx)->Active = 1;
729  HcdSITD(HostID, *pTdIdx)->TotalBytesToTransfer = TDLen;
730  HcdSITD(HostID, *pTdIdx)->IntOnComplete = IntOnComplete;
731  /*-- Word 5 --*/
732  HcdSITD(HostID, *pTdIdx)->BufferPointer[0] = (uint32_t) dataBuff;
733  /*-- Word 6 --*/
734  HcdSITD(HostID, *pTdIdx)->BufferPointer[1] = Align4k( ((uint32_t) dataBuff) + TDLen);
735 
736  HcdSITD(HostID, *pTdIdx)->BufferPointer[1] |= TCount << TCount_Pos;
737  HcdSITD(HostID, *pTdIdx)->BufferPointer[1] |= (TCount > 1 ? 1 : 0 ) << TPos_Pos;/*-- TPosition - More than 1 split --> Begin Encoding, Otherwise All Encoding --*/
738 
739  // HcdSITD(*pTdIdx)->TCount = NoSplits;
740  // HcdSITD(*pTdIdx)->TPosition = (NoSplits > 1) ? 1 : 0 ; /*-- TPosition - More than 1 split --> Begin Encoding, Otherwise All Encoding --*/
741 
742  /*-- Word 7 --*/
743  HcdSITD(HostID, *pTdIdx)->BackPointer = LINK_TERMINATE;
744 
745  return HCD_STATUS_OK;
746  }
747  else {
749  }
750 }
751 
752 static HCD_STATUS QueueSITDs(uint8_t HostID, uint8_t HeadIdx, uint8_t *dataBuff, uint32_t xferLen)
753 {
754  uint32_t FrameIdx;
755 
756 #if 0 /* Maximum bandwidth (Interval = 1) regardless of Interval value */
757  uint8_t XactPerITD;
758  uint32_t FramePeriod;
759  if (HcdQHD(IhdIdx)->Interval < 4) { /*-- Period < 8 --*/
760  FramePeriod = 1;
761  }
762  else {
763  FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 ); /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/
764  }
765 #else
766  #define FramePeriod 1
767 #endif
768 
769  if (xferLen > HcdQHD(HostID, HeadIdx)->MaxPackageSize * FRAME_LIST_SIZE) { /*-- Data length overflow the Period FRAME LIST --*/
772  "ISO data length overflows the Period Frame List size, Please increase size by FRAMELIST_SIZE_BITS or reduce data length");
773  }
774 
775  FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;
776  while (xferLen) {
777  uint32_t TdIdx;
778  uint32_t TDLen;
779 
780  TDLen = MIN(xferLen, HcdQHD(HostID, HeadIdx)->MaxPackageSize);
781  xferLen -= TDLen;
782 
783  ASSERT_STATUS_OK(AllocSItd(HostID, &TdIdx, HeadIdx, dataBuff, TDLen, xferLen ? 0 : 1) );
784 
785  FrameIdx = (FrameIdx + FramePeriod) % FRAME_LIST_SIZE;
786  /*-- Hook SITD to Period List Base --*/
787  InsertLinkPointer(&EHCI_FRAME_LIST(HostID)[FrameIdx], &HcdSITD(HostID, TdIdx)->Horizontal, SITD_TYPE);
788  dataBuff += TDLen;
789  }
790  return HCD_STATUS_OK;
791 }
792 
793 static HCD_STATUS WaitForTransferComplete(uint8_t HostID, uint8_t EdIdx)/* TODO indentical to OHCI now */
794 {
795 
796 #ifndef __TEST__
797  while ( HcdQHD(HostID, EdIdx)->status == HCD_STATUS_TRANSFER_QUEUED ) {
798  /* Should have time-out but left blank intentionally for bug catcher */
799  }
800  return (HCD_STATUS) HcdQHD(HostID, EdIdx)->status;
801 #else
802  return HCD_STATUS_OK;
803 #endif
804 
805 }
806 
807 static HCD_STATUS PipehandleParse(uint32_t Pipehandle, uint8_t *pHostID, HCD_TRANSFER_TYPE *XferType, uint8_t *pIdx)
808 {
809  Pipe_Handle_T *pHandle = (Pipe_Handle_T *) (&Pipehandle);
810 
811  if ((pHandle->HostId >= MAX_USB_CORE) ||
812  ( pHandle->Idx >= HCD_MAX_QTD) ||
813  ( HcdQHD(pHandle->HostId, pHandle->Idx)->inUse == 0) ||
814  ( HcdQHD(pHandle->HostId, pHandle->Idx)->status == HCD_STATUS_TO_BE_REMOVED) ) {
816  }
817 
818  if (pHostID) {
819  *pHostID = pHandle->HostId;
820  }
821  if (pIdx) {
822  *pIdx = pHandle->Idx;
823  }
824  if (XferType) {
825  *XferType = (HCD_TRANSFER_TYPE) pHandle->Type;
826  }
827 
828  return HCD_STATUS_OK;
829 }
830 
831 static void PipehandleCreate(uint32_t *pPipeHandle, uint8_t HostID, HCD_TRANSFER_TYPE XferType, uint8_t idx)
832 {
833  /*---------- HostID | PortNum | Type | Idx ----------*/
834  Pipe_Handle_T *pHandle = (Pipe_Handle_T *) pPipeHandle;
835 
836  pHandle->HostId = HostID;
837  pHandle->PortNumber = 0;
838  pHandle->Type = (uint8_t) XferType;
839  pHandle->Idx = idx;
840 }
841 
842 static __INLINE PHCD_QHD HcdAsyncHead(uint8_t HostID)
843 {
844  return &(ehci_data[HostID].AsyncHeadQhd);
845  // return &(ehci_data.AsyncHeadQhd);
846 }
847 
848 static __INLINE PHCD_QHD HcdIntHead(uint8_t HostID)
849 {
850  return &(ehci_data[HostID].IntHeadQhd);
851  // return &(ehci_data.IntHeadQhd);
852 }
853 
854 // === TODO: Deal with HostID later ===
855 static __INLINE PHCD_QHD HcdQHD(uint8_t HostID, uint8_t idx)
856 {
857  return &(ehci_data[HostID].qHDs[idx]);
858  // return &(ehci_data.qHDs[idx]);
859 }
860 
861 static __INLINE PHCD_QTD HcdQTD(uint8_t HostID, uint8_t idx)
862 {
863  return &(ehci_data[HostID].qTDs[idx]);
864  // return &(ehci_data.qTDs[idx]);
865 }
866 
867 static __INLINE PHCD_SITD HcdSITD(uint8_t HostID, uint8_t idx)
868 {
869  return &(ehci_data[HostID].siTDs[idx]);
870  // return &(ehci_data.siTDs[idx]);
871 }
872 
873 static __INLINE PHCD_HS_ITD HcdHsITD(uint8_t HostID, uint8_t idx)
874 {
875  return &(ehci_data[HostID].iTDs[idx]);
876  // return &(ehci_data.iTDs[idx]);
877 }
878 
879 static __INLINE bool isValidLink(uint32_t link)
880 {
881  return (link & LINK_TERMINATE) == 0;
882 }
883 
884 static __INLINE bool IsInterruptQhd(uint8_t HostID, uint8_t QhdIdx)
885 {
886  return HcdQHD(HostID, QhdIdx)->uFrameSMask;
887 }
888 
889 void HcdIrqHandler(uint8_t HostID)
890 {
892  uint32_t t = USB_REG(HostID)->USBINTR_H;
893  IntStatus = USB_REG(HostID)->USBSTS_H & t;
894 
895  if (IntStatus == 0) {
896  return;
897  }
898 
899  /* disable all interrupt for processing */
900  /* Acknowledge Interrrupt */
901  USB_REG(HostID)->USBSTS_H |= IntStatus;
902 
903  /* Process Interrupt Sources */
904  if (IntStatus & EHC_USBSTS_PortChangeDetect) {
905  uint32_t PortSC = USB_REG(HostID)->PORTSC1_H;
906  if (PortSC & EHC_PORTSC_ConnectStatusChange) {
907  PortStatusChangeIsr(HostID, PortSC & EHC_PORTSC_CurrentConnectStatus);
908  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_ConnectStatusChange; /* Clear PortSC Interrupt Status */
909  }
910  if (PortSC & EHC_PORTSC_PortEnableChange) {
911  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortEnableChange; /* Clear PortSC Interrupt Status */
912  }
913  if (PortSC & EHC_PORTSC_OvercurrentChange) {
914  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_OvercurrentChange; /* Clear PortSC Interrupt Status */
915  }
916  if (PortSC & EHC_PORTSC_ForcePortResume) {
917  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_ForcePortResume; /* Clear PortSC Interrupt Status */
918  }
919  }
920 
921  if (IntStatus & EHC_USBSTS_UsbAsyncInt) {
922  AsyncScheduleIsr(HostID);
923  }
924 
925  if (IntStatus & EHC_USBSTS_UsbPeriodInt) {
926  PeriodScheduleIsr(HostID);
927  }
928 
929  if (IntStatus & EHC_USBSTS_UsbErrorInt) {
930  UsbErrorIsr(HostID);
931  }
932 
933  if (IntStatus & EHC_USBSTS_IntAsyncAdvance) {
934  AsyncAdvanceIsr(HostID);
935  }
936  /* Enable Interrupt */
937 }
938 
939 static void RemoveCompletedQTD(uint8_t HostID, PHCD_QHD pQhd)
940 {
941  PHCD_QTD pQtd;
942  uint32_t TdLink = pQhd->FirstQtd;
943  bool is_data_remain = false;
944 
945  /*-- Foreach Qtd in Qhd --*/
946  while( (isValidLink(TdLink), pQtd = (PHCD_QTD) Align32(TdLink) ) &&
947  pQtd->Active == 0)
948  {
949  TdLink = pQtd->NextQtd;
950 
951  if(pQhd->pActualTransferCount)
952  *(pQhd->pActualTransferCount) -= pQtd->TotalBytesToTransfer;
953 
954  if (pQtd->IntOnComplete)
955  {
956  if(PipeStreaming[HostID].RemainBytes > 0)
957  is_data_remain = true;
958  else
959  pQhd->status = HCD_STATUS_OK;
960  }
961  if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/)
962  {
963  pQhd->status = HCD_STATUS_TRANSFER_Stall;
964  }
965  FreeQtd(pQtd);
966  }
967  pQhd->FirstQtd = TdLink;
968  if(is_data_remain)
969  {
970  uint32_t pQtd;
971  QueueQTDs(HostID, &pQtd,(uint8_t*)PipeStreaming[HostID].BufferAddress,
972  PipeStreaming[HostID].RemainBytes,
973  pQhd->Direction ? IN_TRANSFER : OUT_TRANSFER,
974  PipeStreaming[HostID].DataToggle);
975  pQhd->FirstQtd = Align32( (uint32_t) HcdQTD(HostID,pQtd) );
976  pQhd->Overlay.NextQtd = (uint32_t) HcdQTD(HostID,pQtd);
977  }
978 }
979 
980 static void RemoveErrorQTD(PHCD_QHD pQhd)
981 {
982  PHCD_QTD pQtd;
983  uint32_t TdLink = pQhd->FirstQtd;
984  bool errorfound = false;
985 
986  /*-- Scan error Qtd in Qhd --*/
987  while ( (isValidLink(TdLink), pQtd = (PHCD_QTD) Align32(TdLink) ) &&
988  pQtd->Active == 0) {
989  TdLink = pQtd->NextQtd;
990 
991  if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/) {
992  errorfound = true;
993  pQhd->status = HCD_STATUS_TRANSFER_Stall;
994  }
995  }
996  /*-- Remove error Qtd in Qhd --*/
997  if (errorfound) {
998  TdLink = pQhd->FirstQtd;
999  while (isValidLink(TdLink)) {
1000  pQtd = (PHCD_QTD) Align32(TdLink);
1001  TdLink = pQtd->NextQtd;
1002  pQtd->Active = 0;
1003  pQtd->IntOnComplete = 0;
1004  FreeQtd(pQtd);
1005  }
1006  pQhd->FirstQtd = LINK_TERMINATE;
1007  pQhd->Overlay.Halted = 0;
1008  }
1009 }
1010 
1011 /*---------- Interrupt On Compete has occurred, however we have no clues on which QueueHead it happened. Also IOC TD may be advanced already So we will free all TD which is not Active (transferred already) ----------*/
1012 static void AsyncScheduleIsr(uint8_t HostID)
1013 {
1014  PHCD_QHD pQhd = HcdAsyncHead(HostID);
1015 
1016  /*-- Foreach Qhd in async list --*/
1017  while ( isValidLink(pQhd->Horizontal.Link) &&
1018  Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
1019  pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
1020  RemoveCompletedQTD(HostID,pQhd);
1021  }
1022 }
1023 
1024 static void PeriodScheduleIsr(uint8_t HostID)
1025 {
1026  uint32_t i;
1027 
1028  /*ISOCHRONOUS*/
1029  for (i = 0; i < FRAME_LIST_SIZE; i++) { /*-- Foreach link in Period List Base --*/
1030  NextLinkPointer *pNextPointer = &EHCI_FRAME_LIST(HostID)[i];
1031 
1032  /*-- Foreach Itd/SItd in the link--*/
1033  while ( isValidLink(pNextPointer->Link) && pNextPointer->Type != QHD_TYPE ) {
1034  if (pNextPointer->Type == ITD_TYPE) { /*-- Highspeed ISO --*/
1035  PHCD_HS_ITD pItd = (PHCD_HS_ITD) Align32(pNextPointer->Link);
1036 
1037  if ((pItd->Transaction[0].Active == 0) && (pItd->Transaction[1].Active == 0) &&
1038  ( pItd->Transaction[2].Active == 0) && ( pItd->Transaction[3].Active == 0) &&
1039  ( pItd->Transaction[4].Active == 0) && ( pItd->Transaction[5].Active == 0) &&
1040  ( pItd->Transaction[6].Active == 0) && ( pItd->Transaction[7].Active == 0) ) {
1041  if ((pItd->Transaction[0].IntOnComplete == 1) || (pItd->Transaction[1].IntOnComplete == 1) ||
1042  ( pItd->Transaction[2].IntOnComplete == 1) || ( pItd->Transaction[3].IntOnComplete == 1) ||
1043  ( pItd->Transaction[4].IntOnComplete == 1) || ( pItd->Transaction[5].IntOnComplete == 1) ||
1044  ( pItd->Transaction[6].IntOnComplete == 1) || ( pItd->Transaction[7].IntOnComplete == 1) ) {
1045  /*-- request complete, signal on Iso Head --*/
1046  HcdQHD(HostID, pItd->IhdIdx)->status = HCD_STATUS_OK;
1047  }
1048  /*-- remove executed ITD --*/
1049  pNextPointer->Link = pItd->Horizontal.Link;
1050  FreeHsItd(pItd);
1051  continue; /*-- skip advance pNextPointer due to TD removal --*/
1052  }
1053  }
1054  else if (pNextPointer->Type == SITD_TYPE) { /*-- Split ISO --*/
1055  PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);
1056 
1057  if (pSItd->Active == 0) {
1058  if (pSItd->IntOnComplete) {
1059  /*-- request complete, signal on Iso Head --*/
1060  HcdQHD(HostID, pSItd->IhdIdx)->status = HCD_STATUS_OK;
1061  }
1062 
1063  /*-- removed executed SITD --*/
1064  pNextPointer->Link = pSItd->Horizontal.Link;
1065  FreeSItd(pSItd);
1066  continue; /*-- skip advance pNextPointer due to TD removal --*/
1067  }
1068  }
1069 
1070  pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);
1071  }
1072  }
1073 
1074  /*INTERRUPT*/
1075  {
1076  PHCD_QHD pQhd = HcdIntHead(HostID);
1077 
1078  /*-- Foreach Qhd in list --*/
1079  while ( isValidLink(pQhd->Horizontal.Link) ) {
1080  pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
1081  RemoveCompletedQTD(HostID,pQhd);
1082  }
1083  }
1084 }
1085 
1086 static void UsbErrorIsr(uint8_t HostID)
1087 {
1088  PHCD_QHD pQhd = HcdAsyncHead(HostID);
1089 
1090  /*-- Foreach Qhd in async list --*/
1091  while ( isValidLink(pQhd->Horizontal.Link) &&
1092  Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
1093  pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
1094  RemoveErrorQTD(pQhd);
1095  }
1096 }
1097 
1098 static HCD_STATUS PortStatusChangeIsr(uint8_t HostID, uint32_t deviceConnect)
1099 {
1100  if (deviceConnect) {/* Device Attached */
1101  USB_Host_Enumerate(HostID);
1102  }
1103  else { /* Device detached */
1104  USB_Host_DeEnumerate(HostID);
1105  }
1106  return HCD_STATUS_OK;
1107 }
1108 
1109 static void AsyncAdvanceIsr(uint8_t HostID)
1110 {
1111  uint32_t QhdIdx;
1112 
1113  for (QhdIdx = 0; QhdIdx < HCD_MAX_QHD; QhdIdx++)
1114  if ((HcdQHD(HostID, QhdIdx)->inUse == 1) && (HcdQHD(HostID, QhdIdx)->status == HCD_STATUS_TO_BE_REMOVED)) {
1115  FreeQhd(HostID, QhdIdx);
1116  }
1117 }
1118 
1119 static __INLINE HCD_STATUS EHciHostRun(uint8_t HostID)
1120 {
1121  USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_RunStop;
1122  while (USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) {}
1123  return HCD_STATUS_OK;
1124 }
1125 
1126 static __INLINE HCD_STATUS EHciHostStop(uint8_t HostID)
1127 {
1128  USB_REG(HostID)->USBCMD_H &= ~EHC_USBCMD_RunStop;
1129  while ( !(USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) ) {}
1130  return HCD_STATUS_OK;
1131 }
1132 
1133 static __INLINE HCD_STATUS EHciHostReset(uint8_t HostID)
1134 {
1135  if (USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) {
1136  EHciHostStop(HostID);
1137  }
1138 
1139  USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_HostReset;
1140  while ( USB_REG(HostID)->USBCMD_H & EHC_USBCMD_HostReset ) {}
1141 
1142  /* Program the controller to be the USB host controller, this can only be done after Reset */
1143  USB_REG(HostID)->USBMODE_H = 0x23; // USBMODE_HostController | USBMODE_VBusPowerSelect_High;
1144  return HCD_STATUS_OK;
1145 }
1146 
1147 static __INLINE HCD_STATUS EHciHostInit(uint8_t HostID)
1148 {
1149  uint32_t idx;
1150 
1151  /*---------- Host Data Structure Init ----------*/
1152  // memset(&ehci_data[HostID], 0, sizeof(EHCI_HOST_DATA_T) );
1153 
1154  /*---------- USBINT ----------*/
1155  USB_REG(HostID)->USBINTR_H &= ~EHC_USBINTR_ALL; /* Disable All Interrupt */
1156  USB_REG(HostID)->USBSTS_H &= ~EHC_USBINTR_ALL; /* Clear All Interrupt Status */
1157  USB_REG(HostID)->USBINTR_H = EHC_USBINTR_UsbAsyncEnable | EHC_USBINTR_UsbPeriodEnable | /* Enable necessary interrupt source: Async Advance, System Error, Port Change, USB Error, USB Int */
1161 
1162  /*---------- Asynchronous List ----------*/
1163  /*-- Static Head Qhd with Halted/inactive --*/
1164  HcdAsyncHead(HostID)->Horizontal.Link = Align32( (uint32_t) HcdAsyncHead(HostID) );
1165  HcdAsyncHead(HostID)->Horizontal.Type = QHD_TYPE;
1166  HcdAsyncHead(HostID)->HeadReclamationFlag = 1;
1167  HcdAsyncHead(HostID)->Overlay.NextQtd = LINK_TERMINATE; /* Terminate Links */
1168  HcdAsyncHead(HostID)->Overlay.AlterNextQtd = LINK_TERMINATE; /* Terminate Links */
1169  HcdAsyncHead(HostID)->Overlay.Halted = 1;
1170 
1171  USB_REG(HostID)->ASYNCLISTADDR = (uint32_t) HcdAsyncHead(HostID);
1172 
1173  /*---------- Periodic List ----------*/
1174  /*-- Static Interrupt Qhd (1 ms) --*/
1175  HcdIntHead(HostID)->Horizontal.Link = LINK_TERMINATE;
1176  HcdIntHead(HostID)->Overlay.NextQtd = LINK_TERMINATE; /* Terminate Links */
1177  HcdIntHead(HostID)->Overlay.AlterNextQtd = LINK_TERMINATE; /* Terminate Links */
1178  HcdIntHead(HostID)->Overlay.Halted = 1;
1179  HcdIntHead(HostID)->uFrameSMask = 1;
1180 
1181  for (idx = 0; idx < FRAME_LIST_SIZE; idx++) { /* Attach 1 ms Interrupt Qhd to Period Frame List */
1182  EHCI_FRAME_LIST(HostID)[idx].Link = Align32( (uint32_t) HcdIntHead(HostID) );
1183  EHCI_FRAME_LIST(HostID)[idx].Type = QHD_TYPE;
1184  }
1185 
1186  USB_REG(HostID)->PERIODICLISTBASE = Align4k( (uint32_t) EHCI_FRAME_LIST(HostID) );
1187 
1188  /*---------- USBCMD ----------*/
1189  USB_REG(HostID)->USBCMD_H = EHC_USBCMD_AsynScheduleEnable |
1190  ((FRAMELIST_SIZE_BITS % 4) << 2) | ((FRAMELIST_SIZE_BITS / 4) << 15);
1191 
1192  /*---------- CONFIGFLAG ----------*/
1193  /* LPC18xx doesn't has CONFIGFLAG register */
1194 
1195  /*---------- Power On RhPort ----------*/
1196  USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortPowerControl;
1197 
1198  EHciHostRun(HostID);/* Run The HC */
1199 
1200  return HCD_STATUS_OK;
1201 }
1202 
1203 static __INLINE void DisableSchedule(uint8_t HostID, uint8_t isPeriod)
1204 {
1207 
1208  if (USB_REG(HostID)->USBSTS_H & statusMask) {
1209  USB_REG(HostID)->USBCMD_H &= ~cmdMask;
1210  while (USB_REG(HostID)->USBSTS_H & statusMask) {} /* TODO Should have time-out */
1211  }
1212 }
1213 
1214 static __INLINE void EnableSchedule(uint8_t HostID, uint8_t isPeriod)
1215 {
1218 
1219  if (!(USB_REG(HostID)->USBSTS_H & statusMask)) {
1220  USB_REG(HostID)->USBCMD_H |= cmdMask;
1221  while (!(USB_REG(HostID)->USBSTS_H & statusMask)) {}/* TODO Should have time-out */
1222  }
1223 }
1224 
1225 static void DisableAsyncSchedule(uint8_t HostID)
1226 {
1227  DisableSchedule(HostID, 0);
1228 }
1229 
1230 static void EnableAsyncSchedule(uint8_t HostID)
1231 {
1232  EnableSchedule(HostID, 0);
1233 }
1234 
1235 static void DisablePeriodSchedule(uint8_t HostID)
1236 {
1237  DisableSchedule(HostID, 1);
1238 }
1239 
1240 static void EnablePeriodSchedule(uint8_t HostID)
1241 {
1242  EnableSchedule(HostID, 1);
1243 }
1244 
1245 void HcdSetStreamPacketSize(uint32_t PipeHandle, uint16_t packetsize)
1246 {
1247  uint8_t HostID = 0, HeadIdx;
1248  HCD_TRANSFER_TYPE XferType;
1249 
1250  PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx);
1251 
1252  PipeStreaming[HostID].PacketSize = packetsize;
1253 }
1254 
1255 #endif // __LPC_EHCI__