]> git.sur5r.net Git - freertos/blob
255e4ac920d352bd02bf97a22d04030c7a424556
[freertos] /
1 /*\r
2  * @brief Enhanced Host Controller Interface\r
3  *\r
4  * @note\r
5  * Copyright(C) NXP Semiconductors, 2012\r
6  * All rights reserved.\r
7  *\r
8  * @par\r
9  * Software that is described herein is for illustrative purposes only\r
10  * which provides customers with programming information regarding the\r
11  * LPC products.  This software is supplied "AS IS" without any warranties of\r
12  * any kind, and NXP Semiconductors and its licensor disclaim any and\r
13  * all warranties, express or implied, including all implied warranties of\r
14  * merchantability, fitness for a particular purpose and non-infringement of\r
15  * intellectual property rights.  NXP Semiconductors assumes no responsibility\r
16  * or liability for the use of the software, conveys no license or rights under any\r
17  * patent, copyright, mask work right, or any other intellectual property rights in\r
18  * or to any products. NXP Semiconductors reserves the right to make changes\r
19  * in the software without notification. NXP Semiconductors also makes no\r
20  * representation or warranty that such application will be suitable for the\r
21  * specified use without further testing or modification.\r
22  *\r
23  * @par\r
24  * Permission to use, copy, modify, and distribute this software and its\r
25  * documentation is hereby granted, under NXP Semiconductors' and its\r
26  * licensor's relevant copyrights in the software, without fee, provided that it\r
27  * is used in conjunction with NXP Semiconductors microcontrollers.  This\r
28  * copyright, permission, and disclaimer notice must appear in all copies of\r
29  * this code.\r
30  */\r
31 \r
32 /*=======================================================================*/\r
33 /*        I N C L U D E S                                                */\r
34 /*=======================================================================*/\r
35 #define  __INCLUDE_FROM_USB_DRIVER\r
36 #include "../../USBMode.h"\r
37 \r
38 #if (defined(USB_CAN_BE_HOST) && defined(__LPC_EHCI__))\r
39 \r
40 #define __LPC_EHCI_C__\r
41 #include "../../../../../Common/Common.h"\r
42 #include "../../USBTask.h"\r
43 #include "../HCD.h"\r
44 #include "EHCI.h"\r
45 \r
46 // === TODO: Unify USBRAM Section ===\r
47 PRAGMA_ALIGN_32\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
50 PRAGMA_ALIGN_4096\r
51 NextLinkPointer PeriodFrameList0[FRAME_LIST_SIZE] ATTR_ALIGNED(4096) __BSS(USBRAM_SECTION);             /* Period Frame List */\r
52 PRAGMA_ALIGN_4096\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
59 {\r
60         EHciHostReset(HostID);\r
61         return EHciHostInit(HostID);\r
62 }\r
63 \r
64 HCD_STATUS HcdDeInitDriver(uint8_t HostID)\r
65 {\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
69 \r
70         return HCD_STATUS_OK;\r
71 }\r
72 \r
73 HCD_STATUS HcdRhPortEnable(uint8_t HostID)\r
74 {\r
75         return HCD_STATUS_OK;\r
76 }\r
77 \r
78 HCD_STATUS HcdRhPortDisable(uint8_t HostID)\r
79 {\r
80         return HCD_STATUS_OK;\r
81 }\r
82 \r
83 HCD_STATUS HcdRhPortReset(uint8_t HostID)\r
84 {\r
85         HcdDelayMS(PORT_RESET_PERIOD_MS);\r
86 \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
89 \r
90         /* should have time-out */\r
91         while (USB_REG(HostID)->PORTSC1_H & EHC_PORTSC_PortReset) {}\r
92 \r
93         /* PortEnable is always set - Deviation from EHCI */\r
94 \r
95         HcdDelayMS(PORT_RESET_PERIOD_MS);\r
96         return HCD_STATUS_OK;\r
97 }\r
98 \r
99 HCD_STATUS HcdClearEndpointHalt(uint32_t PipeHandle)// FIXME not implemented\r
100 {\r
101         return HCD_STATUS_OK;\r
102 }\r
103 \r
104 uint32_t   HcdGetFrameNumber(uint8_t HostID)\r
105 {\r
106         return USB_REG(HostID)->FRINDEX_H;\r
107 }\r
108 \r
109 HCD_STATUS HcdGetDeviceSpeed(uint8_t HostID, HCD_USB_SPEED *DeviceSpeed)\r
110 {\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
114         }\r
115         else {\r
116                 return HCD_STATUS_DEVICE_DISCONNECTED;\r
117         }\r
118 }\r
119 \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
127                                            uint8_t Interval,\r
128                                            uint8_t Mult,\r
129                                            uint8_t HSHubDevAddr,\r
130                                            uint8_t HSHubPortNum,\r
131                                            uint32_t *const pPipeHandle)\r
132 {\r
133         uint32_t HeadIdx;\r
134 \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
138         }\r
139 #endif\r
140 \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
144         }\r
145 #endif\r
146 \r
147         /********************************* Parameters Verify *********************************/\r
148         ASSERT_STATUS_OK(OpenPipe_VerifyParameters(HostID, DeviceAddr, DeviceSpeed, EndpointNumber, TransferType,\r
149                                                                                            TransferDir, MaxPacketSize, Interval, Mult) );\r
150 \r
151         EndpointNumber &= 0xF;  /* Endpoint number is in range 0-15 */\r
152         MaxPacketSize &= 0x3FF; /* Max Packet Size is in range 0-1024 */\r
153 \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
162                 break;\r
163 \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
171                 break;\r
172 \r
173         case ISOCHRONOUS_TRANSFER:\r
174 #ifndef __TEST__\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
178                 }\r
179 #endif\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
183                 break;\r
184         }\r
185 \r
186         PipehandleCreate(pPipeHandle, HostID, TransferType, HeadIdx);\r
187         return HCD_STATUS_OK;\r
188 }\r
189 \r
190 HCD_STATUS HcdClosePipe(uint32_t PipeHandle)\r
191 {\r
192         uint8_t HostID, HeadIdx;\r
193         HCD_TRANSFER_TYPE XferType;\r
194 \r
195         ASSERT_STATUS_OK(HcdCancelTransfer(PipeHandle) );\r
196         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );\r
197 \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
204                 break;\r
205 \r
206         case ISOCHRONOUS_TRANSFER:\r
207                 FreeQhd(HostID, HeadIdx);\r
208                 DisablePeriodSchedule(HostID);\r
209                 break;\r
210         }\r
211         return HCD_STATUS_OK;\r
212 }\r
213 \r
214 HCD_STATUS HcdCancelTransfer(uint32_t PipeHandle)\r
215 {\r
216         uint8_t HostID, HeadIdx;\r
217         HCD_TRANSFER_TYPE XferType;\r
218 \r
219         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );\r
220 \r
221         DisableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);\r
222 \r
223         if (XferType == ISOCHRONOUS_TRANSFER) { /* ISOCHRONOUS_TRANSFER */\r
224                 uint32_t i;\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
227 \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
232 \r
233                                         if (HeadIdx == pItd->IhdIdx) {\r
234                                                 /*-- remove matched ITD --*/\r
235                                                 pNextPointer->Link = pItd->Horizontal.Link;\r
236                                                 FreeHsItd(pItd);\r
237                                                 continue;       /*-- skip advance pNextPointer due to TD removal --*/\r
238                                         }\r
239                                 }\r
240                                 else if (pNextPointer->Type == SITD_TYPE) {     /*-- Split ISO --*/\r
241                                         PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);\r
242 \r
243                                         if (HeadIdx == pSItd->IhdIdx) {\r
244                                                 /*-- removed matched SITD --*/\r
245                                                 pNextPointer->Link = pSItd->Horizontal.Link;\r
246                                                 FreeSItd(pSItd);\r
247                                                 continue;       /*-- skip advance pNextPointer due to TD removal --*/\r
248                                         }\r
249                                 }\r
250                                 pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);\r
251                         }\r
252                 }\r
253         }\r
254         else {  /*-- Bulk / Control / Interrupt --*/\r
255                 uint32_t TdLink = HcdQHD(HostID, HeadIdx)->FirstQtd;\r
256 \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
261 \r
262                         pQtd->Active = 0;\r
263                         pQtd->IntOnComplete = 0;/* no interrupt scenario on this TD */\r
264                         FreeQtd(pQtd);\r
265                 }\r
266                 HcdQHD(HostID, HeadIdx)->FirstQtd = LINK_TERMINATE;\r
267         }\r
268 \r
269         EnableSchedule(HostID, (XferType == INTERRUPT_TRANSFER) || (XferType == ISOCHRONOUS_TRANSFER) ? 1 : 0);\r
270         return HCD_STATUS_OK;\r
271 }\r
272 \r
273 HCD_STATUS HcdControlTransfer(uint32_t PipeHandle,\r
274                                                           const USB_Request_Header_t *const pDeviceRequest,\r
275                                                           uint8_t *const buffer)\r
276 {\r
277         uint8_t HostID, QhdIdx;\r
278         HCD_TRANSFER_TYPE XferType;\r
279         uint32_t SetupTdIdx, DataTdIdx, StatusTdIdx;\r
280         uint8_t direction;\r
281         uint32_t Datalength;\r
282 \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
285         }\r
286 \r
287         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &QhdIdx) );\r
288 \r
289         Datalength = pDeviceRequest->wLength;\r
290         direction =  pDeviceRequest->bmRequestType & 0x80;\r
291 \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
294 \r
295         /*---------- Data Stage ----------*/\r
296         if (Datalength) {\r
297                 ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, Datalength, direction ? IN_TRANSFER : OUT_TRANSFER, 1, 0) );\r
298         }\r
299         else {\r
300                 DataTdIdx = SetupTdIdx; /* Data TD is skipped */\r
301         }\r
302 \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
305 \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
309 \r
310         HcdQHD(HostID, QhdIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;\r
311 \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
315 \r
316         /* wait for semaphore compete TDs */\r
317         ASSERT_STATUS_OK(WaitForTransferComplete(HostID, QhdIdx) );\r
318 \r
319         return HCD_STATUS_OK;\r
320 }\r
321 \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
326 {\r
327         uint8_t HostID, HeadIdx;\r
328         HCD_TRANSFER_TYPE XferType;\r
329         uint32_t DataTdIdx;\r
330         uint32_t ExpectedLength;\r
331 \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
334         }\r
335 \r
336         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );\r
337 \r
338         ExpectedLength = (length != HCD_ENDPOINT_MAXPACKET_XFER_LEN) ? length : HcdQHD(HostID, HeadIdx)->MaxPackageSize;\r
339 \r
340         HcdQHD(HostID, HeadIdx)->status = (uint32_t) HCD_STATUS_TRANSFER_QUEUED;\r
341 \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
345                 }\r
346                 else {  /*-- Full/Low Speed ISO --*/\r
347                         ASSERT_STATUS_OK(QueueSITDs(HostID, HeadIdx, buffer, ExpectedLength) );\r
348                 }\r
349         }\r
350         else {  /*-- Control / Bulk / Interrupt --*/\r
351                 if(XferType == BULK_TRANSFER)\r
352                 {\r
353                         ASSERT_STATUS_OK( QueueQTDs(HostID, &DataTdIdx, buffer, ExpectedLength,\r
354                                                                         HcdQHD(HostID,HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0) );\r
355                 }\r
356                 else\r
357                 {\r
358                         ASSERT_STATUS_OK(AllocQTD(HostID, &DataTdIdx, buffer, ExpectedLength,\r
359                                                                   HcdQHD(HostID, HeadIdx)->Direction ? IN_TRANSFER : OUT_TRANSFER, 0, 1) );\r
360                 }\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
364         }\r
365 \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
369         }\r
370 \r
371         return HCD_STATUS_OK;\r
372 }\r
373 \r
374 HCD_STATUS HcdGetPipeStatus(uint32_t PipeHandle)/* TODO can be implemented based on overlay */\r
375 {\r
376         uint8_t HostID, HeadIdx;\r
377         HCD_TRANSFER_TYPE XferType;\r
378 \r
379         ASSERT_STATUS_OK(PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx) );\r
380 \r
381         return (HCD_STATUS)HcdQHD(HostID, HeadIdx)->status;\r
382 }\r
383 \r
384 static void FreeQhd(uint8_t HostID, uint8_t QhdIdx)\r
385 {\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
389 }\r
390 \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
398                                                    uint8_t Interval,\r
399                                                    uint8_t Mult,\r
400                                                    uint8_t HSHubDevAddr,\r
401                                                    uint8_t HSHubPortNum,\r
402                                                    uint32_t *pQhdIdx)\r
403 {\r
404         /* Looking for a free QHD */\r
405         for ( (*pQhdIdx) = 0; (*pQhdIdx) < HCD_MAX_QTD && HcdQHD(HostID, *pQhdIdx)->inUse; (*pQhdIdx)++) {}\r
406 \r
407         if ((*pQhdIdx) == HCD_MAX_QTD ) {\r
408                 return HCD_STATUS_NOT_ENOUGH_ENDPOINT;\r
409         }\r
410 \r
411         memset(HcdQHD(HostID, *pQhdIdx), 0, sizeof(HCD_QHD) );\r
412 \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
419 \r
420         HcdQHD(HostID, *pQhdIdx)->Horizontal.Link = LINK_TERMINATE;\r
421         HcdQHD(HostID, *pQhdIdx)->DeviceAddress = DeviceAddr;\r
422 \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
429         HcdQHD(HostID,\r
430                    *pQhdIdx)->ControlEndpointFlag = (DeviceSpeed != HIGH_SPEED && TransferType == CONTROL_TRANSFER) ? 1 : 0;\r
431         HcdQHD(HostID, *pQhdIdx)->NakCountReload = 0;   /* infinite NAK/NYET */\r
432 \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
435         HcdQHD(HostID,\r
436                    *pQhdIdx)->uFrameSMask =\r
437                 (TransferType == INTERRUPT_TRANSFER) ? (DeviceSpeed == HIGH_SPEED ? 0xFF : 0x01) : 0;\r
438         HcdQHD(HostID,\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
443 \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
447 \r
448         HcdQHD(HostID,\r
449                    *pQhdIdx)->Overlay.PingState_Err =\r
450                 (DeviceSpeed == HIGH_SPEED && TransferType != INTERRUPT_TRANSFER && TransferDir == OUT_TRANSFER) ? 1 : 0;\r
451 \r
452         return HCD_STATUS_OK;\r
453 }\r
454 \r
455 static HCD_STATUS InsertLinkPointer(NextLinkPointer *pList, NextLinkPointer *pNew, uint8_t type)\r
456 {\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
461 }\r
462 \r
463 static HCD_STATUS RemoveQueueHead(uint8_t HostID, uint8_t QhdIdx)\r
464 {\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
471         }\r
472         if (  Align32(pQhd->Horizontal.Link) != (uint32_t) HcdQHD(HostID, QhdIdx) ) {\r
473                 return HCD_STATUS_PARAMETER_INVALID;\r
474         }\r
475 \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
478 \r
479         return HCD_STATUS_OK;\r
480 }\r
481 \r
482 /*---------- Queue TD Routines ----------*/\r
483 static void FreeQtd(PHCD_QTD pQtd)\r
484 {\r
485         pQtd->NextQtd |= LINK_TERMINATE;\r
486         pQtd->inUse = 0;\r
487 }\r
488 \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
491                                                    uint32_t *pTdIdx,\r
492                                                    uint8_t *const BufferPointer,\r
493                                                    uint32_t xferLen,\r
494                                                    HCD_TRANSFER_DIR PIDCode,\r
495                                                    uint8_t DataToggle,\r
496                                                    uint8_t IOC)\r
497 {\r
498         for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_QTD && HcdQTD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}\r
499 \r
500         if ((*pTdIdx) < HCD_MAX_QTD) {\r
501                 uint8_t idx = 1;\r
502                 uint32_t BytesInPage;\r
503 \r
504                 memset(HcdQTD(HostID, *pTdIdx), 0, sizeof(HCD_QTD));\r
505 \r
506                 HcdQTD(HostID, *pTdIdx)->NextQtd = 1;\r
507 \r
508                 HcdQTD(HostID, *pTdIdx)->AlterNextQtd = LINK_TERMINATE;\r
509                 HcdQTD(HostID, *pTdIdx)->inUse = 1;\r
510 \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
516 \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
520 \r
521                 for (idx = 1; idx <= 4 && xferLen > 0; idx++) {\r
522                         HcdQTD(HostID,\r
523                                    *pTdIdx)->BufferPointer[idx] = Align4k(HcdQTD(HostID, (*pTdIdx))->BufferPointer[idx - 1]) + 0x1000;\r
524                         xferLen -= MIN(xferLen, 0x1000);\r
525                 }\r
526                 return HCD_STATUS_OK;\r
527         }\r
528         else {\r
529                 return HCD_STATUS_NOT_ENOUGH_QTD;\r
530         }\r
531 }\r
532 \r
533 static HCD_STATUS QueueQTDs (uint8_t HostID,\r
534                                                          uint32_t* pTdIdx,\r
535                                                          uint8_t* dataBuff,\r
536                                                          uint32_t xferLen,\r
537                                                          HCD_TRANSFER_DIR PIDCode,\r
538                                                          uint8_t DataToggle)\r
539 {\r
540         uint32_t TailTdIdx=0xFFFFFFFF;\r
541 \r
542         while (xferLen > 0)\r
543         {\r
544                 uint32_t TdLen;\r
545                 uint32_t MaxTDLen = QTD_MAX_XFER_LENGTH - Offset4k((uint32_t)dataBuff);\r
546 \r
547                 if(PipeStreaming[HostID].PacketSize > 0)\r
548                         TdLen = MIN(xferLen, PipeStreaming[HostID].PacketSize);\r
549                 else\r
550                         TdLen = MIN(xferLen, MaxTDLen);\r
551                 xferLen -= TdLen;\r
552 \r
553                 if (TailTdIdx == 0xFFFFFFFF)\r
554                 {\r
555                         ASSERT_STATUS_OK ( AllocQTD(HostID, pTdIdx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0) );\r
556                         TailTdIdx = *pTdIdx;\r
557                 }\r
558                 else\r
559                 {\r
560                         uint32_t NewTdIDx;\r
561                         if(HCD_STATUS_OK == AllocQTD(HostID, &NewTdIDx, dataBuff, TdLen, PIDCode, DataToggle, (xferLen==0) ? 1 : 0))\r
562                         {\r
563                                 HcdQTD(HostID,TailTdIdx)->NextQtd = Align32((uint32_t) HcdQTD(HostID,NewTdIDx));\r
564                                 TailTdIdx = NewTdIDx;\r
565                         }\r
566                         else\r
567                         {\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
572                                 break;\r
573                         }\r
574                 }\r
575                 if(DataToggle == 1) DataToggle = 0;\r
576                 else DataToggle = 1;\r
577                 dataBuff += TdLen;\r
578         }\r
579         if(xferLen == 0)\r
580         {\r
581                 memset(&PipeStreaming[HostID], 0, sizeof(Pipe_Stream_Handle_T));\r
582         }\r
583         return HCD_STATUS_OK;\r
584 }\r
585 \r
586 static void FreeHsItd(PHCD_HS_ITD pItd)\r
587 {\r
588         pItd->Horizontal.Link |= LINK_TERMINATE;\r
589         pItd->inUse = 0;\r
590 }\r
591 \r
592 HCD_STATUS AllocHsItd(uint8_t HostID,\r
593                                           uint32_t *pTdIdx,\r
594                                           uint8_t IhdIdx,\r
595                                           uint8_t *dataBuff,\r
596                                           uint32_t TDLen,\r
597                                           uint8_t XactPerITD,\r
598                                           uint8_t IntOnComplete)\r
599 {\r
600         for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_HS_ITD && HcdHsITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}\r
601         if ((*pTdIdx) < HCD_MAX_HS_ITD) {\r
602                 uint8_t i;\r
603                 uint8_t XactStep = 8 / XactPerITD;\r
604                 uint32_t MaxXactLen = HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;\r
605 \r
606                 memset(HcdHsITD(HostID, *pTdIdx), 0, sizeof(HCD_HS_ITD));\r
607 \r
608                 HcdHsITD(HostID, *pTdIdx)->inUse = 1;\r
609                 HcdHsITD(HostID, *pTdIdx)->IhdIdx = IhdIdx;\r
610 \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
614                         TDLen -= XactLen;\r
615 \r
616                         HcdHsITD(HostID, *pTdIdx)->BufferPointer[i] = Align4k( (uint32_t) dataBuff);\r
617 \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
623 \r
624                         dataBuff += XactLen;\r
625                 }\r
626 \r
627                 HcdHsITD(HostID, *pTdIdx)->BufferPointer[0] |= (HcdQHD(HostID, IhdIdx)->EndpointNumber << 8) | HcdQHD(HostID,\r
628                                                                                                                                                                                                                           IhdIdx)->\r
629                                                                                                            DeviceAddress;\r
630                 HcdHsITD(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
634 \r
635                 return HCD_STATUS_OK;\r
636         }\r
637         else {\r
638                 return HCD_STATUS_NOT_ENOUGH_HS_ITD;\r
639         }\r
640 }\r
641 \r
642 static HCD_STATUS QueueITDs(uint8_t HostID, uint8_t IhdIdx, uint8_t *dataBuff, uint32_t xferLen)\r
643 {\r
644         uint32_t MaxTDLen;\r
645         uint32_t FrameIdx;\r
646 \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
652                 FramePeriod = 1;\r
653         }\r
654         else {\r
655                 XactPerITD = 1;\r
656                 FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 );    /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/\r
657         }\r
658 #else\r
659         #define XactPerITD      8\r
660         #define FramePeriod     1\r
661 #endif\r
662 \r
663         MaxTDLen = XactPerITD * HcdQHD(HostID, IhdIdx)->MaxPackageSize * HcdQHD(HostID, IhdIdx)->Mult;\r
664         FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;\r
665 \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
670         }\r
671 \r
672         while (xferLen > 0) {\r
673                 uint32_t TdIdx;\r
674                 uint32_t TDLen;\r
675 \r
676                 TDLen = MIN(xferLen, MaxTDLen);\r
677                 xferLen -= TDLen;\r
678 \r
679                 ASSERT_STATUS_OK(AllocHsItd(HostID, &TdIdx, IhdIdx, dataBuff, TDLen, XactPerITD, xferLen ? 0 : 1) );\r
680 \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
684                 dataBuff += TDLen;\r
685         }\r
686 \r
687         return HCD_STATUS_OK;\r
688 }\r
689 \r
690 static void FreeSItd(PHCD_SITD pSItd)\r
691 {\r
692         pSItd->Horizontal.Link |= LINK_TERMINATE;\r
693         pSItd->inUse = 0;\r
694 }\r
695 \r
696 static HCD_STATUS AllocSItd(uint8_t HostID,\r
697                                                         uint32_t *pTdIdx,\r
698                                                         uint8_t HeadIdx,\r
699                                                         uint8_t *dataBuff,\r
700                                                         uint32_t TDLen,\r
701                                                         uint8_t IntOnComplete)\r
702 {\r
703 #define TCount_Pos 0\r
704 #define TPos_Pos 3\r
705 \r
706         for ((*pTdIdx) = 0; (*pTdIdx) < HCD_MAX_SITD && HcdSITD(HostID, *pTdIdx)->inUse; (*pTdIdx)++) {}\r
707 \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
710 \r
711                 memset(HcdSITD(HostID, *pTdIdx), 0, sizeof(HCD_SITD) );\r
712 \r
713                 HcdSITD(HostID, *pTdIdx)->inUse = 1;\r
714                 HcdSITD(HostID, *pTdIdx)->IhdIdx = HeadIdx;\r
715 \r
716                 /*-- Word 1 --*/\r
717                 HcdSITD(HostID, *pTdIdx)->Horizontal.Link = LINK_TERMINATE;\r
718                 /*-- Word 2 --*/\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
724                 /*-- Word 3 --*/\r
725                 HcdSITD(HostID, *pTdIdx)->uFrameSMask = (1 << TCount) - 1;\r
726                 HcdSITD(HostID, *pTdIdx)->uFrameCMask = 0;\r
727                 /*-- Word 4 --*/\r
728                 HcdSITD(HostID, *pTdIdx)->Active = 1;\r
729                 HcdSITD(HostID, *pTdIdx)->TotalBytesToTransfer = TDLen;\r
730                 HcdSITD(HostID, *pTdIdx)->IntOnComplete = IntOnComplete;\r
731                 /*-- Word 5 --*/\r
732                 HcdSITD(HostID, *pTdIdx)->BufferPointer[0] = (uint32_t) dataBuff;\r
733                 /*-- Word 6 --*/\r
734                 HcdSITD(HostID, *pTdIdx)->BufferPointer[1] = Align4k( ((uint32_t) dataBuff) + TDLen);\r
735 \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
738 \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
741 \r
742                 /*-- Word 7 --*/\r
743                 HcdSITD(HostID, *pTdIdx)->BackPointer = LINK_TERMINATE;\r
744 \r
745                 return HCD_STATUS_OK;\r
746         }\r
747         else {\r
748                 return HCD_STATUS_NOT_ENOUGH_SITD;\r
749         }\r
750 }\r
751 \r
752 static HCD_STATUS QueueSITDs(uint8_t HostID, uint8_t HeadIdx, uint8_t *dataBuff, uint32_t xferLen)\r
753 {\r
754         uint32_t FrameIdx;\r
755 \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
760                 FramePeriod = 1;\r
761         }\r
762         else {\r
763                 FramePeriod = 1 << ( HcdQHD(IhdIdx)->Interval - 4 );    /*-- Frame step 4 => 1, 5 => 2, 6 => 3 --*/\r
764         }\r
765 #else\r
766         #define FramePeriod     1\r
767 #endif\r
768 \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
773         }\r
774 \r
775         FrameIdx = USB_REG(HostID)->FRINDEX_H >> 3;\r
776         while (xferLen) {\r
777                 uint32_t TdIdx;\r
778                 uint32_t TDLen;\r
779 \r
780                 TDLen = MIN(xferLen, HcdQHD(HostID, HeadIdx)->MaxPackageSize);\r
781                 xferLen -= TDLen;\r
782 \r
783                 ASSERT_STATUS_OK(AllocSItd(HostID, &TdIdx, HeadIdx, dataBuff, TDLen, xferLen ? 0 : 1) );\r
784 \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
788                 dataBuff += TDLen;\r
789         }\r
790         return HCD_STATUS_OK;\r
791 }\r
792 \r
793 static HCD_STATUS WaitForTransferComplete(uint8_t HostID, uint8_t EdIdx)/* TODO indentical to OHCI now */\r
794 {\r
795 \r
796 #ifndef __TEST__\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
799         }\r
800         return (HCD_STATUS) HcdQHD(HostID, EdIdx)->status;\r
801 #else\r
802         return HCD_STATUS_OK;\r
803 #endif\r
804 \r
805 }\r
806 \r
807 static HCD_STATUS PipehandleParse(uint32_t Pipehandle, uint8_t *pHostID, HCD_TRANSFER_TYPE *XferType, uint8_t *pIdx)\r
808 {\r
809         Pipe_Handle_T *pHandle = (Pipe_Handle_T *) (&Pipehandle);\r
810 \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
816         }\r
817 \r
818         if (pHostID) {\r
819                 *pHostID = pHandle->HostId;\r
820         }\r
821         if (pIdx) {\r
822                 *pIdx = pHandle->Idx;\r
823         }\r
824         if (XferType) {\r
825                 *XferType = (HCD_TRANSFER_TYPE) pHandle->Type;\r
826         }\r
827 \r
828         return HCD_STATUS_OK;\r
829 }\r
830 \r
831 static void PipehandleCreate(uint32_t *pPipeHandle, uint8_t HostID, HCD_TRANSFER_TYPE XferType, uint8_t idx)\r
832 {\r
833         /*---------- HostID | PortNum | Type | Idx ----------*/\r
834         Pipe_Handle_T *pHandle = (Pipe_Handle_T *) pPipeHandle;\r
835 \r
836         pHandle->HostId = HostID;\r
837         pHandle->PortNumber = 0;\r
838         pHandle->Type = (uint8_t) XferType;\r
839         pHandle->Idx = idx;\r
840 }\r
841 \r
842 static __INLINE PHCD_QHD    HcdAsyncHead(uint8_t HostID)\r
843 {\r
844         return &(ehci_data[HostID].AsyncHeadQhd);\r
845         //      return &(ehci_data.AsyncHeadQhd);\r
846 }\r
847 \r
848 static __INLINE PHCD_QHD    HcdIntHead(uint8_t HostID)\r
849 {\r
850         return &(ehci_data[HostID].IntHeadQhd);\r
851         //      return &(ehci_data.IntHeadQhd);\r
852 }\r
853 \r
854 // === TODO: Deal with HostID later ===\r
855 static __INLINE PHCD_QHD    HcdQHD(uint8_t HostID, uint8_t idx)\r
856 {\r
857         return &(ehci_data[HostID].qHDs[idx]);\r
858         //      return &(ehci_data.qHDs[idx]);\r
859 }\r
860 \r
861 static __INLINE PHCD_QTD    HcdQTD(uint8_t HostID, uint8_t idx)\r
862 {\r
863         return &(ehci_data[HostID].qTDs[idx]);\r
864         //      return &(ehci_data.qTDs[idx]);\r
865 }\r
866 \r
867 static __INLINE PHCD_SITD   HcdSITD(uint8_t HostID, uint8_t idx)\r
868 {\r
869         return &(ehci_data[HostID].siTDs[idx]);\r
870         //      return &(ehci_data.siTDs[idx]);\r
871 }\r
872 \r
873 static __INLINE PHCD_HS_ITD HcdHsITD(uint8_t HostID, uint8_t idx)\r
874 {\r
875         return &(ehci_data[HostID].iTDs[idx]);\r
876         //      return &(ehci_data.iTDs[idx]);\r
877 }\r
878 \r
879 static __INLINE bool        isValidLink(uint32_t link)\r
880 {\r
881         return (link & LINK_TERMINATE) == 0;\r
882 }\r
883 \r
884 static __INLINE bool IsInterruptQhd(uint8_t HostID, uint8_t QhdIdx)\r
885 {\r
886         return HcdQHD(HostID, QhdIdx)->uFrameSMask;\r
887 }\r
888 \r
889 void    HcdIrqHandler(uint8_t HostID)\r
890 {\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
894 \r
895         if (IntStatus == 0) {\r
896                 return;\r
897         }\r
898 \r
899         /* disable all interrupt for processing */\r
900         /* Acknowledge Interrrupt */\r
901         USB_REG(HostID)->USBSTS_H |= IntStatus;\r
902 \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
909                 }\r
910                 if (PortSC & EHC_PORTSC_PortEnableChange) {\r
911                         USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortEnableChange;              /* Clear PortSC Interrupt Status */\r
912                 }\r
913                 if (PortSC & EHC_PORTSC_OvercurrentChange) {\r
914                         USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_OvercurrentChange;     /* Clear PortSC Interrupt Status */\r
915                 }\r
916                 if (PortSC & EHC_PORTSC_ForcePortResume) {\r
917                         USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_ForcePortResume;               /* Clear PortSC Interrupt Status */\r
918                 }\r
919         }\r
920 \r
921         if (IntStatus & EHC_USBSTS_UsbAsyncInt) {\r
922                 AsyncScheduleIsr(HostID);\r
923         }\r
924 \r
925         if (IntStatus & EHC_USBSTS_UsbPeriodInt) {\r
926                 PeriodScheduleIsr(HostID);\r
927         }\r
928 \r
929         if (IntStatus & EHC_USBSTS_UsbErrorInt) {\r
930                 UsbErrorIsr(HostID);\r
931         }\r
932 \r
933         if (IntStatus & EHC_USBSTS_IntAsyncAdvance) {\r
934                 AsyncAdvanceIsr(HostID);\r
935         }\r
936         /* Enable Interrupt */\r
937 }\r
938 \r
939 static void RemoveCompletedQTD(uint8_t HostID, PHCD_QHD pQhd)\r
940 {\r
941         PHCD_QTD pQtd;\r
942         uint32_t TdLink = pQhd->FirstQtd;\r
943         bool is_data_remain = false;\r
944 \r
945         /*-- Foreach Qtd in Qhd --*/\r
946         while( (isValidLink(TdLink), pQtd = (PHCD_QTD) Align32(TdLink) ) &&\r
947                         pQtd->Active == 0)\r
948         {\r
949                 TdLink = pQtd->NextQtd;\r
950 \r
951                 if(pQhd->pActualTransferCount)\r
952                         *(pQhd->pActualTransferCount) -= pQtd->TotalBytesToTransfer;\r
953 \r
954                 if (pQtd->IntOnComplete)\r
955                 {\r
956                         if(PipeStreaming[HostID].RemainBytes > 0)\r
957                                 is_data_remain = true;\r
958                         else\r
959                                 pQhd->status = HCD_STATUS_OK;\r
960                 }\r
961                 if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/)\r
962                 {\r
963                         pQhd->status = HCD_STATUS_TRANSFER_Stall;\r
964                 }\r
965                 FreeQtd(pQtd);\r
966         }\r
967         pQhd->FirstQtd = TdLink;\r
968         if(is_data_remain)\r
969         {\r
970                 uint32_t pQtd;\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
977         }       \r
978 }\r
979 \r
980 static void RemoveErrorQTD(PHCD_QHD pQhd)\r
981 {\r
982         PHCD_QTD pQtd;\r
983         uint32_t TdLink = pQhd->FirstQtd;\r
984         bool errorfound = false;\r
985 \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
990 \r
991                 if (pQtd->Halted /*|| pQtd->Babble || pQtd->BufferError || pQtd->TransactionError*/) {\r
992                         errorfound = true;\r
993                         pQhd->status = HCD_STATUS_TRANSFER_Stall;\r
994                 }\r
995         }\r
996         /*-- Remove error Qtd in Qhd --*/\r
997         if (errorfound) {\r
998                 TdLink = pQhd->FirstQtd;\r
999                 while (isValidLink(TdLink)) {\r
1000                         pQtd = (PHCD_QTD) Align32(TdLink);\r
1001                         TdLink = pQtd->NextQtd;\r
1002                         pQtd->Active = 0;\r
1003                         pQtd->IntOnComplete = 0;\r
1004                         FreeQtd(pQtd);\r
1005                 }\r
1006                 pQhd->FirstQtd = LINK_TERMINATE;\r
1007                 pQhd->Overlay.Halted = 0;\r
1008         }\r
1009 }\r
1010 \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
1013 {\r
1014         PHCD_QHD pQhd = HcdAsyncHead(HostID);\r
1015 \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
1021         }\r
1022 }\r
1023 \r
1024 static void PeriodScheduleIsr(uint8_t HostID)\r
1025 {\r
1026         uint32_t i;\r
1027 \r
1028         /*ISOCHRONOUS*/\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
1031 \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
1036 \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
1047                                         }\r
1048                                         /*-- remove executed ITD --*/\r
1049                                         pNextPointer->Link = pItd->Horizontal.Link;\r
1050                                         FreeHsItd(pItd);\r
1051                                         continue;       /*-- skip advance pNextPointer due to TD removal --*/\r
1052                                 }\r
1053                         }\r
1054                         else if (pNextPointer->Type == SITD_TYPE) {     /*-- Split ISO --*/\r
1055                                 PHCD_SITD pSItd = (PHCD_SITD) Align32(pNextPointer->Link);\r
1056 \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
1061                                         }\r
1062 \r
1063                                         /*-- removed executed SITD --*/\r
1064                                         pNextPointer->Link = pSItd->Horizontal.Link;\r
1065                                         FreeSItd(pSItd);\r
1066                                         continue;       /*-- skip advance pNextPointer due to TD removal --*/\r
1067                                 }\r
1068                         }\r
1069 \r
1070                         pNextPointer = (NextLinkPointer *) Align32(pNextPointer->Link);\r
1071                 }\r
1072         }\r
1073 \r
1074         /*INTERRUPT*/\r
1075         {\r
1076                 PHCD_QHD pQhd = HcdIntHead(HostID);\r
1077 \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
1082                 }\r
1083         }\r
1084 }\r
1085 \r
1086 static void UsbErrorIsr(uint8_t HostID)\r
1087 {\r
1088         PHCD_QHD pQhd = HcdAsyncHead(HostID);\r
1089 \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
1095         }\r
1096 }\r
1097 \r
1098 static HCD_STATUS PortStatusChangeIsr(uint8_t HostID, uint32_t deviceConnect)\r
1099 {\r
1100         if (deviceConnect) {/* Device Attached */\r
1101                 USB_Host_Enumerate(HostID);\r
1102         }\r
1103         else {  /* Device detached */\r
1104                 USB_Host_DeEnumerate(HostID);\r
1105         }\r
1106         return HCD_STATUS_OK;\r
1107 }\r
1108 \r
1109 static void AsyncAdvanceIsr(uint8_t HostID)\r
1110 {\r
1111         uint32_t QhdIdx;\r
1112 \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
1116                 }\r
1117 }\r
1118 \r
1119 static __INLINE HCD_STATUS EHciHostRun(uint8_t HostID)\r
1120 {\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
1124 }\r
1125 \r
1126 static __INLINE HCD_STATUS EHciHostStop(uint8_t HostID)\r
1127 {\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
1131 }\r
1132 \r
1133 static __INLINE HCD_STATUS EHciHostReset(uint8_t HostID)\r
1134 {\r
1135         if (USB_REG(HostID)->USBSTS_H & EHC_USBSTS_HCHalted) {\r
1136                 EHciHostStop(HostID);\r
1137         }\r
1138 \r
1139         USB_REG(HostID)->USBCMD_H |= EHC_USBCMD_HostReset;\r
1140         while ( USB_REG(HostID)->USBCMD_H & EHC_USBCMD_HostReset ) {}\r
1141 \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
1145 }\r
1146 \r
1147 static __INLINE HCD_STATUS EHciHostInit(uint8_t HostID)\r
1148 {\r
1149         uint32_t idx;\r
1150 \r
1151         /*---------- Host Data Structure Init ----------*/\r
1152         //      memset(&ehci_data[HostID], 0, sizeof(EHCI_HOST_DATA_T) );\r
1153 \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
1161 \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
1170 \r
1171         USB_REG(HostID)->ASYNCLISTADDR = (uint32_t) HcdAsyncHead(HostID);\r
1172 \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
1180 \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
1184         }\r
1185 \r
1186         USB_REG(HostID)->PERIODICLISTBASE = Align4k( (uint32_t) EHCI_FRAME_LIST(HostID) );\r
1187 \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
1191 \r
1192         /*---------- CONFIGFLAG ----------*/\r
1193         /* LPC18xx doesn't has CONFIGFLAG register */\r
1194 \r
1195         /*---------- Power On RhPort ----------*/\r
1196         USB_REG(HostID)->PORTSC1_H |= EHC_PORTSC_PortPowerControl;\r
1197 \r
1198         EHciHostRun(HostID);/* Run The HC */\r
1199 \r
1200         return HCD_STATUS_OK;\r
1201 }\r
1202 \r
1203 static __INLINE void DisableSchedule(uint8_t HostID, uint8_t isPeriod)\r
1204 {\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
1207 \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
1211         }\r
1212 }\r
1213 \r
1214 static __INLINE void EnableSchedule(uint8_t HostID, uint8_t isPeriod)\r
1215 {\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
1218 \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
1222         }\r
1223 }\r
1224 \r
1225 static void DisableAsyncSchedule(uint8_t HostID)\r
1226 {\r
1227         DisableSchedule(HostID, 0);\r
1228 }\r
1229 \r
1230 static void EnableAsyncSchedule(uint8_t HostID)\r
1231 {\r
1232         EnableSchedule(HostID, 0);\r
1233 }\r
1234 \r
1235 static void DisablePeriodSchedule(uint8_t HostID)\r
1236 {\r
1237         DisableSchedule(HostID, 1);\r
1238 }\r
1239 \r
1240 static void EnablePeriodSchedule(uint8_t HostID)\r
1241 {\r
1242         EnableSchedule(HostID, 1);\r
1243 }\r
1244 \r
1245 void HcdSetStreamPacketSize(uint32_t PipeHandle, uint16_t packetsize)\r
1246 {\r
1247         uint8_t HostID = 0, HeadIdx;\r
1248         HCD_TRANSFER_TYPE XferType;\r
1249 \r
1250         PipehandleParse(PipeHandle, &HostID, &XferType, &HeadIdx);\r
1251 \r
1252         PipeStreaming[HostID].PacketSize = packetsize;\r
1253 }\r
1254 \r
1255 #endif // __LPC_EHCI__\r