| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

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