2 * @brief Enhanced 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_EHCI__))
\r
40 #define __LPC_EHCI_C__
\r
41 #include "../../../../../Common/Common.h"
\r
42 #include "../../USBTask.h"
\r
46 // === TODO: Unify USBRAM Section ===
\r
48 EHCI_HOST_DATA_T ehci_data[MAX_USB_CORE] __BSS(USBRAM_SECTION);
\r
49 // EHCI_HOST_DATA_T ehci_data __BSS(USBRAM_SECTION);
\r
51 NextLinkPointer PeriodFrameList0[FRAME_LIST_SIZE] ATTR_ALIGNED(4096) __BSS(USBRAM_SECTION); /* Period Frame List */
\r
53 NextLinkPointer PeriodFrameList1[FRAME_LIST_SIZE] ATTR_ALIGNED(4096) __BSS(USBRAM_SECTION); /* Period Frame List */
\r
54 Pipe_Stream_Handle_T PipeStreaming[MAX_USB_CORE];
\r
55 /*=======================================================================*/
\r
56 /* G L O B A L F U N C T I O N S */
\r
57 /*=======================================================================*/
\r
58 HCD_STATUS HcdInitDriver(uint8_t HostID)
\r
60 EHciHostReset(HostID);
\r
61 return EHciHostInit(HostID);
\r
64 HCD_STATUS HcdDeInitDriver(uint8_t HostID)
\r
66 USB_REG(HostID)->USBSTS_H = 0xFFFFFFFF; /* clear all current interrupts */
\r
67 USB_REG(HostID)->PORTSC1_H &= ~(1 << 12); /* clear port power */
\r
68 USB_REG(HostID)->USBMODE_H = (1 << 0); /* set USB mode reserve */
\r
70 return HCD_STATUS_OK;
\r
73 HCD_STATUS HcdRhPortEnable(uint8_t HostID)
\r
75 return HCD_STATUS_OK;
\r
78 HCD_STATUS HcdRhPortDisable(uint8_t HostID)
\r
80 return HCD_STATUS_OK;
\r
83 HCD_STATUS HcdRhPortReset(uint8_t HostID)
\r
85 HcdDelayMS(PORT_RESET_PERIOD_MS);
\r
87 USB_REG(HostID)->PORTSC1_H &= ~EHC_PORTSC_PortEnable; /* Disable Port first */
\r
88 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortReset; /* Reset port */
\r
90 /* should have time-out */
\r
91 while (USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_PortReset) {}
\r
93 /* PortEnable is always set - Deviation from EHCI */
\r
95 HcdDelayMS(PORT_RESET_PERIOD_MS);
\r
96 return HCD_STATUS_OK;
\r
99 HCD_STATUS HcdClearEndpointHalt(uint32_t PipeHandle)// FIXME not implemented
\r
101 return HCD_STATUS_OK;
\r
104 uint32_t HcdGetFrameNumber(uint8_t HostID)
\r
106 return USB_REG(HostID)->FRINDEX_H;
\r
109 HCD_STATUS HcdGetDeviceSpeed(uint8_t HostID, HCD_USB_SPEED *DeviceSpeed)
\r
111 if ( USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_CurrentConnectStatus) {/* If device is connected */
\r
112 *DeviceSpeed = (HCD_USB_SPEED) ( (USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_PortSpeed) >> 26 ); /* TODO magic number */
\r
113 return HCD_STATUS_OK;
\r
116 return HCD_STATUS_DEVICE_DISCONNECTED;
\r
120 HCD_STATUS HcdOpenPipe(uint8_t HostID,
\r
121 uint8_t DeviceAddr,
\r
122 HCD_USB_SPEED DeviceSpeed,
\r
123 uint8_t EndpointNumber,
\r
124 HCD_TRANSFER_TYPE TransferType,
\r
125 HCD_TRANSFER_DIR TransferDir,
\r
126 uint16_t MaxPacketSize,
\r
129 uint8_t HSHubDevAddr,
\r
130 uint8_t HSHubPortNum,
\r
131 uint32_t *const pPipeHandle)
\r
135 #if !ISO_LIST_ENABLE
\r
136 if ( TransferType == ISOCHRONOUS_TRANSFER ) {
\r
137 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set ISO_LIST_ENABLE to YES");
\r
141 #if !INTERRUPT_LIST_ENABLE
\r
142 if ( TransferType == INTERRUPT_TRANSFER ) {
\r
143 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED, "Please set INTERRUPT_LIST_ENABLE to YES");
\r
147 /********************************* Parameters Verify *********************************/
\r
148 ASSERT_STATUS_OK(OpenPipe_VerifyParameters(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType,
\r
149 TransferDir, MaxPacketSize, Interval, Mult) );
\r
151 EndpointNumber &= 0xF; /* Endpoint number is in range 0-15 */
\r
152 MaxPacketSize &= 0x3FF; /* Max Packet Size is in range 0-1024 */
\r
154 switch (TransferType) { // TODO should unify more, perharps later
\r
155 case CONTROL_TRANSFER:
\r
156 case BULK_TRANSFER:
\r
157 ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
\r
158 MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
\r
159 DisableAsyncSchedule(HostID);
\r
160 InsertLinkPointer(&HcdAsyncHead(HostID)->Horizontal, &HcdQHD(HostID, HeadIdx)->Horizontal, QHD_TYPE);
\r
161 EnableAsyncSchedule(HostID);
\r
164 case INTERRUPT_TRANSFER:
\r
165 ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
\r
166 MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
\r
167 DisablePeriodSchedule(HostID);
\r
168 InsertLinkPointer(&HcdIntHead(HostID)->Horizontal, &HcdQHD(HostID, HeadIdx)->Horizontal, QHD_TYPE);
\r
169 EnablePeriodSchedule(HostID);
\r
170 memset(&PipeStreaming[HostID], 0, sizeof(Pipe_Stream_Handle_T));
\r
173 case ISOCHRONOUS_TRANSFER:
\r
175 if (( DeviceSpeed == HIGH_SPEED) || ( TransferDir == IN_TRANSFER) ) { /* TODO currently not support HS due to lack of device for testing */
\r
176 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_TRANSFER_TYPE_NOT_SUPPORTED,
\r
177 "Highspeed ISO and ISO IN is not supported yet, due to lack of testing");
\r
180 ASSERT_STATUS_OK(AllocQhd(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType, TransferDir,
\r
181 MaxPacketSize, Interval, Mult, HSHubDevAddr, HSHubPortNum, &HeadIdx) );
\r
182 EnablePeriodSchedule(HostID);
\r
186 PipehandleCreate(pPipeHandle, HostID, TransferType, HeadIdx);
\r
187 return HCD_STATUS_OK;
\r
190 HCD_STATUS HcdClosePipe(uint32_t PipeHandle)
\r
192 uint8_t HostID, HeadIdx;
\r
193 HCD_TRANSFER_TYPE XferType;
\r
195 ASSERT_STATUS_OK(HcdCancelTransfer(PipeHandle) );
\r
196 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
\r
198 switch (XferType) {
\r
199 case CONTROL_TRANSFER:
\r
200 case BULK_TRANSFER:
\r
201 case INTERRUPT_TRANSFER:
\r
202 RemoveQueueHead(HostID, HeadIdx);
\r
203 USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_IntAsyncAdvanceDoorbell; /* DoorBell Handshake: Queue Head will only be free in AsyncAdvanceIsr */
\r
206 case ISOCHRONOUS_TRANSFER:
\r
207 FreeQhd(HostID, HeadIdx);
\r
208 DisablePeriodSchedule(HostID);
\r
211 return HCD_STATUS_OK;
\r
214 HCD_STATUS HcdCancelTransfer(uint32_t PipeHandle)
\r
216 uint8_t HostID, HeadIdx;
\r
217 HCD_TRANSFER_TYPE XferType;
\r
219 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
\r
221 DisableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);
\r
223 if (XferType == ISOCHRONOUS_TRANSFER) { /* ISOCHRONOUS_TRANSFER */
\r
225 for (i = 0; i < FRAME_LIST_SIZE; i++) { /*-- Foreach link in Period List Base --*/
\r
226 NextLinkPointer *pNextPointer = &EHCI_FRAME_LIST(HostID)[i];
\r
228 /*-- Foreach Itd/SItd in the link--*/
\r
229 while ( isValidLink(pNextPointer->Link) && pNextPointer->Type != QHD_TYPE) {
\r
230 if (pNextPointer->Type == ITD_TYPE) { /*-- Highspeed ISO --*/
\r
231 PHCD_HS_ITD pItd = (PHCD_HS_ITD) Align32(pNextPointer->Link);
\r
233 if (HeadIdx == pItd->IhdIdx) {
\r
234 /*-- remove matched ITD --*/
\r
235 pNextPointer->Link = pItd->Horizontal.Link;
\r
237 continue; /*-- skip advance pNextPointer due to TD removal --*/
\r
240 else if (pNextPointer->Type == SITD_TYPE) { /*-- Split ISO --*/
\r
241 PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);
\r
243 if (HeadIdx == pSItd->IhdIdx) {
\r
244 /*-- removed matched SITD --*/
\r
245 pNextPointer->Link = pSItd->Horizontal.Link;
\r
247 continue; /*-- skip advance pNextPointer due to TD removal --*/
\r
250 pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);
\r
254 else { /*-- Bulk / Control / Interrupt --*/
\r
255 uint32_t TdLink = HcdQHD(HostID, HeadIdx)->FirstQtd;
\r
257 /*-- Foreach Qtd in Qhd --*/ /*---------- Deactivate all queued TDs ----------*/
\r
258 while ( isValidLink(TdLink) ) {
\r
259 PHCD_QTD pQtd = (PHCD_QTD) Align32(TdLink);
\r
260 TdLink = pQtd->NextQtd;
\r
263 pQtd->IntOnComplete = 0;/* no interrupt scenario on this TD */
\r
266 HcdQHD(HostID, HeadIdx)->FirstQtd = LINK_TERMINATE;
\r
269 EnableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);
\r
270 return HCD_STATUS_OK;
\r
273 HCD_STATUS HcdControlTransfer(uint32_t PipeHandle,
\r
274 const USB_Request_Header_t *const pDeviceRequest,
\r
275 uint8_t *const buffer)
\r
277 uint8_t HostID, QhdIdx;
\r
278 HCD_TRANSFER_TYPE XferType;
\r
279 uint32_t SetupTdIdx, DataTdIdx, StatusTdIdx;
\r
281 uint32_t Datalength;
\r
283 if ((pDeviceRequest == NULL) || (buffer == NULL)) {
\r
284 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Device Request or Data Buffer is NULL");
\r
287 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &QhdIdx) );
\r
289 Datalength = pDeviceRequest->wLength;
\r
290 direction = pDeviceRequest->bmRequestType & 0x80;
\r
292 /*---------- Setup Stage ----------*/
\r
293 ASSERT_STATUS_OK(AllocQTD(HostID, &SetupTdIdx, (uint8_t *) pDeviceRequest, 8, SETUP_TRANSFER, 0, 0) ); /* Setup TD: DirectionPID=00 - DataToggle=10b (always DATA0) */
\r
295 /*---------- Data Stage ----------*/
\r
297 ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, Datalength, direction ? IN_TRANSFER : OUT_TRANSFER, 1, 0) );
\r
300 DataTdIdx = SetupTdIdx; /* Data TD is skipped */
\r
303 /*---------- Status Stage ----------*/
\r
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) */
\r
306 /* Hook TDs Together */
\r
307 HcdQTD(HostID, SetupTdIdx)->NextQtd = (uint32_t) HcdQTD(HostID, DataTdIdx);
\r
308 HcdQTD(HostID, DataTdIdx)->NextQtd = (uint32_t) HcdQTD(HostID, StatusTdIdx);
\r
310 HcdQHD(HostID, QhdIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;
\r
312 /* Hook TDs to QHD */
\r
313 HcdQHD(HostID, QhdIdx)->FirstQtd = Align32( (uint32_t) HcdQTD(HostID, SetupTdIdx) );
\r
314 HcdQHD(HostID, QhdIdx)->Overlay.NextQtd = (uint32_t) HcdQTD(HostID, SetupTdIdx);
\r
316 /* wait for semaphore compete TDs */
\r
317 ASSERT_STATUS_OK(WaitForTransferComplete(HostID, QhdIdx) );
\r
319 return HCD_STATUS_OK;
\r
322 HCD_STATUS HcdDataTransfer(uint32_t PipeHandle,
\r
323 uint8_t *const buffer,
\r
324 uint32_t const length,
\r
325 uint16_t *const pActualTransferred)
\r
327 uint8_t HostID, HeadIdx;
\r
328 HCD_TRANSFER_TYPE XferType;
\r
329 uint32_t DataTdIdx;
\r
330 uint32_t ExpectedLength;
\r
332 if ((buffer == NULL) || (length == 0)) {
\r
333 ASSERT_STATUS_OK_MESSAGE(HCD_STATUS_PARAMETER_INVALID, "Data Buffer is NULL or Transfer Length is 0");
\r
336 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
\r
338 ExpectedLength = (length != HCD_ENDPOINT_MAXPACKET_XFER_LEN) ? length : HcdQHD(HostID, HeadIdx)->MaxPackageSize;
\r
340 HcdQHD(HostID, HeadIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;
\r
342 if (XferType == ISOCHRONOUS_TRANSFER) {
\r
343 if ( HcdQHD(HostID, HeadIdx)->EndpointSpeed == HIGH_SPEED ) { /*-- Highspeed ISO --*/
\r
344 ASSERT_STATUS_OK(QueueITDs(HostID, HeadIdx, buffer, ExpectedLength) );
\r
346 else { /*-- Full/Low Speed ISO --*/
\r
347 ASSERT_STATUS_OK(QueueSITDs(HostID, HeadIdx, buffer, ExpectedLength) );
\r
350 else { /*-- Control / Bulk / Interrupt --*/
\r
351 if(XferType == BULK_TRANSFER)
\r
353 ASSERT_STATUS_OK( QueueQTDs(HostID, &DataTdIdx, buffer, ExpectedLength,
\r
354 HcdQHD(HostID,HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0) );
\r
358 ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, ExpectedLength,
\r
359 HcdQHD(HostID, HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0, 1) );
\r
361 /*---------- Hook to Queue Head ----------*/
\r
362 HcdQHD(HostID, HeadIdx)->FirstQtd = Align32( (uint32_t) HcdQTD(HostID, DataTdIdx) ); /* used as TD head to clean up TD chain when transfer done */
\r
363 HcdQHD(HostID, HeadIdx)->Overlay.NextQtd = (uint32_t) HcdQTD(HostID, DataTdIdx);
\r
366 HcdQHD(HostID, HeadIdx)->pActualTransferCount = pActualTransferred; /* TODO Actual Length get rid of this */
\r
367 if (HcdQHD(HostID, HeadIdx)->pActualTransferCount) {
\r
368 *(HcdQHD(HostID, HeadIdx)->pActualTransferCount) = ExpectedLength;
\r
371 return HCD_STATUS_OK;
\r
374 HCD_STATUS HcdGetPipeStatus(uint32_t PipeHandle)/* TODO can be implemented based on overlay */
\r
376 uint8_t HostID, HeadIdx;
\r
377 HCD_TRANSFER_TYPE XferType;
\r
379 ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );
\r
381 return (HCD_STATUS)HcdQHD(HostID, HeadIdx)->status;
\r
384 static void FreeQhd(uint8_t HostID, uint8_t QhdIdx)
\r
386 HcdQHD(HostID, QhdIdx)->status = HCD_STATUS_STRUCTURE_IS_FREE;
\r
387 HcdQHD(HostID, QhdIdx)->Horizontal.Link |= LINK_TERMINATE;
\r
388 HcdQHD(HostID, QhdIdx)->inUse = 0;
\r
391 static HCD_STATUS AllocQhd(uint8_t HostID,
\r
392 uint8_t DeviceAddr,
\r
393 HCD_USB_SPEED DeviceSpeed,
\r
394 uint8_t EndpointNumber,
\r
395 HCD_TRANSFER_TYPE TransferType,
\r
396 HCD_TRANSFER_DIR TransferDir,
\r
397 uint16_t MaxPacketSize,
\r
400 uint8_t HSHubDevAddr,
\r
401 uint8_t HSHubPortNum,
\r
404 /* Looking for a free QHD */
\r
405 for ( (*pQhdIdx) = 0; (*pQhdIdx) < HCD_MAX_QTD && HcdQHD(HostID, *pQhdIdx)->inUse; (*pQhdIdx)++) {}
\r
407 if ((*pQhdIdx) == HCD_MAX_QTD ) {
\r
408 return HCD_STATUS_NOT_ENOUGH_ENDPOINT;
\r
411 memset(HcdQHD(HostID, *pQhdIdx), 0, sizeof(HCD_QHD) );
\r
413 /* Init Data For Queue Head */
\r
414 HcdQHD(HostID, *pQhdIdx)->inUse = 1;
\r
415 HcdQHD(HostID, *pQhdIdx)->Direction = (TransferDir == IN_TRANSFER) ? 1 : 0; /* Control Endpoint should not use this parameter */
\r
416 HcdQHD(HostID, *pQhdIdx)->Interval = Interval;
\r
417 HcdQHD(HostID, *pQhdIdx)->status = HCD_STATUS_OK;
\r
418 HcdQHD(HostID, *pQhdIdx)->FirstQtd = LINK_TERMINATE;
\r
420 HcdQHD(HostID, *pQhdIdx)->Horizontal.Link = LINK_TERMINATE;
\r
421 HcdQHD(HostID, *pQhdIdx)->DeviceAddress = DeviceAddr;
\r
423 HcdQHD(HostID, *pQhdIdx)->InActiveOnNextTransaction = 0;
\r
424 HcdQHD(HostID, *pQhdIdx)->EndpointNumber = EndpointNumber;
\r
425 HcdQHD(HostID, *pQhdIdx)->EndpointSpeed = (uint32_t) DeviceSpeed;
\r
426 HcdQHD(HostID, *pQhdIdx)->DataToggleControl = (TransferType == CONTROL_TRANSFER) ? 1 : 0;
\r
427 HcdQHD(HostID, *pQhdIdx)->HeadReclamationFlag = 0;
\r
428 HcdQHD(HostID, *pQhdIdx)->MaxPackageSize = MaxPacketSize;
\r
430 *pQhdIdx)->ControlEndpointFlag = (DeviceSpeed != HIGH_SPEED && TransferType == CONTROL_TRANSFER) ? 1 : 0;
\r
431 HcdQHD(HostID, *pQhdIdx)->NakCountReload = 0; /* infinite NAK/NYET */
\r
433 /*-- Currently All interrupt endpoints will be served as 1 (micro)frame polling, thus Interval parameter is ignored --*/
\r
434 /*-- For High Speed Interval should be used to compute the uFrameSMask --*/
\r
436 *pQhdIdx)->uFrameSMask =
\r
437 (TransferType == INTERRUPT_TRANSFER) ? (DeviceSpeed == HIGH_SPEED ? 0xFF : 0x01) : 0;
\r
439 *pQhdIdx)->uFrameCMask = (DeviceSpeed != HIGH_SPEED && TransferType == INTERRUPT_TRANSFER) ? 0x1C : 0; /*-- Schedule Complete Split at uFrame2, uFrame3 and uFrame4 --*/
\r
440 HcdQHD(HostID, *pQhdIdx)->HubAddress = HSHubDevAddr;
\r
441 HcdQHD(HostID, *pQhdIdx)->PortNumber = HSHubPortNum;
\r
442 HcdQHD(HostID, *pQhdIdx)->Mult = (DeviceSpeed == HIGH_SPEED ? Mult : 1);
\r
444 HcdQHD(HostID, *pQhdIdx)->Overlay.NextQtd = LINK_TERMINATE;
\r
445 HcdQHD(HostID, *pQhdIdx)->Overlay.AlterNextQtd = LINK_TERMINATE;
\r
446 HcdQHD(HostID, *pQhdIdx)->FirstQtd = LINK_TERMINATE;
\r
449 *pQhdIdx)->Overlay.PingState_Err =
\r
450 (DeviceSpeed == HIGH_SPEED && TransferType != INTERRUPT_TRANSFER && TransferDir == OUT_TRANSFER) ? 1 : 0;
\r
452 return HCD_STATUS_OK;
\r
455 static HCD_STATUS InsertLinkPointer(NextLinkPointer *pList, NextLinkPointer *pNew, uint8_t type)
\r
457 pNew->Link = pList->Link;
\r
458 pList->Link = Align32( (uint32_t) pNew);
\r
459 pList->Type = type;
\r
460 return HCD_STATUS_OK;
\r
463 static HCD_STATUS RemoveQueueHead(uint8_t HostID, uint8_t QhdIdx)
\r
465 PHCD_QHD pQhd = IsInterruptQhd(HostID, QhdIdx) ? HcdIntHead(HostID) : HcdAsyncHead(HostID);
\r
466 /*-- Foreach Qhd in async list --*/
\r
467 while ( isValidLink(pQhd->Horizontal.Link) &&
\r
468 Align32(pQhd->Horizontal.Link) != (uint32_t) HcdQHD(HostID, QhdIdx) &&
\r
469 Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
\r
470 pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
\r
472 if ( Align32(pQhd->Horizontal.Link) != (uint32_t) HcdQHD(HostID, QhdIdx) ) {
\r
473 return HCD_STATUS_PARAMETER_INVALID;
\r
476 HcdQHD(HostID, QhdIdx)->status = (uint32_t) HCD_STATUS_TO_BE_REMOVED; /* Will be remove in AsyncAdvanceIsr - make use of IAAD */
\r
477 pQhd->Horizontal.Link = HcdQHD(HostID, QhdIdx)->Horizontal.Link;
\r
479 return HCD_STATUS_OK;
\r
482 /*---------- Queue TD Routines ----------*/
\r
483 static void FreeQtd(PHCD_QTD pQtd)
\r
485 pQtd->NextQtd |= LINK_TERMINATE;
\r
489 /** Direction, DataToggle parameter only has meaning for control transfer, for other transfer use 0 for these paras */
\r
490 static HCD_STATUS AllocQTD(uint8_t HostID,
\r
492 uint8_t *const BufferPointer,
\r
494 HCD_TRANSFER_DIR PIDCode,
\r
495 uint8_t DataToggle,
\r
498 for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_QTD && HcdQTD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
\r
500 if ((*pTdIdx) < HCD_MAX_QTD) {
\r
502 uint32_t BytesInPage;
\r
504 memset(HcdQTD(HostID, *pTdIdx), 0, sizeof(HCD_QTD));
\r
506 HcdQTD(HostID, *pTdIdx)->NextQtd = 1;
\r
508 HcdQTD(HostID, *pTdIdx)->AlterNextQtd = LINK_TERMINATE;
\r
509 HcdQTD(HostID, *pTdIdx)->inUse = 1;
\r
511 HcdQTD(HostID, *pTdIdx)->Active = 1;
\r
512 HcdQTD(HostID, *pTdIdx)->PIDCode = (PIDCode == SETUP_TRANSFER) ? 2 : (PIDCode == IN_TRANSFER ? 1 : 0);
\r
513 HcdQTD(HostID, *pTdIdx)->TotalBytesToTransfer = xferLen;
\r
514 HcdQTD(HostID, *pTdIdx)->DataToggle = DataToggle;
\r
515 HcdQTD(HostID, *pTdIdx)->IntOnComplete = IOC;
\r
517 HcdQTD(HostID, *pTdIdx)->BufferPointer[0] = (uint32_t) BufferPointer;
\r
518 BytesInPage = 0x1000 - Offset4k((uint32_t) BufferPointer);
\r
519 xferLen -= MIN(xferLen, BytesInPage); /*-- Trim down xferlen to be multiple of 4k --*/
\r
521 for (idx = 1; idx <= 4 && xferLen > 0; idx++) {
\r
523 *pTdIdx)->BufferPointer[idx] = Align4k(HcdQTD(HostID, (*pTdIdx))->BufferPointer[idx - 1]) + 0x1000;
\r
524 xferLen -= MIN(xferLen, 0x1000);
\r
526 return HCD_STATUS_OK;
\r
529 return HCD_STATUS_NOT_ENOUGH_QTD;
\r
533 static HCD_STATUS QueueQTDs (uint8_t HostID,
\r
537 HCD_TRANSFER_DIR PIDCode,
\r
538 uint8_t DataToggle)
\r
540 uint32_t TailTdIdx=0xFFFFFFFF;
\r
542 while (xferLen > 0)
\r
545 uint32_t MaxTDLen = QTD_MAX_XFER_LENGTH - Offset4k((uint32_t)dataBuff);
\r
547 if(PipeStreaming[HostID].PacketSize > 0)
\r
548 TdLen = MIN(xferLen, PipeStreaming[HostID].PacketSize);
\r
550 TdLen = MIN(xferLen, MaxTDLen);
\r
553 if (TailTdIdx == 0xFFFFFFFF)
\r
555 ASSERT_STATUS_OK ( AllocQTD(HostID, pTdIdx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0) );
\r
556 TailTdIdx = *pTdIdx;
\r
561 if(HCD_STATUS_OK == AllocQTD(HostID, &NewTdIDx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0))
\r
563 HcdQTD(HostID,TailTdIdx)->NextQtd = Align32((uint32_t) HcdQTD(HostID,NewTdIDx));
\r
564 TailTdIdx = NewTdIDx;
\r
568 PipeStreaming[HostID].BufferAddress = (uint32_t)dataBuff;
\r
569 PipeStreaming[HostID].RemainBytes = xferLen + TdLen;
\r
570 PipeStreaming[HostID].DataToggle = DataToggle;
\r
571 HcdQTD(HostID,HCD_MAX_QTD - 1)->IntOnComplete = 1;
\r
575 if(DataToggle == 1) DataToggle = 0;
\r
576 else DataToggle = 1;
\r
581 memset(&PipeStreaming[HostID], 0, sizeof(Pipe_Stream_Handle_T));
\r
583 return HCD_STATUS_OK;
\r
586 static void FreeHsItd(PHCD_HS_ITD pItd)
\r
588 pItd->Horizontal.Link |= LINK_TERMINATE;
\r
592 HCD_STATUS AllocHsItd(uint8_t HostID,
\r
597 uint8_t XactPerITD,
\r
598 uint8_t IntOnComplete)
\r
600 for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_HS_ITD && HcdHsITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
\r
601 if ((*pTdIdx) < HCD_MAX_HS_ITD) {
\r
603 uint8_t XactStep = 8 / XactPerITD;
\r
604 uint32_t MaxXactLen = HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;
\r
606 memset(HcdHsITD(HostID, *pTdIdx), 0, sizeof(HCD_HS_ITD));
\r
608 HcdHsITD(HostID, *pTdIdx)->inUse = 1;
\r
609 HcdHsITD(HostID, *pTdIdx)->IhdIdx = IhdIdx;
\r
611 HcdHsITD(HostID, *pTdIdx)->Horizontal.Link = LINK_TERMINATE;
\r
612 for (i = 0; TDLen > 0 && i < 8; i += XactStep) {
\r
613 uint32_t XactLen = MIN(TDLen, MaxXactLen);
\r
616 HcdHsITD(HostID, *pTdIdx)->BufferPointer[i] = Align4k( (uint32_t) dataBuff);
\r
618 HcdHsITD(HostID, *pTdIdx)->Transaction[i].Offset = ( (uint32_t) dataBuff ) & 4095;
\r
619 HcdHsITD(HostID, *pTdIdx)->Transaction[i].PageSelect = i;
\r
620 HcdHsITD(HostID, *pTdIdx)->Transaction[i].IntOnComplete = (IntOnComplete && TDLen == 0) ? 1 : 0;
\r
621 HcdHsITD(HostID, *pTdIdx)->Transaction[i].Length = XactLen;
\r
622 HcdHsITD(HostID, *pTdIdx)->Transaction[i].Active = 1;
\r
624 dataBuff += XactLen;
\r
627 HcdHsITD(HostID, *pTdIdx)->BufferPointer[0] |= (HcdQHD(HostID, IhdIdx)->EndpointNumber << 8) | HcdQHD(HostID,
\r
631 *pTdIdx)->BufferPointer[1] |=
\r
632 (HcdQHD(HostID, IhdIdx)->Direction << 1) | HcdQHD(HostID, IhdIdx)->MaxPackageSize;
\r
633 HcdHsITD(HostID, *pTdIdx)->BufferPointer[2] |= HcdQHD(HostID, IhdIdx)->Mult;
\r
635 return HCD_STATUS_OK;
\r
638 return HCD_STATUS_NOT_ENOUGH_HS_ITD;
\r
642 static HCD_STATUS QueueITDs(uint8_t HostID, uint8_t IhdIdx, uint8_t *dataBuff, uint32_t xferLen)
\r
647 #if 0 /* Maximum bandwidth (Interval = 1) regardless of Interval value */
\r
648 uint8_t XactPerITD;
\r
649 uint32_t FramePeriod;
\r
650 if (HcdQHD(IhdIdx)->Interval < 4) { /*-- Period < 8 --*/
\r
651 XactPerITD = 1 << ( 4 - HcdQHD(IhdIdx)->Interval ); /*-- Interval 1 => 8, 2 => 4, 3 => 2 --*/
\r
656 FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 ); /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/
\r
659 #define XactPerITD 8
\r
660 #define FramePeriod 1
\r
663 MaxTDLen = XactPerITD * HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;
\r
664 FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;
\r
666 if (xferLen > MaxTDLen * FRAME_LIST_SIZE) { /*-- Data length overflow the Period FRAME LIST --*/
\r
667 ASSERT_STATUS_OK_MESSAGE(
\r
668 HCD_STATUS_DATA_OVERFLOW,
\r
669 "ISO data length overflows the Period Frame List size, Please increase size by FRAMELIST_SIZE_BITS or reduce data length");
\r
672 while (xferLen > 0) {
\r
676 TDLen = MIN(xferLen, MaxTDLen);
\r
679 ASSERT_STATUS_OK(AllocHsItd(HostID, &TdIdx, IhdIdx, dataBuff, TDLen, XactPerITD, xferLen ? 0 : 1) );
\r
681 FrameIdx = (FrameIdx + FramePeriod) % FRAME_LIST_SIZE;
\r
682 /*-- Hook ITD to Period List Base --*/
\r
683 InsertLinkPointer(&EHCI_FRAME_LIST(HostID)[FrameIdx], &HcdHsITD(HostID, TdIdx)->Horizontal, ITD_TYPE);
\r
687 return HCD_STATUS_OK;
\r
690 static void FreeSItd(PHCD_SITD pSItd)
\r
692 pSItd->Horizontal.Link |= LINK_TERMINATE;
\r
696 static HCD_STATUS AllocSItd(uint8_t HostID,
\r
701 uint8_t IntOnComplete)
\r
703 #define TCount_Pos 0
\r
706 for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_SITD && HcdSITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}
\r
708 if ((*pTdIdx) < HCD_MAX_SITD) {
\r
709 uint8_t TCount = TDLen / SPLIT_MAX_LEN_UFRAME + (TDLen % SPLIT_MAX_LEN_UFRAME ? 1 : 0); /*-- Number of Split Transactions --*/
\r
711 memset(HcdSITD(HostID, *pTdIdx), 0, sizeof(HCD_SITD) );
\r
713 HcdSITD(HostID, *pTdIdx)->inUse = 1;
\r
714 HcdSITD(HostID, *pTdIdx)->IhdIdx = HeadIdx;
\r
717 HcdSITD(HostID, *pTdIdx)->Horizontal.Link = LINK_TERMINATE;
\r
719 HcdSITD(HostID, *pTdIdx)->DeviceAddress = HcdQHD(HostID, HeadIdx)->DeviceAddress;
\r
720 HcdSITD(HostID, *pTdIdx)->EndpointNumber = HcdQHD(HostID, HeadIdx)->EndpointNumber;
\r
721 HcdSITD(HostID, *pTdIdx)->HubAddress = HcdQHD(HostID, HeadIdx)->HubAddress;
\r
722 HcdSITD(HostID, *pTdIdx)->PortNumber = HcdQHD(HostID, HeadIdx)->PortNumber;
\r
723 HcdSITD(HostID, *pTdIdx)->Direction = HcdQHD(HostID, HeadIdx)->Direction;
\r
725 HcdSITD(HostID, *pTdIdx)->uFrameSMask = (1 << TCount) - 1;
\r
726 HcdSITD(HostID, *pTdIdx)->uFrameCMask = 0;
\r
728 HcdSITD(HostID, *pTdIdx)->Active = 1;
\r
729 HcdSITD(HostID, *pTdIdx)->TotalBytesToTransfer = TDLen;
\r
730 HcdSITD(HostID, *pTdIdx)->IntOnComplete = IntOnComplete;
\r
732 HcdSITD(HostID, *pTdIdx)->BufferPointer[0] = (uint32_t) dataBuff;
\r
734 HcdSITD(HostID, *pTdIdx)->BufferPointer[1] = Align4k( ((uint32_t) dataBuff) + TDLen);
\r
736 HcdSITD(HostID, *pTdIdx)->BufferPointer[1] |= TCount << TCount_Pos;
\r
737 HcdSITD(HostID, *pTdIdx)->BufferPointer[1] |= (TCount > 1 ? 1 : 0 ) << TPos_Pos;/*-- TPosition - More than 1 split --> Begin Encoding, Otherwise All Encoding --*/
\r
739 // HcdSITD(*pTdIdx)->TCount = NoSplits;
\r
740 // HcdSITD(*pTdIdx)->TPosition = (NoSplits > 1) ? 1 : 0 ; /*-- TPosition - More than 1 split --> Begin Encoding, Otherwise All Encoding --*/
\r
743 HcdSITD(HostID, *pTdIdx)->BackPointer = LINK_TERMINATE;
\r
745 return HCD_STATUS_OK;
\r
748 return HCD_STATUS_NOT_ENOUGH_SITD;
\r
752 static HCD_STATUS QueueSITDs(uint8_t HostID, uint8_t HeadIdx, uint8_t *dataBuff, uint32_t xferLen)
\r
756 #if 0 /* Maximum bandwidth (Interval = 1) regardless of Interval value */
\r
757 uint8_t XactPerITD;
\r
758 uint32_t FramePeriod;
\r
759 if (HcdQHD(IhdIdx)->Interval < 4) { /*-- Period < 8 --*/
\r
763 FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 ); /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/
\r
766 #define FramePeriod 1
\r
769 if (xferLen > HcdQHD(HostID, HeadIdx)->MaxPackageSize * FRAME_LIST_SIZE) { /*-- Data length overflow the Period FRAME LIST --*/
\r
770 ASSERT_STATUS_OK_MESSAGE(
\r
771 HCD_STATUS_DATA_OVERFLOW,
\r
772 "ISO data length overflows the Period Frame List size, Please increase size by FRAMELIST_SIZE_BITS or reduce data length");
\r
775 FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;
\r
780 TDLen = MIN(xferLen, HcdQHD(HostID, HeadIdx)->MaxPackageSize);
\r
783 ASSERT_STATUS_OK(AllocSItd(HostID, &TdIdx, HeadIdx, dataBuff, TDLen, xferLen ? 0 : 1) );
\r
785 FrameIdx = (FrameIdx + FramePeriod) % FRAME_LIST_SIZE;
\r
786 /*-- Hook SITD to Period List Base --*/
\r
787 InsertLinkPointer(&EHCI_FRAME_LIST(HostID)[FrameIdx], &HcdSITD(HostID, TdIdx)->Horizontal, SITD_TYPE);
\r
790 return HCD_STATUS_OK;
\r
793 static HCD_STATUS WaitForTransferComplete(uint8_t HostID, uint8_t EdIdx)/* TODO indentical to OHCI now */
\r
797 while ( HcdQHD(HostID, EdIdx)->status == HCD_STATUS_TRANSFER_QUEUED ) {
\r
798 /* Should have time-out but left blank intentionally for bug catcher */
\r
800 return (HCD_STATUS) HcdQHD(HostID, EdIdx)->status;
\r
802 return HCD_STATUS_OK;
\r
807 static HCD_STATUS PipehandleParse(uint32_t Pipehandle, uint8_t *pHostID, HCD_TRANSFER_TYPE *XferType, uint8_t *pIdx)
\r
809 Pipe_Handle_T *pHandle = (Pipe_Handle_T *) (&Pipehandle);
\r
811 if ((pHandle->HostId >= MAX_USB_CORE) ||
\r
812 ( pHandle->Idx >= HCD_MAX_QTD) ||
\r
813 ( HcdQHD(pHandle->HostId, pHandle->Idx)->inUse == 0) ||
\r
814 ( HcdQHD(pHandle->HostId, pHandle->Idx)->status == HCD_STATUS_TO_BE_REMOVED) ) {
\r
815 return HCD_STATUS_PIPEHANDLE_INVALID;
\r
819 *pHostID = pHandle->HostId;
\r
822 *pIdx = pHandle->Idx;
\r
825 *XferType = (HCD_TRANSFER_TYPE) pHandle->Type;
\r
828 return HCD_STATUS_OK;
\r
831 static void PipehandleCreate(uint32_t *pPipeHandle, uint8_t HostID, HCD_TRANSFER_TYPE XferType, uint8_t idx)
\r
833 /*---------- HostID | PortNum | Type | Idx ----------*/
\r
834 Pipe_Handle_T *pHandle = (Pipe_Handle_T *) pPipeHandle;
\r
836 pHandle->HostId = HostID;
\r
837 pHandle->PortNumber = 0;
\r
838 pHandle->Type = (uint8_t) XferType;
\r
839 pHandle->Idx = idx;
\r
842 static __INLINE PHCD_QHD HcdAsyncHead(uint8_t HostID)
\r
844 return &(ehci_data[HostID].AsyncHeadQhd);
\r
845 // return &(ehci_data.AsyncHeadQhd);
\r
848 static __INLINE PHCD_QHD HcdIntHead(uint8_t HostID)
\r
850 return &(ehci_data[HostID].IntHeadQhd);
\r
851 // return &(ehci_data.IntHeadQhd);
\r
854 // === TODO: Deal with HostID later ===
\r
855 static __INLINE PHCD_QHD HcdQHD(uint8_t HostID, uint8_t idx)
\r
857 return &(ehci_data[HostID].qHDs[idx]);
\r
858 // return &(ehci_data.qHDs[idx]);
\r
861 static __INLINE PHCD_QTD HcdQTD(uint8_t HostID, uint8_t idx)
\r
863 return &(ehci_data[HostID].qTDs[idx]);
\r
864 // return &(ehci_data.qTDs[idx]);
\r
867 static __INLINE PHCD_SITD HcdSITD(uint8_t HostID, uint8_t idx)
\r
869 return &(ehci_data[HostID].siTDs[idx]);
\r
870 // return &(ehci_data.siTDs[idx]);
\r
873 static __INLINE PHCD_HS_ITD HcdHsITD(uint8_t HostID, uint8_t idx)
\r
875 return &(ehci_data[HostID].iTDs[idx]);
\r
876 // return &(ehci_data.iTDs[idx]);
\r
879 static __INLINE bool isValidLink(uint32_t link)
\r
881 return (link & LINK_TERMINATE) == 0;
\r
884 static __INLINE bool IsInterruptQhd(uint8_t HostID, uint8_t QhdIdx)
\r
886 return HcdQHD(HostID, QhdIdx)->uFrameSMask;
\r
889 void HcdIrqHandler(uint8_t HostID)
\r
891 uint32_t IntStatus;
\r
892 uint32_t t = USB_REG(HostID)->USBINTR_H;
\r
893 IntStatus = USB_REG(HostID)->USBSTS_H & t;
\r
895 if (IntStatus == 0) {
\r
899 /* disable all interrupt for processing */
\r
900 /* Acknowledge Interrrupt */
\r
901 USB_REG(HostID)->USBSTS_H |= IntStatus;
\r
903 /* Process Interrupt Sources */
\r
904 if (IntStatus & EHC_USBSTS_PortChangeDetect) {
\r
905 uint32_t PortSC = USB_REG(HostID)->PORTSC1_H;
\r
906 if (PortSC & EHC_PORTSC_ConnectStatusChange) {
\r
907 PortStatusChangeIsr(HostID, PortSC & EHC_PORTSC_CurrentConnectStatus);
\r
908 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_ConnectStatusChange; /* Clear PortSC Interrupt Status */
\r
910 if (PortSC & EHC_PORTSC_PortEnableChange) {
\r
911 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortEnableChange; /* Clear PortSC Interrupt Status */
\r
913 if (PortSC & EHC_PORTSC_OvercurrentChange) {
\r
914 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_OvercurrentChange; /* Clear PortSC Interrupt Status */
\r
916 if (PortSC & EHC_PORTSC_ForcePortResume) {
\r
917 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_ForcePortResume; /* Clear PortSC Interrupt Status */
\r
921 if (IntStatus & EHC_USBSTS_UsbAsyncInt) {
\r
922 AsyncScheduleIsr(HostID);
\r
925 if (IntStatus & EHC_USBSTS_UsbPeriodInt) {
\r
926 PeriodScheduleIsr(HostID);
\r
929 if (IntStatus & EHC_USBSTS_UsbErrorInt) {
\r
930 UsbErrorIsr(HostID);
\r
933 if (IntStatus & EHC_USBSTS_IntAsyncAdvance) {
\r
934 AsyncAdvanceIsr(HostID);
\r
936 /* Enable Interrupt */
\r
939 static void RemoveCompletedQTD(uint8_t HostID, PHCD_QHD pQhd)
\r
942 uint32_t TdLink = pQhd->FirstQtd;
\r
943 bool is_data_remain = false;
\r
945 /*-- Foreach Qtd in Qhd --*/
\r
946 while( (isValidLink(TdLink), pQtd = (PHCD_QTD) Align32(TdLink) ) &&
\r
949 TdLink = pQtd->NextQtd;
\r
951 if(pQhd->pActualTransferCount)
\r
952 *(pQhd->pActualTransferCount) -= pQtd->TotalBytesToTransfer;
\r
954 if (pQtd->IntOnComplete)
\r
956 if(PipeStreaming[HostID].RemainBytes > 0)
\r
957 is_data_remain = true;
\r
959 pQhd->status = HCD_STATUS_OK;
\r
961 if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/)
\r
963 pQhd->status = HCD_STATUS_TRANSFER_Stall;
\r
967 pQhd->FirstQtd = TdLink;
\r
971 QueueQTDs(HostID, &pQtd,(uint8_t*)PipeStreaming[HostID].BufferAddress,
\r
972 PipeStreaming[HostID].RemainBytes,
\r
973 pQhd->Direction ? IN_TRANSFER : OUT_TRANSFER,
\r
974 PipeStreaming[HostID].DataToggle);
\r
975 pQhd->FirstQtd = Align32( (uint32_t) HcdQTD(HostID,pQtd) );
\r
976 pQhd->Overlay.NextQtd = (uint32_t) HcdQTD(HostID,pQtd);
\r
980 static void RemoveErrorQTD(PHCD_QHD pQhd)
\r
983 uint32_t TdLink = pQhd->FirstQtd;
\r
984 bool errorfound = false;
\r
986 /*-- Scan error Qtd in Qhd --*/
\r
987 while ( (isValidLink(TdLink), pQtd = (PHCD_QTD) Align32(TdLink) ) &&
\r
988 pQtd->Active == 0) {
\r
989 TdLink = pQtd->NextQtd;
\r
991 if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/) {
\r
993 pQhd->status = HCD_STATUS_TRANSFER_Stall;
\r
996 /*-- Remove error Qtd in Qhd --*/
\r
998 TdLink = pQhd->FirstQtd;
\r
999 while (isValidLink(TdLink)) {
\r
1000 pQtd = (PHCD_QTD) Align32(TdLink);
\r
1001 TdLink = pQtd->NextQtd;
\r
1003 pQtd->IntOnComplete = 0;
\r
1006 pQhd->FirstQtd = LINK_TERMINATE;
\r
1007 pQhd->Overlay.Halted = 0;
\r
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) ----------*/
\r
1012 static void AsyncScheduleIsr(uint8_t HostID)
\r
1014 PHCD_QHD pQhd = HcdAsyncHead(HostID);
\r
1016 /*-- Foreach Qhd in async list --*/
\r
1017 while ( isValidLink(pQhd->Horizontal.Link) &&
\r
1018 Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
\r
1019 pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
\r
1020 RemoveCompletedQTD(HostID,pQhd);
\r
1024 static void PeriodScheduleIsr(uint8_t HostID)
\r
1029 for (i = 0; i < FRAME_LIST_SIZE; i++) { /*-- Foreach link in Period List Base --*/
\r
1030 NextLinkPointer *pNextPointer = &EHCI_FRAME_LIST(HostID)[i];
\r
1032 /*-- Foreach Itd/SItd in the link--*/
\r
1033 while ( isValidLink(pNextPointer->Link) && pNextPointer->Type != QHD_TYPE ) {
\r
1034 if (pNextPointer->Type == ITD_TYPE) { /*-- Highspeed ISO --*/
\r
1035 PHCD_HS_ITD pItd = (PHCD_HS_ITD) Align32(pNextPointer->Link);
\r
1037 if ((pItd->Transaction[0].Active == 0) && (pItd->Transaction[1].Active == 0) &&
\r
1038 ( pItd->Transaction[2].Active == 0) && ( pItd->Transaction[3].Active == 0) &&
\r
1039 ( pItd->Transaction[4].Active == 0) && ( pItd->Transaction[5].Active == 0) &&
\r
1040 ( pItd->Transaction[6].Active == 0) && ( pItd->Transaction[7].Active == 0) ) {
\r
1041 if ((pItd->Transaction[0].IntOnComplete == 1) || (pItd->Transaction[1].IntOnComplete == 1) ||
\r
1042 ( pItd->Transaction[2].IntOnComplete == 1) || ( pItd->Transaction[3].IntOnComplete == 1) ||
\r
1043 ( pItd->Transaction[4].IntOnComplete == 1) || ( pItd->Transaction[5].IntOnComplete == 1) ||
\r
1044 ( pItd->Transaction[6].IntOnComplete == 1) || ( pItd->Transaction[7].IntOnComplete == 1) ) {
\r
1045 /*-- request complete, signal on Iso Head --*/
\r
1046 HcdQHD(HostID, pItd->IhdIdx)->status = HCD_STATUS_OK;
\r
1048 /*-- remove executed ITD --*/
\r
1049 pNextPointer->Link = pItd->Horizontal.Link;
\r
1051 continue; /*-- skip advance pNextPointer due to TD removal --*/
\r
1054 else if (pNextPointer->Type == SITD_TYPE) { /*-- Split ISO --*/
\r
1055 PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);
\r
1057 if (pSItd->Active == 0) {
\r
1058 if (pSItd->IntOnComplete) {
\r
1059 /*-- request complete, signal on Iso Head --*/
\r
1060 HcdQHD(HostID, pSItd->IhdIdx)->status = HCD_STATUS_OK;
\r
1063 /*-- removed executed SITD --*/
\r
1064 pNextPointer->Link = pSItd->Horizontal.Link;
\r
1066 continue; /*-- skip advance pNextPointer due to TD removal --*/
\r
1070 pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);
\r
1076 PHCD_QHD pQhd = HcdIntHead(HostID);
\r
1078 /*-- Foreach Qhd in list --*/
\r
1079 while ( isValidLink(pQhd->Horizontal.Link) ) {
\r
1080 pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
\r
1081 RemoveCompletedQTD(HostID,pQhd);
\r
1086 static void UsbErrorIsr(uint8_t HostID)
\r
1088 PHCD_QHD pQhd = HcdAsyncHead(HostID);
\r
1090 /*-- Foreach Qhd in async list --*/
\r
1091 while ( isValidLink(pQhd->Horizontal.Link) &&
\r
1092 Align32(pQhd->Horizontal.Link) != (uint32_t) HcdAsyncHead(HostID) ) {
\r
1093 pQhd = (PHCD_QHD) Align32(pQhd->Horizontal.Link);
\r
1094 RemoveErrorQTD(pQhd);
\r
1098 static HCD_STATUS PortStatusChangeIsr(uint8_t HostID, uint32_t deviceConnect)
\r
1100 if (deviceConnect) {/* Device Attached */
\r
1101 USB_Host_Enumerate(HostID);
\r
1103 else { /* Device detached */
\r
1104 USB_Host_DeEnumerate(HostID);
\r
1106 return HCD_STATUS_OK;
\r
1109 static void AsyncAdvanceIsr(uint8_t HostID)
\r
1113 for (QhdIdx = 0; QhdIdx < HCD_MAX_QHD; QhdIdx++)
\r
1114 if ((HcdQHD(HostID, QhdIdx)->inUse == 1) && (HcdQHD(HostID, QhdIdx)->status == HCD_STATUS_TO_BE_REMOVED)) {
\r
1115 FreeQhd(HostID, QhdIdx);
\r
1119 static __INLINE HCD_STATUS EHciHostRun(uint8_t HostID)
\r
1121 USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_RunStop;
\r
1122 while (USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) {}
\r
1123 return HCD_STATUS_OK;
\r
1126 static __INLINE HCD_STATUS EHciHostStop(uint8_t HostID)
\r
1128 USB_REG(HostID)->USBCMD_H &= ~EHC_USBCMD_RunStop;
\r
1129 while ( !(USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) ) {}
\r
1130 return HCD_STATUS_OK;
\r
1133 static __INLINE HCD_STATUS EHciHostReset(uint8_t HostID)
\r
1135 if (USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) {
\r
1136 EHciHostStop(HostID);
\r
1139 USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_HostReset;
\r
1140 while ( USB_REG(HostID)->USBCMD_H & EHC_USBCMD_HostReset ) {}
\r
1142 /* Program the controller to be the USB host controller, this can only be done after Reset */
\r
1143 USB_REG(HostID)->USBMODE_H = 0x23; // USBMODE_HostController | USBMODE_VBusPowerSelect_High;
\r
1144 return HCD_STATUS_OK;
\r
1147 static __INLINE HCD_STATUS EHciHostInit(uint8_t HostID)
\r
1151 /*---------- Host Data Structure Init ----------*/
\r
1152 // memset(&ehci_data[HostID], 0, sizeof(EHCI_HOST_DATA_T) );
\r
1154 /*---------- USBINT ----------*/
\r
1155 USB_REG(HostID)->USBINTR_H &= ~EHC_USBINTR_ALL; /* Disable All Interrupt */
\r
1156 USB_REG(HostID)->USBSTS_H &= ~EHC_USBINTR_ALL; /* Clear All Interrupt Status */
\r
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 */
\r
1158 EHC_USBINTR_PortChangeIntEnable | EHC_USBINTR_UsbErroIntEnable |
\r
1159 EHC_USBINTR_IntAsyncAdvanceEnable |
\r
1160 (INT_FRAME_ROLL_OVER_ENABLE ? EHC_USBINTR_FrameListRolloverEnable : 0);
\r
1162 /*---------- Asynchronous List ----------*/
\r
1163 /*-- Static Head Qhd with Halted/inactive --*/
\r
1164 HcdAsyncHead(HostID)->Horizontal.Link = Align32( (uint32_t) HcdAsyncHead(HostID) );
\r
1165 HcdAsyncHead(HostID)->Horizontal.Type = QHD_TYPE;
\r
1166 HcdAsyncHead(HostID)->HeadReclamationFlag = 1;
\r
1167 HcdAsyncHead(HostID)->Overlay.NextQtd = LINK_TERMINATE; /* Terminate Links */
\r
1168 HcdAsyncHead(HostID)->Overlay.AlterNextQtd = LINK_TERMINATE; /* Terminate Links */
\r
1169 HcdAsyncHead(HostID)->Overlay.Halted = 1;
\r
1171 USB_REG(HostID)->ASYNCLISTADDR = (uint32_t) HcdAsyncHead(HostID);
\r
1173 /*---------- Periodic List ----------*/
\r
1174 /*-- Static Interrupt Qhd (1 ms) --*/
\r
1175 HcdIntHead(HostID)->Horizontal.Link = LINK_TERMINATE;
\r
1176 HcdIntHead(HostID)->Overlay.NextQtd = LINK_TERMINATE; /* Terminate Links */
\r
1177 HcdIntHead(HostID)->Overlay.AlterNextQtd = LINK_TERMINATE; /* Terminate Links */
\r
1178 HcdIntHead(HostID)->Overlay.Halted = 1;
\r
1179 HcdIntHead(HostID)->uFrameSMask = 1;
\r
1181 for (idx = 0; idx < FRAME_LIST_SIZE; idx++) { /* Attach 1 ms Interrupt Qhd to Period Frame List */
\r
1182 EHCI_FRAME_LIST(HostID)[idx].Link = Align32( (uint32_t) HcdIntHead(HostID) );
\r
1183 EHCI_FRAME_LIST(HostID)[idx].Type = QHD_TYPE;
\r
1186 USB_REG(HostID)->PERIODICLISTBASE = Align4k( (uint32_t) EHCI_FRAME_LIST(HostID) );
\r
1188 /*---------- USBCMD ----------*/
\r
1189 USB_REG(HostID)->USBCMD_H = EHC_USBCMD_AsynScheduleEnable |
\r
1190 ((FRAMELIST_SIZE_BITS % 4) << 2) | ((FRAMELIST_SIZE_BITS / 4) << 15);
\r
1192 /*---------- CONFIGFLAG ----------*/
\r
1193 /* LPC18xx doesn't has CONFIGFLAG register */
\r
1195 /*---------- Power On RhPort ----------*/
\r
1196 USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortPowerControl;
\r
1198 EHciHostRun(HostID);/* Run The HC */
\r
1200 return HCD_STATUS_OK;
\r
1203 static __INLINE void DisableSchedule(uint8_t HostID, uint8_t isPeriod)
\r
1205 uint32_t statusMask = isPeriod ? EHC_USBSTS_PeriodScheduleStatus : EHC_USBSTS_AsyncScheduleStatus;
\r
1206 uint32_t cmdMask = isPeriod ? EHC_USBCMD_PeriodScheduleEnable : EHC_USBCMD_AsynScheduleEnable;
\r
1208 if (USB_REG(HostID)->USBSTS_H & statusMask) {
\r
1209 USB_REG(HostID)->USBCMD_H &= ~cmdMask;
\r
1210 while (USB_REG(HostID)->USBSTS_H & statusMask) {} /* TODO Should have time-out */
\r
1214 static __INLINE void EnableSchedule(uint8_t HostID, uint8_t isPeriod)
\r
1216 uint32_t statusMask = isPeriod ? EHC_USBSTS_PeriodScheduleStatus : EHC_USBSTS_AsyncScheduleStatus;
\r
1217 uint32_t cmdMask = isPeriod ? EHC_USBCMD_PeriodScheduleEnable : EHC_USBCMD_AsynScheduleEnable;
\r
1219 if (!(USB_REG(HostID)->USBSTS_H & statusMask)) {
\r
1220 USB_REG(HostID)->USBCMD_H |= cmdMask;
\r
1221 while (!(USB_REG(HostID)->USBSTS_H & statusMask)) {}/* TODO Should have time-out */
\r
1225 static void DisableAsyncSchedule(uint8_t HostID)
\r
1227 DisableSchedule(HostID, 0);
\r
1230 static void EnableAsyncSchedule(uint8_t HostID)
\r
1232 EnableSchedule(HostID, 0);
\r
1235 static void DisablePeriodSchedule(uint8_t HostID)
\r
1237 DisableSchedule(HostID, 1);
\r
1240 static void EnablePeriodSchedule(uint8_t HostID)
\r
1242 EnableSchedule(HostID, 1);
\r
1245 void HcdSetStreamPacketSize(uint32_t PipeHandle, uint16_t packetsize)
\r
1247 uint8_t HostID = 0, HeadIdx;
\r
1248 HCD_TRANSFER_TYPE XferType;
\r
1250 PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx);
\r
1252 PipeStreaming[HostID].PacketSize = packetsize;
\r
1255 #endif // __LPC_EHCI__
\r