2 This file contains the implementation of Usb Hc Protocol.
4 Copyright (c) 2013-2015 Intel Corporation.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Provides software reset for the USB host controller.
22 @param This This EFI_USB_HC_PROTOCOL instance.
23 @param Attributes A bit mask of the reset operation to perform.
25 @retval EFI_SUCCESS The reset operation succeeded.
26 @retval EFI_INVALID_PARAMETER Attributes is not valid.
27 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
28 not currently supported by the host controller.
29 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
35 IN EFI_USB_HC_PROTOCOL
*This
,
43 UINT32 PowerOnGoodTime
;
47 if ((Attributes
& ~(EFI_USB_HC_RESET_GLOBAL
| EFI_USB_HC_RESET_HOST_CONTROLLER
)) != 0) {
48 return EFI_INVALID_PARAMETER
;
52 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
54 if ((Attributes
& EFI_USB_HC_RESET_HOST_CONTROLLER
) != 0) {
55 gBS
->Stall (50 * 1000);
56 Status
= OhciSetHcCommandStatus (Ohc
, HC_RESET
, HC_RESET
);
57 if (EFI_ERROR (Status
)) {
58 return EFI_DEVICE_ERROR
;
60 gBS
->Stall (50 * 1000);
62 // Wait for host controller reset.
66 gBS
->Stall (1 * 1000);
67 Data32
= OhciGetOperationalReg (Ohc
->PciIo
, HC_COMMAND_STATUS
);
68 if (EFI_ERROR (Status
)) {
69 return EFI_DEVICE_ERROR
;
71 if ((Data32
& HC_RESET
) == 0) {
75 }while(PowerOnGoodTime
--);
77 return EFI_DEVICE_ERROR
;
80 OhciFreeIntTransferMemory (Ohc
);
81 Status
= OhciInitializeInterruptList (Ohc
);
82 OhciSetFrameInterval (Ohc
, FRAME_INTERVAL
, 0x2edf);
83 if ((Attributes
& EFI_USB_HC_RESET_GLOBAL
) != 0) {
84 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_RESET
);
85 if (EFI_ERROR (Status
)) {
86 return EFI_DEVICE_ERROR
;
88 gBS
->Stall (50 * 1000);
91 // Initialize host controller operational registers
93 OhciSetFrameInterval (Ohc
, FS_LARGEST_DATA_PACKET
, 0x2778);
94 OhciSetFrameInterval (Ohc
, FRAME_INTERVAL
, 0x2edf);
95 OhciSetPeriodicStart (Ohc
, 0x2a2f);
96 OhciSetHcControl (Ohc
, CONTROL_BULK_RATIO
, 0x3);
97 OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
| BULK_LIST_FILLED
, 0);
98 OhciSetRootHubDescriptor (Ohc
, RH_PSWITCH_MODE
, 0);
99 OhciSetRootHubDescriptor (Ohc
, RH_NO_PSWITCH
| RH_NOC_PROT
, 1);
100 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
101 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
103 OhciSetRootHubDescriptor (Ohc
, RH_DEV_REMOVABLE
, 0);
104 OhciSetRootHubDescriptor (Ohc
, RH_PORT_PWR_CTRL_MASK
, 0xffff);
105 OhciSetRootHubStatus (Ohc
, RH_LOCAL_PSTAT_CHANGE
);
106 OhciSetRootHubPortStatus (Ohc
, 0, RH_SET_PORT_POWER
);
107 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
108 for (Index
= 0; Index
< NumOfPorts
; Index
++) {
109 if (!EFI_ERROR (OhciSetRootHubPortFeature (This
, Index
, EfiUsbPortReset
))) {
110 gBS
->Stall (200 * 1000);
111 OhciClearRootHubPortFeature (This
, Index
, EfiUsbPortReset
);
113 OhciSetRootHubPortFeature (This
, Index
, EfiUsbPortEnable
);
117 OhciSetMemoryPointer (Ohc
, HC_HCCA
, Ohc
->HccaMemoryBlock
);
118 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
119 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
120 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| BULK_ENABLE
, 1); /*ISOCHRONOUS_ENABLE*/
121 OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_OPERATIONAL
);
122 gBS
->Stall (50*1000);
124 // Wait till first SOF occurs, and then clear it
126 while (OhciGetHcInterruptStatus (Ohc
, START_OF_FRAME
) == 0);
127 OhciClearInterruptStatus (Ohc
, START_OF_FRAME
);
134 Retrieve the current state of the USB host controller.
136 @param This This EFI_USB_HC_PROTOCOL instance.
137 @param State Variable to return the current host controller
140 @retval EFI_SUCCESS Host controller state was returned in State.
141 @retval EFI_INVALID_PARAMETER State is NULL.
142 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
143 retrieve the host controller's current state.
150 IN EFI_USB_HC_PROTOCOL
*This
,
151 OUT EFI_USB_HC_STATE
*State
154 USB_OHCI_HC_DEV
*Ohc
;
158 return EFI_INVALID_PARAMETER
;
161 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
163 FuncState
= OhciGetHcControl (Ohc
, HC_FUNCTIONAL_STATE
);
167 case HC_STATE_RESUME
:
168 *State
= EfiUsbHcStateHalt
;
171 case HC_STATE_OPERATIONAL
:
172 *State
= EfiUsbHcStateOperational
;
175 case HC_STATE_SUSPEND
:
176 *State
= EfiUsbHcStateSuspend
;
186 Sets the USB host controller to a specific state.
188 @param This This EFI_USB_HC_PROTOCOL instance.
189 @param State The state of the host controller that will be set.
191 @retval EFI_SUCCESS The USB host controller was successfully placed
192 in the state specified by State.
193 @retval EFI_INVALID_PARAMETER State is invalid.
194 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
201 IN EFI_USB_HC_PROTOCOL
*This
,
202 IN EFI_USB_HC_STATE State
206 USB_OHCI_HC_DEV
*Ohc
;
208 Ohc
= USB_OHCI_HC_DEV_FROM_THIS(This
);
211 case EfiUsbHcStateHalt
:
212 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_RESET
);
215 case EfiUsbHcStateOperational
:
216 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_OPERATIONAL
);
219 case EfiUsbHcStateSuspend
:
220 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_SUSPEND
);
224 Status
= EFI_INVALID_PARAMETER
;
234 Submits control transfer to a target USB device.
236 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
237 @param DeviceAddress Represents the address of the target device on the USB,
238 which is assigned during USB enumeration.
239 @param IsSlowDevice Indicates whether the target device is slow device
240 or full-speed device.
241 @param MaxPaketLength Indicates the maximum packet size that the
242 default control transfer endpoint is capable of
243 sending or receiving.
244 @param Request A pointer to the USB device request that will be sent
246 @param TransferDirection Specifies the data direction for the transfer.
247 There are three values available, DataIn, DataOut
249 @param Data A pointer to the buffer of data that will be transmitted
250 to USB device or received from USB device.
251 @param DataLength Indicates the size, in bytes, of the data buffer
253 @param TimeOut Indicates the maximum time, in microseconds,
254 which the transfer is allowed to complete.
255 @param TransferResult A pointer to the detailed result information generated
256 by this control transfer.
258 @retval EFI_SUCCESS The control transfer was completed successfully.
259 @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.
260 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
261 @retval EFI_TIMEOUT The control transfer failed due to timeout.
262 @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.
263 Caller should check TranferResult for detailed error information.
270 OhciControlTransfer (
271 IN EFI_USB_HC_PROTOCOL
*This
,
272 IN UINT8 DeviceAddress
,
273 IN BOOLEAN IsSlowDevice
,
274 IN UINT8 MaxPacketLength
,
275 IN EFI_USB_DEVICE_REQUEST
*Request
,
276 IN EFI_USB_DATA_DIRECTION TransferDirection
,
277 IN OUT VOID
*Data OPTIONAL
,
278 IN OUT UINTN
*DataLength OPTIONAL
,
280 OUT UINT32
*TransferResult
283 USB_OHCI_HC_DEV
*Ohc
;
284 ED_DESCRIPTOR
*HeadEd
;
286 TD_DESCRIPTOR
*HeadTd
;
287 TD_DESCRIPTOR
*SetupTd
;
288 TD_DESCRIPTOR
*DataTd
;
289 TD_DESCRIPTOR
*StatusTd
;
290 TD_DESCRIPTOR
*EmptyTd
;
295 OHCI_ED_RESULT EdResult
;
297 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
299 UINTN ActualSendLength
;
303 VOID
*ReqMapping
= NULL
;
304 UINTN ReqMapLength
= 0;
305 EFI_PHYSICAL_ADDRESS ReqMapPhyAddr
= 0;
307 VOID
*DataMapping
= NULL
;
308 UINTN DataMapLength
= 0;
309 EFI_PHYSICAL_ADDRESS DataMapPhyAddr
= 0;
314 if ((TransferDirection
!= EfiUsbDataOut
&& TransferDirection
!= EfiUsbDataIn
&&
315 TransferDirection
!= EfiUsbNoData
) ||
316 Request
== NULL
|| DataLength
== NULL
|| TransferResult
== NULL
||
317 (TransferDirection
== EfiUsbNoData
&& (*DataLength
!= 0 || Data
!= NULL
)) ||
318 (TransferDirection
!= EfiUsbNoData
&& (*DataLength
== 0 || Data
== NULL
)) ||
319 (IsSlowDevice
&& MaxPacketLength
!= 8) ||
320 (MaxPacketLength
!= 8 && MaxPacketLength
!= 16 &&
321 MaxPacketLength
!= 32 && MaxPacketLength
!= 64)) {
322 return EFI_INVALID_PARAMETER
;
325 if (*DataLength
> MAX_BYTES_PER_TD
) {
326 DEBUG ((EFI_D_ERROR
, "OhciControlTransfer: Request data size is too large\r\n"));
327 return EFI_INVALID_PARAMETER
;
330 Ohc
= USB_OHCI_HC_DEV_FROM_THIS(This
);
332 if (TransferDirection
== EfiUsbDataIn
) {
333 DataPidDir
= TD_IN_PID
;
334 StatusPidDir
= TD_OUT_PID
;
336 DataPidDir
= TD_OUT_PID
;
337 StatusPidDir
= TD_IN_PID
;
340 Status
= OhciSetHcControl (Ohc
, CONTROL_ENABLE
, 0);
341 if (EFI_ERROR(Status
)) {
342 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));
343 *TransferResult
= EFI_USB_ERR_SYSTEM
;
344 return EFI_DEVICE_ERROR
;
346 Status
= OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
, 0);
347 if (EFI_ERROR(Status
)) {
348 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));
349 *TransferResult
= EFI_USB_ERR_SYSTEM
;
350 return EFI_DEVICE_ERROR
;
352 gBS
->Stall(20 * 1000);
354 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
355 Ed
= OhciCreateED (Ohc
);
357 Status
= EFI_OUT_OF_RESOURCES
;
358 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));
361 OhciSetEDField (Ed
, ED_SKIP
, 1);
362 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
363 OhciSetEDField (Ed
, ED_ENDPT_NUM
, 0);
364 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
365 OhciSetEDField (Ed
, ED_SPEED
, IsSlowDevice
);
366 OhciSetEDField (Ed
, ED_FORMAT
| ED_HALTED
| ED_DTTOGGLE
, 0);
367 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
368 OhciSetEDField (Ed
, ED_PDATA
, 0);
369 OhciSetEDField (Ed
, ED_ZERO
, 0);
370 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
371 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
372 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
373 HeadEd
= OhciAttachEDToList (Ohc
, CONTROL_LIST
, Ed
, NULL
);
377 if(Request
!= NULL
) {
378 ReqMapLength
= sizeof(EFI_USB_DEVICE_REQUEST
);
379 MapOp
= EfiPciIoOperationBusMasterRead
;
380 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, (UINT8
*)Request
, &ReqMapLength
, &ReqMapPhyAddr
, &ReqMapping
);
381 if (EFI_ERROR(Status
)) {
382 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));
386 SetupTd
= OhciCreateTD (Ohc
);
387 if (SetupTd
== NULL
) {
388 Status
= EFI_OUT_OF_RESOURCES
;
389 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));
390 goto UNMAP_SETUP_BUFF
;
393 OhciSetTDField (SetupTd
, TD_PDATA
, 0);
394 OhciSetTDField (SetupTd
, TD_BUFFER_ROUND
, 1);
395 OhciSetTDField (SetupTd
, TD_DIR_PID
, TD_SETUP_PID
);
396 OhciSetTDField (SetupTd
, TD_DELAY_INT
, TD_NO_DELAY
);
397 OhciSetTDField (SetupTd
, TD_DT_TOGGLE
, 2);
398 OhciSetTDField (SetupTd
, TD_ERROR_CNT
, 0);
399 OhciSetTDField (SetupTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
400 OhciSetTDField (SetupTd
, TD_CURR_BUFFER_PTR
, (UINT32
)ReqMapPhyAddr
);
401 OhciSetTDField (SetupTd
, TD_NEXT_PTR
, 0);
402 OhciSetTDField (SetupTd
, TD_BUFFER_END_PTR
, (UINT32
)(ReqMapPhyAddr
+ sizeof (EFI_USB_DEVICE_REQUEST
) - 1));
403 SetupTd
->ActualSendLength
= sizeof (EFI_USB_DEVICE_REQUEST
);
404 SetupTd
->DataBuffer
= (UINT32
)ReqMapPhyAddr
;
405 SetupTd
->NextTDPointer
= 0;
407 if (TransferDirection
== EfiUsbDataIn
) {
408 MapOp
= EfiPciIoOperationBusMasterWrite
;
410 MapOp
= EfiPciIoOperationBusMasterRead
;
412 DataMapLength
= *DataLength
;
413 if ((Data
!= NULL
) && (DataMapLength
!= 0)) {
414 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, Data
, &DataMapLength
, &DataMapPhyAddr
, &DataMapping
);
415 if (EFI_ERROR(Status
)) {
416 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));
423 LeftLength
= DataMapLength
;
424 ActualSendLength
= DataMapLength
;
426 while (LeftLength
> 0) {
427 ActualSendLength
= LeftLength
;
428 if (LeftLength
> MaxPacketLength
) {
429 ActualSendLength
= MaxPacketLength
;
431 DataTd
= OhciCreateTD (Ohc
);
432 if (DataTd
== NULL
) {
433 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
434 Status
= EFI_OUT_OF_RESOURCES
;
435 goto UNMAP_DATA_BUFF
;
437 OhciSetTDField (DataTd
, TD_PDATA
, 0);
438 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
439 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
440 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
441 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, DataToggle
);
442 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
443 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
444 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) DataMapPhyAddr
);
445 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(DataMapPhyAddr
+ ActualSendLength
- 1));
446 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
447 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
448 DataTd
->DataBuffer
= (UINT32
)DataMapPhyAddr
;
449 DataTd
->NextTDPointer
= 0;
450 OhciLinkTD (HeadTd
, DataTd
);
452 DataMapPhyAddr
+= ActualSendLength
;
453 LeftLength
-= ActualSendLength
;
458 StatusTd
= OhciCreateTD (Ohc
);
459 if (StatusTd
== NULL
) {
460 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));
461 Status
= EFI_OUT_OF_RESOURCES
;
462 goto UNMAP_DATA_BUFF
;
464 OhciSetTDField (StatusTd
, TD_PDATA
, 0);
465 OhciSetTDField (StatusTd
, TD_BUFFER_ROUND
, 1);
466 OhciSetTDField (StatusTd
, TD_DIR_PID
, StatusPidDir
);
467 OhciSetTDField (StatusTd
, TD_DELAY_INT
, 7);
468 OhciSetTDField (StatusTd
, TD_DT_TOGGLE
, 3);
469 OhciSetTDField (StatusTd
, TD_ERROR_CNT
, 0);
470 OhciSetTDField (StatusTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
471 OhciSetTDField (StatusTd
, TD_CURR_BUFFER_PTR
, 0);
472 OhciSetTDField (StatusTd
, TD_NEXT_PTR
, 0);
473 OhciSetTDField (StatusTd
, TD_BUFFER_END_PTR
, 0);
474 StatusTd
->ActualSendLength
= 0;
475 StatusTd
->DataBuffer
= 0;
476 StatusTd
->NextTDPointer
= 0;
477 OhciLinkTD (HeadTd
, StatusTd
);
481 EmptyTd
= OhciCreateTD (Ohc
);
482 if (EmptyTd
== NULL
) {
483 Status
= EFI_OUT_OF_RESOURCES
;
484 goto UNMAP_DATA_BUFF
;
486 OhciSetTDField (EmptyTd
, TD_PDATA
, 0);
487 OhciSetTDField (EmptyTd
, TD_BUFFER_ROUND
, 0);
488 OhciSetTDField (EmptyTd
, TD_DIR_PID
, 0);
489 OhciSetTDField (EmptyTd
, TD_DELAY_INT
, 0);
490 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
491 EmptyTd
->Word0
.DataToggle
= 0;
492 OhciSetTDField (EmptyTd
, TD_ERROR_CNT
, 0);
493 OhciSetTDField (EmptyTd
, TD_COND_CODE
, 0);
494 OhciSetTDField (EmptyTd
, TD_CURR_BUFFER_PTR
, 0);
495 OhciSetTDField (EmptyTd
, TD_BUFFER_END_PTR
, 0);
496 OhciSetTDField (EmptyTd
, TD_NEXT_PTR
, 0);
497 EmptyTd
->ActualSendLength
= 0;
498 EmptyTd
->DataBuffer
= 0;
499 EmptyTd
->NextTDPointer
= 0;
500 OhciLinkTD (HeadTd
, EmptyTd
);
501 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptyTd
;
502 OhciAttachTDListToED (Ed
, HeadTd
);
504 // For debugging, dump ED & TD buffer befor transferring
507 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);
509 OhciSetEDField (Ed
, ED_SKIP
, 0);
510 Status
= OhciSetHcControl (Ohc
, CONTROL_ENABLE
, 1);
511 if (EFI_ERROR(Status
)) {
512 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));
513 *TransferResult
= EFI_USB_ERR_SYSTEM
;
514 Status
= EFI_DEVICE_ERROR
;
515 goto UNMAP_DATA_BUFF
;
517 Status
= OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
, 1);
518 if (EFI_ERROR(Status
)) {
519 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));
520 *TransferResult
= EFI_USB_ERR_SYSTEM
;
521 Status
= EFI_DEVICE_ERROR
;
522 goto UNMAP_DATA_BUFF
;
524 gBS
->Stall(20 * 1000);
528 Status
= CheckIfDone (Ohc
, CONTROL_LIST
, Ed
, HeadTd
, &EdResult
);
530 while (Status
== EFI_NOT_READY
&& TimeCount
<= TimeOut
) {
533 Status
= CheckIfDone (Ohc
, CONTROL_LIST
, Ed
, HeadTd
, &EdResult
);
536 // For debugging, dump ED & TD buffer after transferring
538 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);
540 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
542 if (EdResult
.ErrorCode
!= TD_NO_ERROR
) {
543 if (EdResult
.ErrorCode
== TD_TOBE_PROCESSED
) {
544 DEBUG ((EFI_D_INFO
, "Control pipe timeout, > %d mS\r\n", TimeOut
));
546 DEBUG ((EFI_D_INFO
, "Control pipe broken\r\n"));
550 DEBUG ((EFI_D_INFO
, "Control transfer successed\r\n"));
554 OhciSetEDField (Ed
, ED_SKIP
, 1);
556 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
558 HeadEd
->NextED
= Ed
->NextED
;
560 if(DataMapping
!= NULL
) {
561 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, DataMapping
);
567 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
568 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
572 if(ReqMapping
!= NULL
) {
573 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, ReqMapping
);
577 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
585 Submits bulk transfer to a bulk endpoint of a USB device.
587 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
588 @param DeviceAddress Represents the address of the target device on the USB,
589 which is assigned during USB enumeration.
590 @param EndPointAddress The combination of an endpoint number and an
591 endpoint direction of the target USB device.
592 Each endpoint address supports data transfer in
593 one direction except the control endpoint
594 (whose default endpoint address is 0).
595 It is the caller's responsibility to make sure that
596 the EndPointAddress represents a bulk endpoint.
597 @param MaximumPacketLength Indicates the maximum packet size the target endpoint
598 is capable of sending or receiving.
599 @param Data A pointer to the buffer of data that will be transmitted
600 to USB device or received from USB device.
601 @param DataLength When input, indicates the size, in bytes, of the data buffer
602 specified by Data. When output, indicates the actually
603 transferred data size.
604 @param DataToggle A pointer to the data toggle value. On input, it indicates
605 the initial data toggle value the bulk transfer should adopt;
606 on output, it is updated to indicate the data toggle value
607 of the subsequent bulk transfer.
608 @param TimeOut Indicates the maximum time, in microseconds, which the
609 transfer is allowed to complete.
610 TransferResult A pointer to the detailed result information of the
613 @retval EFI_SUCCESS The bulk transfer was completed successfully.
614 @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.
615 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
616 @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
617 @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
618 Caller should check TranferResult for detailed error information.
626 IN EFI_USB_HC_PROTOCOL
*This
,
627 IN UINT8 DeviceAddress
,
628 IN UINT8 EndPointAddress
,
629 IN UINT8 MaxPacketLength
,
631 IN OUT UINTN
*DataLength
,
632 IN OUT UINT8
*DataToggle
,
634 OUT UINT32
*TransferResult
637 USB_OHCI_HC_DEV
*Ohc
;
638 ED_DESCRIPTOR
*HeadEd
;
641 TD_DESCRIPTOR
*HeadTd
;
642 TD_DESCRIPTOR
*DataTd
;
643 TD_DESCRIPTOR
*EmptyTd
;
647 OHCI_ED_RESULT EdResult
;
649 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
652 EFI_PHYSICAL_ADDRESS MapPyhAddr
;
654 UINTN ActualSendLength
;
661 Status
= EFI_SUCCESS
;
663 if (Data
== NULL
|| DataLength
== NULL
|| DataToggle
== NULL
|| TransferResult
== NULL
||
664 *DataLength
== 0 || (*DataToggle
!= 0 && *DataToggle
!= 1) ||
665 (MaxPacketLength
!= 8 && MaxPacketLength
!= 16 &&
666 MaxPacketLength
!= 32 && MaxPacketLength
!= 64)) {
667 return EFI_INVALID_PARAMETER
;
670 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
672 if ((EndPointAddress
& 0x80) != 0) {
673 DataPidDir
= TD_IN_PID
;
674 MapOp
= EfiPciIoOperationBusMasterWrite
;
676 DataPidDir
= TD_OUT_PID
;
677 MapOp
= EfiPciIoOperationBusMasterRead
;
680 EndPointNum
= (EndPointAddress
& 0xF);
681 EdResult
.NextToggle
= *DataToggle
;
683 Status
= OhciSetHcControl (Ohc
, BULK_ENABLE
, 0);
684 if (EFI_ERROR(Status
)) {
685 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));
686 *TransferResult
= EFI_USB_ERR_SYSTEM
;
687 return EFI_DEVICE_ERROR
;
689 Status
= OhciSetHcCommandStatus (Ohc
, BULK_LIST_FILLED
, 0);
690 if (EFI_ERROR(Status
)) {
691 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));
692 *TransferResult
= EFI_USB_ERR_SYSTEM
;
693 return EFI_DEVICE_ERROR
;
695 gBS
->Stall(20 * 1000);
697 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
699 Ed
= OhciCreateED (Ohc
);
701 return EFI_OUT_OF_RESOURCES
;
703 OhciSetEDField (Ed
, ED_SKIP
, 1);
704 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
705 OhciSetEDField (Ed
, ED_ENDPT_NUM
, EndPointNum
);
706 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
707 OhciSetEDField (Ed
, ED_SPEED
, HI_SPEED
);
708 OhciSetEDField (Ed
, ED_FORMAT
| ED_HALTED
| ED_DTTOGGLE
, 0);
709 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
710 OhciSetEDField (Ed
, ED_PDATA
, 0);
711 OhciSetEDField (Ed
, ED_ZERO
, 0);
712 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
713 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
714 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
715 HeadEd
= OhciAttachEDToList (Ohc
, BULK_LIST
, Ed
, NULL
);
718 MapLength
= *DataLength
;
719 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, (UINT8
*)Data
, &MapLength
, &MapPyhAddr
, &Mapping
);
720 if (EFI_ERROR(Status
)) {
721 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));
728 LeftLength
= MapLength
;
729 ActualSendLength
= MapLength
;
732 while (LeftLength
> 0) {
733 ActualSendLength
= LeftLength
;
734 if (LeftLength
> MaxPacketLength
) {
735 ActualSendLength
= MaxPacketLength
;
737 DataTd
= OhciCreateTD (Ohc
);
738 if (DataTd
== NULL
) {
739 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
740 Status
= EFI_OUT_OF_RESOURCES
;
741 goto FREE_OHCI_TDBUFF
;
743 OhciSetTDField (DataTd
, TD_PDATA
, 0);
744 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
745 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
746 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
747 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, *DataToggle
);
748 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
749 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
750 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) MapPyhAddr
);
751 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(MapPyhAddr
+ ActualSendLength
- 1));
752 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
753 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
754 DataTd
->DataBuffer
= (UINT32
)MapPyhAddr
;
755 DataTd
->NextTDPointer
= 0;
760 OhciLinkTD (HeadTd
, DataTd
);
763 MapPyhAddr
+= ActualSendLength
;
764 LeftLength
-= ActualSendLength
;
769 EmptyTd
= OhciCreateTD (Ohc
);
770 if (EmptyTd
== NULL
) {
771 Status
= EFI_OUT_OF_RESOURCES
;
772 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));
773 goto FREE_OHCI_TDBUFF
;
775 OhciSetTDField (EmptyTd
, TD_PDATA
, 0);
776 OhciSetTDField (EmptyTd
, TD_BUFFER_ROUND
, 0);
777 OhciSetTDField (EmptyTd
, TD_DIR_PID
, 0);
778 OhciSetTDField (EmptyTd
, TD_DELAY_INT
, 0);
779 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
780 EmptyTd
->Word0
.DataToggle
= 0;
781 OhciSetTDField (EmptyTd
, TD_ERROR_CNT
, 0);
782 OhciSetTDField (EmptyTd
, TD_COND_CODE
, 0);
783 OhciSetTDField (EmptyTd
, TD_CURR_BUFFER_PTR
, 0);
784 OhciSetTDField (EmptyTd
, TD_BUFFER_END_PTR
, 0);
785 OhciSetTDField (EmptyTd
, TD_NEXT_PTR
, 0);
786 EmptyTd
->ActualSendLength
= 0;
787 EmptyTd
->DataBuffer
= 0;
788 EmptyTd
->NextTDPointer
= 0;
789 OhciLinkTD (HeadTd
, EmptyTd
);
790 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptyTd
;
791 OhciAttachTDListToED (Ed
, HeadTd
);
793 OhciSetEDField (Ed
, ED_SKIP
, 0);
794 Status
= OhciSetHcCommandStatus (Ohc
, BULK_LIST_FILLED
, 1);
795 if (EFI_ERROR(Status
)) {
796 *TransferResult
= EFI_USB_ERR_SYSTEM
;
797 Status
= EFI_DEVICE_ERROR
;
798 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));
799 goto FREE_OHCI_TDBUFF
;
801 Status
= OhciSetHcControl (Ohc
, BULK_ENABLE
, 1);
802 if (EFI_ERROR(Status
)) {
803 *TransferResult
= EFI_USB_ERR_SYSTEM
;
804 Status
= EFI_DEVICE_ERROR
;
805 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));
806 goto FREE_OHCI_TDBUFF
;
808 gBS
->Stall(20 * 1000);
811 Status
= CheckIfDone (Ohc
, BULK_LIST
, Ed
, HeadTd
, &EdResult
);
812 while (Status
== EFI_NOT_READY
&& TimeCount
<= TimeOut
) {
815 Status
= CheckIfDone (Ohc
, BULK_LIST
, Ed
, HeadTd
, &EdResult
);
818 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
820 if (EdResult
.ErrorCode
!= TD_NO_ERROR
) {
821 if (EdResult
.ErrorCode
== TD_TOBE_PROCESSED
) {
822 DEBUG ((EFI_D_INFO
, "Bulk pipe timeout, > %d mS\r\n", TimeOut
));
824 DEBUG ((EFI_D_INFO
, "Bulk pipe broken\r\n"));
825 *DataToggle
= EdResult
.NextToggle
;
829 DEBUG ((EFI_D_INFO
, "Bulk transfer successed\r\n"));
831 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
834 OhciSetEDField (Ed
, ED_SKIP
, 1);
836 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
838 HeadEd
->NextED
= Ed
->NextED
;
842 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
843 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
846 if(Mapping
!= NULL
) {
847 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, Mapping
);
851 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
857 Submits an interrupt transfer to an interrupt endpoint of a USB device.
859 @param Ohc Device private data
860 @param DeviceAddress Represents the address of the target device on the USB,
861 which is assigned during USB enumeration.
862 @param EndPointAddress The combination of an endpoint number and an endpoint
863 direction of the target USB device. Each endpoint address
864 supports data transfer in one direction except the
865 control endpoint (whose default endpoint address is 0).
866 It is the caller's responsibility to make sure that
867 the EndPointAddress represents an interrupt endpoint.
868 @param IsSlowDevice Indicates whether the target device is slow device
869 or full-speed device.
870 @param MaxPacketLength Indicates the maximum packet size the target endpoint
871 is capable of sending or receiving.
872 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
873 the host and the target interrupt endpoint.
874 If FALSE, the specified asynchronous interrupt pipe
876 @param DataToggle A pointer to the data toggle value. On input, it is valid
877 when IsNewTransfer is TRUE, and it indicates the initial
878 data toggle value the asynchronous interrupt transfer
880 On output, it is valid when IsNewTransfer is FALSE,
881 and it is updated to indicate the data toggle value of
882 the subsequent asynchronous interrupt transfer.
883 @param PollingInterval Indicates the interval, in milliseconds, that the
884 asynchronous interrupt transfer is polled.
885 This parameter is required when IsNewTransfer is TRUE.
886 @param UCBuffer Uncacheable buffer
887 @param DataLength Indicates the length of data to be received at the
888 rate specified by PollingInterval from the target
889 asynchronous interrupt endpoint. This parameter
890 is only required when IsNewTransfer is TRUE.
891 @param CallBackFunction The Callback function.This function is called at the
892 rate specified by PollingInterval.This parameter is
893 only required when IsNewTransfer is TRUE.
894 @param Context The context that is passed to the CallBackFunction.
895 This is an optional parameter and may be NULL.
896 @param IsPeriodic Periodic interrupt or not
897 @param OutputED The correspoding ED carried out
898 @param OutputTD The correspoding TD carried out
901 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
902 submitted or canceled.
903 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
904 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
909 OhciInterruptTransfer (
910 IN USB_OHCI_HC_DEV
*Ohc
,
911 IN UINT8 DeviceAddress
,
912 IN UINT8 EndPointAddress
,
913 IN BOOLEAN IsSlowDevice
,
914 IN UINT8 MaxPacketLength
,
915 IN BOOLEAN IsNewTransfer
,
916 IN OUT UINT8
*DataToggle OPTIONAL
,
917 IN UINTN PollingInterval OPTIONAL
,
918 IN VOID
*UCBuffer OPTIONAL
,
919 IN UINTN DataLength OPTIONAL
,
920 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL
,
921 IN VOID
*Context OPTIONAL
,
922 IN BOOLEAN IsPeriodic OPTIONAL
,
923 OUT ED_DESCRIPTOR
**OutputED OPTIONAL
,
924 OUT TD_DESCRIPTOR
**OutputTD OPTIONAL
929 ED_DESCRIPTOR
*HeadEd
;
930 TD_DESCRIPTOR
*HeadTd
;
931 TD_DESCRIPTOR
*DataTd
;
932 TD_DESCRIPTOR
*EmptTd
;
938 INTERRUPT_CONTEXT_ENTRY
*Entry
;
944 EFI_PHYSICAL_ADDRESS MapPyhAddr
;
946 UINTN ActualSendLength
;
949 if (DataLength
> MAX_BYTES_PER_TD
) {
950 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Error param\r\n"));
951 return EFI_INVALID_PARAMETER
;
954 if ((EndPointAddress
& 0x80) != 0) {
956 DataPidDir
= TD_IN_PID
;
959 DataPidDir
= TD_OUT_PID
;
962 EndPointNum
= (EndPointAddress
& 0xF);
964 if (!IsNewTransfer
) {
965 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
966 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 0);
967 OhciFreeInterruptContext (Ohc
, DeviceAddress
, EndPointAddress
, DataToggle
);
968 Status
= OhciFreeInterruptEdByAddr (Ohc
, DeviceAddress
, EndPointNum
);
969 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 1);
970 gBS
->RestoreTPL (OldTpl
);
973 MapLength
= DataLength
;
974 Status
= Ohc
->PciIo
->Map(
976 EfiPciIoOperationBusMasterWrite
,
982 if (EFI_ERROR (Status
)) {
983 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));
988 while (PollingInterval
>= Index
* 2 && Depth
> 0) {
995 HeadEd
= OhciFindMinInterruptEDList (Ohc
, (UINT32
)Depth
);
996 if ((Ed
= OhciFindWorkingEd (HeadEd
, DeviceAddress
, EndPointNum
, EdDir
)) != NULL
) {
997 OhciSetEDField (Ed
, ED_SKIP
, 1);
999 Ed
= OhciCreateED (Ohc
);
1001 Status
= EFI_OUT_OF_RESOURCES
;
1002 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));
1003 goto UNMAP_OHCI_XBUFF
;
1005 OhciSetEDField (Ed
, ED_SKIP
, 1);
1006 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
1007 OhciSetEDField (Ed
, ED_ENDPT_NUM
, EndPointNum
);
1008 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
1009 OhciSetEDField (Ed
, ED_SPEED
, IsSlowDevice
);
1010 OhciSetEDField (Ed
, ED_FORMAT
, 0);
1011 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
1012 OhciSetEDField (Ed
, ED_PDATA
| ED_ZERO
| ED_HALTED
| ED_DTTOGGLE
, 0);
1013 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
1014 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
1015 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
1016 OhciAttachEDToList (Ohc
, INTERRUPT_LIST
, Ed
, HeadEd
);
1021 LeftLength
= MapLength
;
1022 ActualSendLength
= MapLength
;
1025 while (LeftLength
> 0) {
1026 ActualSendLength
= LeftLength
;
1027 if (LeftLength
> MaxPacketLength
) {
1028 ActualSendLength
= MaxPacketLength
;
1030 DataTd
= OhciCreateTD (Ohc
);
1031 if (DataTd
== NULL
) {
1032 Status
= EFI_OUT_OF_RESOURCES
;
1033 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
1034 goto FREE_OHCI_TDBUFF
;
1036 OhciSetTDField (DataTd
, TD_PDATA
, 0);
1037 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
1038 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
1039 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
1040 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, *DataToggle
);
1041 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
1042 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
1043 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) MapPyhAddr
);
1044 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(MapPyhAddr
+ ActualSendLength
- 1));
1045 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
1046 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
1047 DataTd
->DataBuffer
= (UINT32
)MapPyhAddr
;
1048 DataTd
->NextTDPointer
= 0;
1053 OhciLinkTD (HeadTd
, DataTd
);
1056 MapPyhAddr
+= ActualSendLength
;
1057 LeftLength
-= ActualSendLength
;
1060 EmptTd
= OhciCreateTD (Ohc
);
1061 if (EmptTd
== NULL
) {
1062 Status
= EFI_OUT_OF_RESOURCES
;
1063 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));
1064 goto FREE_OHCI_TDBUFF
;
1066 OhciSetTDField (EmptTd
, TD_PDATA
, 0);
1067 OhciSetTDField (EmptTd
, TD_BUFFER_ROUND
, 0);
1068 OhciSetTDField (EmptTd
, TD_DIR_PID
, 0);
1069 OhciSetTDField (EmptTd
, TD_DELAY_INT
, 0);
1070 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);
1071 EmptTd
->Word0
.DataToggle
= 0;
1072 OhciSetTDField (EmptTd
, TD_ERROR_CNT
, 0);
1073 OhciSetTDField (EmptTd
, TD_COND_CODE
, 0);
1074 OhciSetTDField (EmptTd
, TD_CURR_BUFFER_PTR
, 0);
1075 OhciSetTDField (EmptTd
, TD_BUFFER_END_PTR
, 0);
1076 OhciSetTDField (EmptTd
, TD_NEXT_PTR
, 0);
1077 EmptTd
->ActualSendLength
= 0;
1078 EmptTd
->DataBuffer
= 0;
1079 EmptTd
->NextTDPointer
= 0;
1080 OhciLinkTD (HeadTd
, EmptTd
);
1081 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptTd
;
1082 OhciAttachTDListToED (Ed
, HeadTd
);
1084 if (OutputED
!= NULL
) {
1087 if (OutputTD
!= NULL
) {
1091 if (CallBackFunction
!= NULL
) {
1092 Entry
= AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY
));
1093 if (Entry
== NULL
) {
1094 goto FREE_OHCI_TDBUFF
;
1097 Entry
->DeviceAddress
= DeviceAddress
;
1098 Entry
->EndPointAddress
= EndPointAddress
;
1100 Entry
->DataTd
= HeadTd
;
1101 Entry
->IsSlowDevice
= IsSlowDevice
;
1102 Entry
->MaxPacketLength
= MaxPacketLength
;
1103 Entry
->PollingInterval
= PollingInterval
;
1104 Entry
->CallBackFunction
= CallBackFunction
;
1105 Entry
->Context
= Context
;
1106 Entry
->IsPeriodic
= IsPeriodic
;
1107 Entry
->UCBuffer
= UCBuffer
;
1108 Entry
->UCBufferMapping
= Mapping
;
1109 Entry
->DataLength
= DataLength
;
1110 Entry
->Toggle
= DataToggle
;
1111 Entry
->NextEntry
= NULL
;
1112 OhciAddInterruptContextEntry (Ohc
, Entry
);
1114 OhciSetEDField (Ed
, ED_SKIP
, 0);
1116 if (OhciGetHcControl (Ohc
, PERIODIC_ENABLE
) == 0) {
1117 Status
= OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 1);
1126 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
1127 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
1131 if ((HeadEd
!= Ed
) && HeadEd
&& Ed
) {
1132 while(HeadEd
->NextED
!= (UINT32
)(UINTN
)Ed
) {
1133 HeadEd
= (ED_DESCRIPTOR
*)(UINTN
)(HeadEd
->NextED
);
1135 HeadEd
->NextED
= Ed
->NextED
;
1136 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
1140 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, Mapping
);
1148 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
1150 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1151 @param DeviceAddress Represents the address of the target device on the USB,
1152 which is assigned during USB enumeration.
1153 @param EndPointAddress The combination of an endpoint number and an endpoint
1154 direction of the target USB device. Each endpoint address
1155 supports data transfer in one direction except the
1156 control endpoint (whose default endpoint address is 0).
1157 It is the caller's responsibility to make sure that
1158 the EndPointAddress represents an interrupt endpoint.
1159 @param IsSlowDevice Indicates whether the target device is slow device
1160 or full-speed device.
1161 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint
1162 is capable of sending or receiving.
1163 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
1164 the host and the target interrupt endpoint.
1165 If FALSE, the specified asynchronous interrupt pipe
1167 @param DataToggle A pointer to the data toggle value. On input, it is valid
1168 when IsNewTransfer is TRUE, and it indicates the initial
1169 data toggle value the asynchronous interrupt transfer
1171 On output, it is valid when IsNewTransfer is FALSE,
1172 and it is updated to indicate the data toggle value of
1173 the subsequent asynchronous interrupt transfer.
1174 @param PollingInterval Indicates the interval, in milliseconds, that the
1175 asynchronous interrupt transfer is polled.
1176 This parameter is required when IsNewTransfer is TRUE.
1177 @param DataLength Indicates the length of data to be received at the
1178 rate specified by PollingInterval from the target
1179 asynchronous interrupt endpoint. This parameter
1180 is only required when IsNewTransfer is TRUE.
1181 @param CallBackFunction The Callback function.This function is called at the
1182 rate specified by PollingInterval.This parameter is
1183 only required when IsNewTransfer is TRUE.
1184 @param Context The context that is passed to the CallBackFunction.
1185 This is an optional parameter and may be NULL.
1187 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
1188 submitted or canceled.
1189 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1190 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1197 OhciAsyncInterruptTransfer (
1198 IN EFI_USB_HC_PROTOCOL
*This
,
1199 IN UINT8 DeviceAddress
,
1200 IN UINT8 EndPointAddress
,
1201 IN BOOLEAN IsSlowDevice
,
1202 IN UINT8 MaxPacketLength
,
1203 IN BOOLEAN IsNewTransfer
,
1204 IN OUT UINT8
*DataToggle OPTIONAL
,
1205 IN UINTN PollingInterval OPTIONAL
,
1206 IN UINTN DataLength OPTIONAL
,
1207 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL
,
1208 IN VOID
*Context OPTIONAL
1212 USB_OHCI_HC_DEV
*Ohc
;
1215 if (DataToggle
== NULL
|| (EndPointAddress
& 0x80) == 0 ||
1216 (IsNewTransfer
&& (DataLength
== 0 ||
1217 (*DataToggle
!= 0 && *DataToggle
!= 1) || (PollingInterval
< 1 || PollingInterval
> 255)))) {
1218 return EFI_INVALID_PARAMETER
;
1221 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1222 if ( IsNewTransfer
) {
1223 UCBuffer
= AllocatePool(DataLength
);
1224 if (UCBuffer
== NULL
) {
1225 return EFI_OUT_OF_RESOURCES
;
1230 Status
= OhciInterruptTransfer (
1247 if ( IsNewTransfer
) {
1248 if (EFI_ERROR(Status
)) {
1249 gBS
->FreePool (UCBuffer
);
1258 Submits synchronous interrupt transfer to an interrupt endpoint
1261 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1262 @param DeviceAddress Represents the address of the target device on the USB,
1263 which is assigned during USB enumeration.
1264 @param EndPointAddress The combination of an endpoint number and an endpoint
1265 direction of the target USB device. Each endpoint
1266 address supports data transfer in one direction
1267 except the control endpoint (whose default
1268 endpoint address is 0). It is the caller's responsibility
1269 to make sure that the EndPointAddress represents
1270 an interrupt endpoint.
1271 @param IsSlowDevice Indicates whether the target device is slow device
1272 or full-speed device.
1273 @param MaxPacketLength Indicates the maximum packet size the target endpoint
1274 is capable of sending or receiving.
1275 @param Data A pointer to the buffer of data that will be transmitted
1276 to USB device or received from USB device.
1277 @param DataLength On input, the size, in bytes, of the data buffer specified
1278 by Data. On output, the number of bytes transferred.
1279 @param DataToggle A pointer to the data toggle value. On input, it indicates
1280 the initial data toggle value the synchronous interrupt
1281 transfer should adopt;
1282 on output, it is updated to indicate the data toggle value
1283 of the subsequent synchronous interrupt transfer.
1284 @param TimeOut Indicates the maximum time, in microseconds, which the
1285 transfer is allowed to complete.
1286 @param TransferResult A pointer to the detailed result information from
1287 the synchronous interrupt transfer.
1289 @retval EFI_UNSUPPORTED This interface not available.
1290 @retval EFI_INVALID_PARAMETER Parameters not follow spec
1297 OhciSyncInterruptTransfer (
1298 IN EFI_USB_HC_PROTOCOL
*This
,
1299 IN UINT8 DeviceAddress
,
1300 IN UINT8 EndPointAddress
,
1301 IN BOOLEAN IsSlowDevice
,
1302 IN UINT8 MaxPacketLength
,
1304 IN OUT UINTN
*DataLength
,
1305 IN OUT UINT8
*DataToggle
,
1307 OUT UINT32
*TransferResult
1310 USB_OHCI_HC_DEV
*Ohc
;
1313 TD_DESCRIPTOR
*HeadTd
;
1314 OHCI_ED_RESULT EdResult
;
1317 if ((EndPointAddress
& 0x80) == 0 || Data
== NULL
|| DataLength
== NULL
|| *DataLength
== 0 ||
1318 (IsSlowDevice
&& MaxPacketLength
> 8) || (!IsSlowDevice
&& MaxPacketLength
> 64) ||
1319 DataToggle
== NULL
|| (*DataToggle
!= 0 && *DataToggle
!= 1) || TransferResult
== NULL
) {
1320 return EFI_INVALID_PARAMETER
;
1323 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1324 UCBuffer
= AllocatePool (*DataLength
);
1325 if (UCBuffer
== NULL
) {
1326 return EFI_OUT_OF_RESOURCES
;
1328 Status
= OhciInterruptTransfer (
1346 if (!EFI_ERROR (Status
)) {
1347 Status
= CheckIfDone (Ohc
, INTERRUPT_LIST
, Ed
, HeadTd
, &EdResult
);
1348 while (Status
== EFI_NOT_READY
&& TimeOut
> 0) {
1351 Status
= CheckIfDone (Ohc
, INTERRUPT_LIST
, Ed
, HeadTd
, &EdResult
);
1354 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
1356 CopyMem(Data
, UCBuffer
, *DataLength
);
1357 Status
= OhciInterruptTransfer (
1379 Submits isochronous transfer to a target USB device.
1381 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1382 @param DeviceAddress Represents the address of the target device on the USB,
1383 which is assigned during USB enumeration.
1384 @param EndPointAddress End point address
1385 @param MaximumPacketLength Indicates the maximum packet size that the
1386 default control transfer endpoint is capable of
1387 sending or receiving.
1388 @param Data A pointer to the buffer of data that will be transmitted
1389 to USB device or received from USB device.
1390 @param DataLength Indicates the size, in bytes, of the data buffer
1392 @param TransferResult A pointer to the detailed result information generated
1393 by this control transfer.
1395 @retval EFI_UNSUPPORTED This interface not available
1396 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
1403 OhciIsochronousTransfer (
1404 IN EFI_USB_HC_PROTOCOL
*This
,
1405 IN UINT8 DeviceAddress
,
1406 IN UINT8 EndPointAddress
,
1407 IN UINT8 MaximumPacketLength
,
1409 IN OUT UINTN DataLength
,
1410 OUT UINT32
*TransferResult
1413 if (Data
== NULL
|| DataLength
== 0 || TransferResult
== NULL
) {
1414 return EFI_INVALID_PARAMETER
;
1417 return EFI_UNSUPPORTED
;
1422 Submits Async isochronous transfer to a target USB device.
1424 @param his A pointer to the EFI_USB_HC_PROTOCOL instance.
1425 @param DeviceAddress Represents the address of the target device on the USB,
1426 which is assigned during USB enumeration.
1427 @param EndPointAddress End point address
1428 @param MaximumPacketLength Indicates the maximum packet size that the
1429 default control transfer endpoint is capable of
1430 sending or receiving.
1431 @param Data A pointer to the buffer of data that will be transmitted
1432 to USB device or received from USB device.
1433 @param IsochronousCallBack When the transfer complete, the call back function will be called
1434 @param Context Pass to the call back function as parameter
1436 @retval EFI_UNSUPPORTED This interface not available
1437 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
1443 OhciAsyncIsochronousTransfer (
1444 IN EFI_USB_HC_PROTOCOL
*This
,
1445 IN UINT8 DeviceAddress
,
1446 IN UINT8 EndPointAddress
,
1447 IN UINT8 MaximumPacketLength
,
1449 IN OUT UINTN DataLength
,
1450 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1451 IN VOID
*Context OPTIONAL
1455 if (Data
== NULL
|| DataLength
== 0) {
1456 return EFI_INVALID_PARAMETER
;
1459 return EFI_UNSUPPORTED
;
1464 Retrieves the number of root hub ports.
1466 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1467 @param NumOfPorts A pointer to the number of the root hub ports.
1469 @retval EFI_SUCCESS The port number was retrieved successfully.
1473 OhciGetRootHubNumOfPorts (
1474 IN EFI_USB_HC_PROTOCOL
*This
,
1475 OUT UINT8
*NumOfPorts
1478 USB_OHCI_HC_DEV
*Ohc
;
1479 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1481 if (NumOfPorts
== NULL
) {
1482 return EFI_INVALID_PARAMETER
;
1485 *NumOfPorts
= (UINT8
)OhciGetRootHubDescriptor(Ohc
, RH_NUM_DS_PORTS
);
1491 Retrieves the current status of a USB root hub port.
1493 @param This A pointer to the EFI_USB_HC_PROTOCOL.
1494 @param PortNumber Specifies the root hub port from which the status
1495 is to be retrieved. This value is zero-based. For example,
1496 if a root hub has two ports, then the first port is numbered 0,
1497 and the second port is numbered 1.
1498 @param PortStatus A pointer to the current port status bits and
1499 port status change bits.
1501 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber
1502 was returned in PortStatus.
1503 @retval EFI_INVALID_PARAMETER Port number not valid
1509 OhciGetRootHubPortStatus (
1510 IN EFI_USB_HC_PROTOCOL
*This
,
1511 IN UINT8 PortNumber
,
1512 OUT EFI_USB_PORT_STATUS
*PortStatus
1515 USB_OHCI_HC_DEV
*Ohc
;
1518 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1520 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1521 if (PortNumber
>= NumOfPorts
) {
1522 return EFI_INVALID_PARAMETER
;
1524 PortStatus
->PortStatus
= 0;
1525 PortStatus
->PortChangeStatus
= 0;
1527 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_CURR_CONNECT_STAT
)) {
1528 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
1530 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_ENABLE_STAT
)) {
1531 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
1533 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_SUSPEND_STAT
)) {
1534 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
1536 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_OC_INDICATOR
)) {
1537 PortStatus
->PortStatus
|= USB_PORT_STAT_OVERCURRENT
;
1539 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_RESET_STAT
)) {
1540 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
1542 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_POWER_STAT
)) {
1543 PortStatus
->PortStatus
|= USB_PORT_STAT_POWER
;
1545 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_LSDEVICE_ATTACHED
)) {
1546 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
1548 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
)) {
1549 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
1551 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
)) {
1552 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
1554 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
)) {
1555 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_SUSPEND
;
1557 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
)) {
1558 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_OVERCURRENT
;
1560 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
)) {
1561 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_RESET
;
1568 Sets a feature for the specified root hub port.
1570 @param This A pointer to the EFI_USB_HC_PROTOCOL.
1571 @param PortNumber Specifies the root hub port whose feature
1572 is requested to be set.
1573 @param PortFeature Indicates the feature selector associated
1574 with the feature set request.
1576 @retval EFI_SUCCESS The feature specified by PortFeature was set for the
1577 USB root hub port specified by PortNumber.
1578 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue
1579 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1583 OhciSetRootHubPortFeature (
1584 IN EFI_USB_HC_PROTOCOL
*This
,
1585 IN UINT8 PortNumber
,
1586 IN EFI_USB_PORT_FEATURE PortFeature
1589 USB_OHCI_HC_DEV
*Ohc
;
1594 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1595 if (PortNumber
>= NumOfPorts
) {
1596 return EFI_INVALID_PARAMETER
;
1599 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1601 Status
= EFI_SUCCESS
;
1604 switch (PortFeature
) {
1605 case EfiUsbPortPower
:
1606 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_POWER
);
1615 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_POWER_STAT
) == 0 &&
1616 RetryTimes
< MAX_RETRY_TIMES
);
1618 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1619 return EFI_DEVICE_ERROR
;
1623 case EfiUsbPortReset
:
1624 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_RESET
);
1633 } while ((OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
) == 0 ||
1634 OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT
) == 1) &&
1635 RetryTimes
< MAX_RETRY_TIMES
);
1637 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1638 return EFI_DEVICE_ERROR
;
1641 OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
);
1644 case EfiUsbPortEnable
:
1645 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_ENABLE
);
1654 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT
) == 0 &&
1655 RetryTimes
< MAX_RETRY_TIMES
);
1657 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1658 return EFI_DEVICE_ERROR
;
1663 case EfiUsbPortSuspend
:
1664 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_SUSPEND
);
1673 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT
) == 0 &&
1674 RetryTimes
< MAX_RETRY_TIMES
);
1676 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1677 return EFI_DEVICE_ERROR
;
1682 return EFI_INVALID_PARAMETER
;
1690 Clears a feature for the specified root hub port.
1692 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1693 @param PortNumber Specifies the root hub port whose feature
1694 is requested to be cleared.
1695 @param PortFeature Indicates the feature selector associated with the
1696 feature clear request.
1698 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the
1699 USB root hub port specified by PortNumber.
1700 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1701 @retval EFI_DEVICE_ERROR Some error happened when clearing feature
1705 OhciClearRootHubPortFeature (
1706 IN EFI_USB_HC_PROTOCOL
*This
,
1707 IN UINT8 PortNumber
,
1708 IN EFI_USB_PORT_FEATURE PortFeature
1711 USB_OHCI_HC_DEV
*Ohc
;
1717 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1718 if (PortNumber
>= NumOfPorts
) {
1719 return EFI_INVALID_PARAMETER
;
1722 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1724 Status
= EFI_SUCCESS
;
1726 switch (PortFeature
) {
1727 case EfiUsbPortEnable
:
1728 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_PORT_ENABLE
);
1737 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT
) == 1 &&
1738 RetryTimes
< MAX_RETRY_TIMES
);
1740 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1741 return EFI_DEVICE_ERROR
;
1745 case EfiUsbPortSuspend
:
1746 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_SUSPEND_STATUS
);
1755 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT
) == 1 &&
1756 RetryTimes
< MAX_RETRY_TIMES
);
1758 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1759 return EFI_DEVICE_ERROR
;
1763 case EfiUsbPortReset
:
1766 case EfiUsbPortPower
:
1767 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_PORT_POWER
);
1776 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_POWER_STAT
) == 1 &&
1777 RetryTimes
< MAX_RETRY_TIMES
);
1779 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1780 return EFI_DEVICE_ERROR
;
1784 case EfiUsbPortConnectChange
:
1785 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
);
1794 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
) == 1 &&
1795 RetryTimes
< MAX_RETRY_TIMES
);
1797 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1798 return EFI_DEVICE_ERROR
;
1802 case EfiUsbPortResetChange
:
1803 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
);
1812 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
) == 1 &&
1813 RetryTimes
< MAX_RETRY_TIMES
);
1815 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1816 return EFI_DEVICE_ERROR
;
1821 case EfiUsbPortEnableChange
:
1822 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
);
1831 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
) == 1 &&
1832 RetryTimes
< MAX_RETRY_TIMES
);
1834 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1835 return EFI_DEVICE_ERROR
;
1839 case EfiUsbPortSuspendChange
:
1840 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
);
1849 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
) == 1 &&
1850 RetryTimes
< MAX_RETRY_TIMES
);
1852 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1853 return EFI_DEVICE_ERROR
;
1857 case EfiUsbPortOverCurrentChange
:
1858 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
);
1867 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
) == 1 &&
1868 RetryTimes
< MAX_RETRY_TIMES
);
1870 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1871 return EFI_DEVICE_ERROR
;
1876 return EFI_INVALID_PARAMETER
;
1882 EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding
= {
1883 OHCIDriverBindingSupported
,
1884 OHCIDriverBindingStart
,
1885 OHCIDriverBindingStop
,
1893 Entry point for EFI drivers.
1895 @param ImageHandle EFI_HANDLE.
1896 @param SystemTable EFI_SYSTEM_TABLE.
1898 @retval EFI_SUCCESS Driver is successfully loaded.
1899 @return Others Failed.
1904 OHCIDriverEntryPoint (
1905 IN EFI_HANDLE ImageHandle
,
1906 IN EFI_SYSTEM_TABLE
*SystemTable
1909 return EfiLibInstallDriverBindingComponentName2 (
1912 &gOhciDriverBinding
,
1914 &gOhciComponentName
,
1915 &gOhciComponentName2
1921 Test to see if this driver supports ControllerHandle. Any
1922 ControllerHandle that has UsbHcProtocol installed will be supported.
1924 @param This Protocol instance pointer.
1925 @param Controller Handle of device to test.
1926 @param RemainingDevicePath Not used.
1928 @return EFI_SUCCESS This driver supports this device.
1929 @return EFI_UNSUPPORTED This driver does not support this device.
1934 OHCIDriverBindingSupported (
1935 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1936 IN EFI_HANDLE Controller
,
1937 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1941 EFI_PCI_IO_PROTOCOL
*PciIo
;
1942 USB_CLASSC UsbClassCReg
;
1944 // Test whether there is PCI IO Protocol attached on the controller handle.
1946 Status
= gBS
->OpenProtocol (
1948 &gEfiPciIoProtocolGuid
,
1950 This
->DriverBindingHandle
,
1952 EFI_OPEN_PROTOCOL_BY_DRIVER
1955 if (EFI_ERROR (Status
)) {
1956 return EFI_UNSUPPORTED
;
1959 Status
= PciIo
->Pci
.Read (
1962 PCI_CLASSCODE_OFFSET
,
1963 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1967 if (EFI_ERROR (Status
)) {
1968 Status
= EFI_UNSUPPORTED
;
1972 // Test whether the controller belongs to OHCI type
1974 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) ||
1975 (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
) ||
1976 (UsbClassCReg
.ProgInterface
!= PCI_IF_OHCI
)
1979 Status
= EFI_UNSUPPORTED
;
1982 gBS
->CloseProtocol (
1984 &gEfiPciIoProtocolGuid
,
1985 This
->DriverBindingHandle
,
1995 Allocate and initialize the empty OHCI device.
1997 @param PciIo The PCIIO to use.
1998 @param OriginalPciAttributes The original PCI attributes.
2000 @return Allocated OHCI device If err, return NULL.
2006 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2007 IN UINT64 OriginalPciAttributes
2010 USB_OHCI_HC_DEV
*Ohc
;
2013 EFI_PHYSICAL_ADDRESS PhyAddr
;
2018 Ohc
= AllocateZeroPool (sizeof (USB_OHCI_HC_DEV
));
2023 Ohc
->Signature
= USB_OHCI_HC_DEV_SIGNATURE
;
2026 Ohc
->UsbHc
.Reset
= OhciReset
;
2027 Ohc
->UsbHc
.GetState
= OhciGetState
;
2028 Ohc
->UsbHc
.SetState
= OhciSetState
;
2029 Ohc
->UsbHc
.ControlTransfer
= OhciControlTransfer
;
2030 Ohc
->UsbHc
.BulkTransfer
= OhciBulkTransfer
;
2031 Ohc
->UsbHc
.AsyncInterruptTransfer
= OhciAsyncInterruptTransfer
;
2032 Ohc
->UsbHc
.SyncInterruptTransfer
= OhciSyncInterruptTransfer
;
2033 Ohc
->UsbHc
.IsochronousTransfer
= OhciIsochronousTransfer
;
2034 Ohc
->UsbHc
.AsyncIsochronousTransfer
= OhciAsyncIsochronousTransfer
;
2035 Ohc
->UsbHc
.GetRootHubPortNumber
= OhciGetRootHubNumOfPorts
;
2036 Ohc
->UsbHc
.GetRootHubPortStatus
= OhciGetRootHubPortStatus
;
2037 Ohc
->UsbHc
.SetRootHubPortFeature
= OhciSetRootHubPortFeature
;
2038 Ohc
->UsbHc
.ClearRootHubPortFeature
= OhciClearRootHubPortFeature
;
2039 Ohc
->UsbHc
.MajorRevision
= 0x1;
2040 Ohc
->UsbHc
.MinorRevision
= 0x1;
2042 Ohc
->OriginalPciAttributes
= OriginalPciAttributes
;
2044 Ohc
->HccaMemoryBlock
= NULL
;
2045 Ohc
->HccaMemoryMapping
= NULL
;
2046 Ohc
->HccaMemoryBuf
= NULL
;
2047 Ohc
->HccaMemoryPages
= 0;
2048 Ohc
->InterruptContextList
= NULL
;
2049 Ohc
->ControllerNameTable
= NULL
;
2050 Ohc
->HouseKeeperTimer
= NULL
;
2052 Ohc
->MemPool
= UsbHcInitMemPool(PciIo
, TRUE
, 0);
2053 if(Ohc
->MemPool
== NULL
) {
2054 goto FREE_DEV_BUFFER
;
2058 Pages
= EFI_SIZE_TO_PAGES (Bytes
);
2060 Status
= PciIo
->AllocateBuffer (
2063 EfiBootServicesData
,
2069 if (EFI_ERROR (Status
)) {
2073 Status
= PciIo
->Map (
2075 EfiPciIoOperationBusMasterCommonBuffer
,
2082 if (EFI_ERROR (Status
) || (Bytes
!= 4096)) {
2086 Ohc
->HccaMemoryBlock
= (HCCA_MEMORY_BLOCK
*)(UINTN
)PhyAddr
;
2087 Ohc
->HccaMemoryMapping
= Map
;
2088 Ohc
->HccaMemoryBuf
= (VOID
*)(UINTN
)Buf
;
2089 Ohc
->HccaMemoryPages
= Pages
;
2094 PciIo
->FreeBuffer (PciIo
, Pages
, Buf
);
2096 UsbHcFreeMemPool (Ohc
->MemPool
);
2104 Free the OHCI device and release its associated resources.
2106 @param Ohc The OHCI device to release.
2111 IN USB_OHCI_HC_DEV
*Ohc
2114 OhciFreeFixedIntMemory (Ohc
);
2116 if (Ohc
->HouseKeeperTimer
!= NULL
) {
2117 gBS
->CloseEvent (Ohc
->HouseKeeperTimer
);
2120 if (Ohc
->ExitBootServiceEvent
!= NULL
) {
2121 gBS
->CloseEvent (Ohc
->ExitBootServiceEvent
);
2124 if (Ohc
->MemPool
!= NULL
) {
2125 UsbHcFreeMemPool (Ohc
->MemPool
);
2128 if (Ohc
->HccaMemoryMapping
!= NULL
) {
2129 Ohc
->PciIo
->FreeBuffer (Ohc
->PciIo
, Ohc
->HccaMemoryPages
, Ohc
->HccaMemoryBuf
);
2132 if (Ohc
->ControllerNameTable
!= NULL
) {
2133 FreeUnicodeStringTable (Ohc
->ControllerNameTable
);
2140 Uninstall all Ohci Interface.
2142 @param Controller Controller handle.
2143 @param This Protocol instance pointer.
2148 IN EFI_HANDLE Controller
,
2149 IN EFI_USB_HC_PROTOCOL
*This
2152 USB_OHCI_HC_DEV
*Ohc
;
2155 // Retrieve private context structure
2157 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
2160 // Uninstall the USB_HC and USB_HC2 protocol
2162 gBS
->UninstallProtocolInterface (
2164 &gEfiUsbHcProtocolGuid
,
2169 // Cancel the timer event
2171 gBS
->SetTimer (Ohc
->HouseKeeperTimer
, TimerCancel
, 0);
2174 // Stop the host controller
2176 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| ISOCHRONOUS_ENABLE
| BULK_ENABLE
, 0);
2177 This
->Reset (This
, EFI_USB_HC_RESET_GLOBAL
);
2178 This
->SetState (This
, EfiUsbHcStateHalt
);
2183 OhciFreeDynamicIntMemory (Ohc
);
2186 // Restore original PCI attributes
2188 Ohc
->PciIo
->Attributes (
2190 EfiPciIoAttributeOperationSet
,
2191 Ohc
->OriginalPciAttributes
,
2196 // Free the private context structure
2203 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
2205 @param Event Pointer to this event
2206 @param Context Event hanlder private data
2210 OhcExitBootService (
2215 USB_OHCI_HC_DEV
*Ohc
;
2216 EFI_USB_HC_PROTOCOL
*UsbHc
;
2217 Ohc
= (USB_OHCI_HC_DEV
*) Context
;
2219 UsbHc
= &Ohc
->UsbHc
;
2221 // Stop the Host Controller
2223 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);
2224 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| ISOCHRONOUS_ENABLE
| BULK_ENABLE
, 0);
2225 UsbHc
->Reset (UsbHc
, EFI_USB_HC_RESET_GLOBAL
);
2226 UsbHc
->SetState (UsbHc
, EfiUsbHcStateHalt
);
2233 Starting the Usb OHCI Driver.
2235 @param This Protocol instance pointer.
2236 @param Controller Handle of device to test.
2237 @param RemainingDevicePath Not used.
2239 @retval EFI_SUCCESS This driver supports this device.
2240 @retval EFI_UNSUPPORTED This driver does not support this device.
2241 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
2242 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
2247 OHCIDriverBindingStart (
2248 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2249 IN EFI_HANDLE Controller
,
2250 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
2254 EFI_PCI_IO_PROTOCOL
*PciIo
;
2255 USB_OHCI_HC_DEV
*Ohc
;
2257 UINT64 OriginalPciAttributes
;
2258 BOOLEAN PciAttributesSaved
;
2261 // Open PCIIO, then enable the HC device and turn off emulation
2264 Status
= gBS
->OpenProtocol (
2266 &gEfiPciIoProtocolGuid
,
2268 This
->DriverBindingHandle
,
2270 EFI_OPEN_PROTOCOL_BY_DRIVER
2273 if (EFI_ERROR (Status
)) {
2277 PciAttributesSaved
= FALSE
;
2279 // Save original PCI attributes
2281 Status
= PciIo
->Attributes (
2283 EfiPciIoAttributeOperationGet
,
2285 &OriginalPciAttributes
2288 if (EFI_ERROR (Status
)) {
2291 PciAttributesSaved
= TRUE
;
2294 // Robustnesss improvement such as for UoL
2295 // Default is not required.
2297 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
2298 // OhciTurnOffUsbEmulation (PciIo);
2301 Status
= PciIo
->Attributes (
2303 EfiPciIoAttributeOperationSupported
,
2307 if (!EFI_ERROR (Status
)) {
2308 Supports
&= EFI_PCI_DEVICE_ENABLE
;
2309 Status
= PciIo
->Attributes (
2311 EfiPciIoAttributeOperationEnable
,
2317 if (EFI_ERROR (Status
)) {
2321 //Allocate memory for OHC private data structure
2323 Ohc
= OhciAllocateDev(PciIo
, OriginalPciAttributes
);
2325 Status
= EFI_OUT_OF_RESOURCES
;
2329 //Status = OhciInitializeInterruptList ( Uhc );
2330 //if (EFI_ERROR (Status)) {
2337 Status
= gBS
->CreateEvent (
2338 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
2342 &Ohc
->HouseKeeperTimer
2344 if (EFI_ERROR (Status
)) {
2348 Status
= gBS
->SetTimer (Ohc
->HouseKeeperTimer
, TimerPeriodic
, 10 * 1000 * 10);
2349 if (EFI_ERROR (Status
)) {
2354 //Install Host Controller Protocol
2356 Status
= gBS
->InstallProtocolInterface (
2358 &gEfiUsbHcProtocolGuid
,
2359 EFI_NATIVE_INTERFACE
,
2362 if (EFI_ERROR (Status
)) {
2363 DEBUG ((EFI_D_INFO
, "Install protocol error"));
2367 // Create event to stop the HC when exit boot service.
2369 Status
= gBS
->CreateEventEx (
2374 &gEfiEventExitBootServicesGuid
,
2375 &Ohc
->ExitBootServiceEvent
2377 if (EFI_ERROR (Status
)) {
2378 DEBUG ((EFI_D_INFO
, "Create exit boot event error"));
2379 goto UNINSTALL_USBHC
;
2383 gOhciComponentName
.SupportedLanguages
,
2384 &Ohc
->ControllerNameTable
,
2385 L
"Usb Universal Host Controller",
2390 gOhciComponentName2
.SupportedLanguages
,
2391 &Ohc
->ControllerNameTable
,
2392 L
"Usb Universal Host Controller",
2399 gBS
->UninstallMultipleProtocolInterfaces (
2401 &gEfiUsbHcProtocolGuid
,
2410 if (PciAttributesSaved
) {
2412 // Restore original PCI attributes
2416 EfiPciIoAttributeOperationSet
,
2417 OriginalPciAttributes
,
2422 gBS
->CloseProtocol (
2424 &gEfiPciIoProtocolGuid
,
2425 This
->DriverBindingHandle
,
2432 Stop this driver on ControllerHandle. Support stoping any child handles
2433 created by this driver.
2435 @param This Protocol instance pointer.
2436 @param Controller Handle of device to stop driver on.
2437 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2438 @param ChildHandleBuffer List of handles for the children we need to stop.
2446 OHCIDriverBindingStop (
2447 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2448 IN EFI_HANDLE Controller
,
2449 IN UINTN NumberOfChildren
,
2450 IN EFI_HANDLE
*ChildHandleBuffer
2454 EFI_USB_HC_PROTOCOL
*UsbHc
;
2456 Status
= gBS
->OpenProtocol (
2458 &gEfiUsbHcProtocolGuid
,
2460 This
->DriverBindingHandle
,
2462 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2464 if (EFI_ERROR (Status
)) {
2468 OhciCleanDevUp(Controller
, UsbHc
);
2470 gBS
->CloseProtocol (
2472 &gEfiPciIoProtocolGuid
,
2473 This
->DriverBindingHandle
,