2 This file contains the implementation of Usb Hc Protocol.
4 Copyright (c) 2013-2016 Intel Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
14 Provides software reset for the USB host controller.
16 @param This This EFI_USB_HC_PROTOCOL instance.
17 @param Attributes A bit mask of the reset operation to perform.
19 @retval EFI_SUCCESS The reset operation succeeded.
20 @retval EFI_INVALID_PARAMETER Attributes is not valid.
21 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
22 not currently supported by the host controller.
23 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
29 IN EFI_USB_HC_PROTOCOL
*This
,
37 UINT32 PowerOnGoodTime
;
41 if ((Attributes
& ~(EFI_USB_HC_RESET_GLOBAL
| EFI_USB_HC_RESET_HOST_CONTROLLER
)) != 0) {
42 return EFI_INVALID_PARAMETER
;
46 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
48 if ((Attributes
& EFI_USB_HC_RESET_HOST_CONTROLLER
) != 0) {
49 gBS
->Stall (50 * 1000);
50 Status
= OhciSetHcCommandStatus (Ohc
, HC_RESET
, HC_RESET
);
51 if (EFI_ERROR (Status
)) {
52 return EFI_DEVICE_ERROR
;
54 gBS
->Stall (50 * 1000);
56 // Wait for host controller reset.
60 gBS
->Stall (1 * 1000);
61 Data32
= OhciGetOperationalReg (Ohc
->PciIo
, HC_COMMAND_STATUS
);
62 if (EFI_ERROR (Status
)) {
63 return EFI_DEVICE_ERROR
;
65 if ((Data32
& HC_RESET
) == 0) {
69 }while(PowerOnGoodTime
--);
71 return EFI_DEVICE_ERROR
;
74 OhciFreeIntTransferMemory (Ohc
);
75 Status
= OhciInitializeInterruptList (Ohc
);
76 OhciSetFrameInterval (Ohc
, FRAME_INTERVAL
, 0x2edf);
77 if ((Attributes
& EFI_USB_HC_RESET_GLOBAL
) != 0) {
78 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_RESET
);
79 if (EFI_ERROR (Status
)) {
80 return EFI_DEVICE_ERROR
;
82 gBS
->Stall (50 * 1000);
85 // Initialize host controller operational registers
87 OhciSetFrameInterval (Ohc
, FS_LARGEST_DATA_PACKET
, 0x2778);
88 OhciSetFrameInterval (Ohc
, FRAME_INTERVAL
, 0x2edf);
89 OhciSetPeriodicStart (Ohc
, 0x2a2f);
90 OhciSetHcControl (Ohc
, CONTROL_BULK_RATIO
, 0x3);
91 OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
| BULK_LIST_FILLED
, 0);
92 OhciSetRootHubDescriptor (Ohc
, RH_PSWITCH_MODE
, 0);
93 OhciSetRootHubDescriptor (Ohc
, RH_NO_PSWITCH
| RH_NOC_PROT
, 1);
94 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);
95 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);
97 OhciSetRootHubDescriptor (Ohc
, RH_DEV_REMOVABLE
, 0);
98 OhciSetRootHubDescriptor (Ohc
, RH_PORT_PWR_CTRL_MASK
, 0xffff);
99 OhciSetRootHubStatus (Ohc
, RH_LOCAL_PSTAT_CHANGE
);
100 OhciSetRootHubPortStatus (Ohc
, 0, RH_SET_PORT_POWER
);
101 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
102 for (Index
= 0; Index
< NumOfPorts
; Index
++) {
103 if (!EFI_ERROR (OhciSetRootHubPortFeature (This
, Index
, EfiUsbPortReset
))) {
104 gBS
->Stall (200 * 1000);
105 OhciClearRootHubPortFeature (This
, Index
, EfiUsbPortReset
);
107 OhciSetRootHubPortFeature (This
, Index
, EfiUsbPortEnable
);
111 OhciSetMemoryPointer (Ohc
, HC_HCCA
, Ohc
->HccaMemoryBlock
);
112 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
113 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
114 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| BULK_ENABLE
, 1); /*ISOCHRONOUS_ENABLE*/
115 OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_OPERATIONAL
);
116 gBS
->Stall (50*1000);
118 // Wait till first SOF occurs, and then clear it
120 while (OhciGetHcInterruptStatus (Ohc
, START_OF_FRAME
) == 0);
121 OhciClearInterruptStatus (Ohc
, START_OF_FRAME
);
128 Retrieve the current state of the USB host controller.
130 @param This This EFI_USB_HC_PROTOCOL instance.
131 @param State Variable to return the current host controller
134 @retval EFI_SUCCESS Host controller state was returned in State.
135 @retval EFI_INVALID_PARAMETER State is NULL.
136 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
137 retrieve the host controller's current state.
144 IN EFI_USB_HC_PROTOCOL
*This
,
145 OUT EFI_USB_HC_STATE
*State
148 USB_OHCI_HC_DEV
*Ohc
;
152 return EFI_INVALID_PARAMETER
;
155 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
157 FuncState
= OhciGetHcControl (Ohc
, HC_FUNCTIONAL_STATE
);
161 case HC_STATE_RESUME
:
162 *State
= EfiUsbHcStateHalt
;
165 case HC_STATE_OPERATIONAL
:
166 *State
= EfiUsbHcStateOperational
;
169 case HC_STATE_SUSPEND
:
170 *State
= EfiUsbHcStateSuspend
;
180 Sets the USB host controller to a specific state.
182 @param This This EFI_USB_HC_PROTOCOL instance.
183 @param State The state of the host controller that will be set.
185 @retval EFI_SUCCESS The USB host controller was successfully placed
186 in the state specified by State.
187 @retval EFI_INVALID_PARAMETER State is invalid.
188 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
195 IN EFI_USB_HC_PROTOCOL
*This
,
196 IN EFI_USB_HC_STATE State
200 USB_OHCI_HC_DEV
*Ohc
;
202 Ohc
= USB_OHCI_HC_DEV_FROM_THIS(This
);
205 case EfiUsbHcStateHalt
:
206 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_RESET
);
209 case EfiUsbHcStateOperational
:
210 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_OPERATIONAL
);
213 case EfiUsbHcStateSuspend
:
214 Status
= OhciSetHcControl (Ohc
, HC_FUNCTIONAL_STATE
, HC_STATE_SUSPEND
);
218 Status
= EFI_INVALID_PARAMETER
;
228 Submits control transfer to a target USB device.
230 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
231 @param DeviceAddress Represents the address of the target device on the USB,
232 which is assigned during USB enumeration.
233 @param IsSlowDevice Indicates whether the target device is slow device
234 or full-speed device.
235 @param MaxPaketLength Indicates the maximum packet size that the
236 default control transfer endpoint is capable of
237 sending or receiving.
238 @param Request A pointer to the USB device request that will be sent
240 @param TransferDirection Specifies the data direction for the transfer.
241 There are three values available, DataIn, DataOut
243 @param Data A pointer to the buffer of data that will be transmitted
244 to USB device or received from USB device.
245 @param DataLength Indicates the size, in bytes, of the data buffer
247 @param TimeOut Indicates the maximum time, in microseconds,
248 which the transfer is allowed to complete.
249 @param TransferResult A pointer to the detailed result information generated
250 by this control transfer.
252 @retval EFI_SUCCESS The control transfer was completed successfully.
253 @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.
254 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
255 @retval EFI_TIMEOUT The control transfer failed due to timeout.
256 @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.
257 Caller should check TranferResult for detailed error information.
264 OhciControlTransfer (
265 IN EFI_USB_HC_PROTOCOL
*This
,
266 IN UINT8 DeviceAddress
,
267 IN BOOLEAN IsSlowDevice
,
268 IN UINT8 MaxPacketLength
,
269 IN EFI_USB_DEVICE_REQUEST
*Request
,
270 IN EFI_USB_DATA_DIRECTION TransferDirection
,
271 IN OUT VOID
*Data OPTIONAL
,
272 IN OUT UINTN
*DataLength OPTIONAL
,
274 OUT UINT32
*TransferResult
277 USB_OHCI_HC_DEV
*Ohc
;
278 ED_DESCRIPTOR
*HeadEd
;
280 TD_DESCRIPTOR
*HeadTd
;
281 TD_DESCRIPTOR
*SetupTd
;
282 TD_DESCRIPTOR
*DataTd
;
283 TD_DESCRIPTOR
*StatusTd
;
284 TD_DESCRIPTOR
*EmptyTd
;
289 OHCI_ED_RESULT EdResult
;
291 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
293 UINTN ActualSendLength
;
297 VOID
*ReqMapping
= NULL
;
298 UINTN ReqMapLength
= 0;
299 EFI_PHYSICAL_ADDRESS ReqMapPhyAddr
= 0;
301 VOID
*DataMapping
= NULL
;
302 UINTN DataMapLength
= 0;
303 EFI_PHYSICAL_ADDRESS DataMapPhyAddr
= 0;
308 if ((TransferDirection
!= EfiUsbDataOut
&& TransferDirection
!= EfiUsbDataIn
&&
309 TransferDirection
!= EfiUsbNoData
) ||
310 Request
== NULL
|| DataLength
== NULL
|| TransferResult
== NULL
||
311 (TransferDirection
== EfiUsbNoData
&& (*DataLength
!= 0 || Data
!= NULL
)) ||
312 (TransferDirection
!= EfiUsbNoData
&& (*DataLength
== 0 || Data
== NULL
)) ||
313 (IsSlowDevice
&& MaxPacketLength
!= 8) ||
314 (MaxPacketLength
!= 8 && MaxPacketLength
!= 16 &&
315 MaxPacketLength
!= 32 && MaxPacketLength
!= 64)) {
316 return EFI_INVALID_PARAMETER
;
319 if (*DataLength
> MAX_BYTES_PER_TD
) {
320 DEBUG ((EFI_D_ERROR
, "OhciControlTransfer: Request data size is too large\r\n"));
321 return EFI_INVALID_PARAMETER
;
324 Ohc
= USB_OHCI_HC_DEV_FROM_THIS(This
);
326 if (TransferDirection
== EfiUsbDataIn
) {
327 DataPidDir
= TD_IN_PID
;
328 StatusPidDir
= TD_OUT_PID
;
330 DataPidDir
= TD_OUT_PID
;
331 StatusPidDir
= TD_IN_PID
;
334 Status
= OhciSetHcControl (Ohc
, CONTROL_ENABLE
, 0);
335 if (EFI_ERROR(Status
)) {
336 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));
337 *TransferResult
= EFI_USB_ERR_SYSTEM
;
338 return EFI_DEVICE_ERROR
;
340 Status
= OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
, 0);
341 if (EFI_ERROR(Status
)) {
342 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));
343 *TransferResult
= EFI_USB_ERR_SYSTEM
;
344 return EFI_DEVICE_ERROR
;
346 gBS
->Stall(20 * 1000);
348 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
349 Ed
= OhciCreateED (Ohc
);
351 Status
= EFI_OUT_OF_RESOURCES
;
352 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));
355 OhciSetEDField (Ed
, ED_SKIP
, 1);
356 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
357 OhciSetEDField (Ed
, ED_ENDPT_NUM
, 0);
358 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
359 OhciSetEDField (Ed
, ED_SPEED
, IsSlowDevice
);
360 OhciSetEDField (Ed
, ED_FORMAT
| ED_HALTED
| ED_DTTOGGLE
, 0);
361 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
362 OhciSetEDField (Ed
, ED_PDATA
, 0);
363 OhciSetEDField (Ed
, ED_ZERO
, 0);
364 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
365 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
366 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
367 HeadEd
= OhciAttachEDToList (Ohc
, CONTROL_LIST
, Ed
, NULL
);
371 if(Request
!= NULL
) {
372 ReqMapLength
= sizeof(EFI_USB_DEVICE_REQUEST
);
373 MapOp
= EfiPciIoOperationBusMasterRead
;
374 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, (UINT8
*)Request
, &ReqMapLength
, &ReqMapPhyAddr
, &ReqMapping
);
375 if (EFI_ERROR(Status
)) {
376 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));
380 SetupTd
= OhciCreateTD (Ohc
);
381 if (SetupTd
== NULL
) {
382 Status
= EFI_OUT_OF_RESOURCES
;
383 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));
384 goto UNMAP_SETUP_BUFF
;
387 OhciSetTDField (SetupTd
, TD_PDATA
, 0);
388 OhciSetTDField (SetupTd
, TD_BUFFER_ROUND
, 1);
389 OhciSetTDField (SetupTd
, TD_DIR_PID
, TD_SETUP_PID
);
390 OhciSetTDField (SetupTd
, TD_DELAY_INT
, TD_NO_DELAY
);
391 OhciSetTDField (SetupTd
, TD_DT_TOGGLE
, 2);
392 OhciSetTDField (SetupTd
, TD_ERROR_CNT
, 0);
393 OhciSetTDField (SetupTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
394 OhciSetTDField (SetupTd
, TD_CURR_BUFFER_PTR
, (UINT32
)ReqMapPhyAddr
);
395 OhciSetTDField (SetupTd
, TD_NEXT_PTR
, 0);
396 OhciSetTDField (SetupTd
, TD_BUFFER_END_PTR
, (UINT32
)(ReqMapPhyAddr
+ sizeof (EFI_USB_DEVICE_REQUEST
) - 1));
397 SetupTd
->ActualSendLength
= sizeof (EFI_USB_DEVICE_REQUEST
);
398 SetupTd
->DataBuffer
= (UINT32
)ReqMapPhyAddr
;
399 SetupTd
->NextTDPointer
= 0;
401 if (TransferDirection
== EfiUsbDataIn
) {
402 MapOp
= EfiPciIoOperationBusMasterWrite
;
404 MapOp
= EfiPciIoOperationBusMasterRead
;
406 DataMapLength
= *DataLength
;
407 if ((Data
!= NULL
) && (DataMapLength
!= 0)) {
408 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, Data
, &DataMapLength
, &DataMapPhyAddr
, &DataMapping
);
409 if (EFI_ERROR(Status
)) {
410 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));
417 LeftLength
= DataMapLength
;
418 ActualSendLength
= DataMapLength
;
420 while (LeftLength
> 0) {
421 ActualSendLength
= LeftLength
;
422 if (LeftLength
> MaxPacketLength
) {
423 ActualSendLength
= MaxPacketLength
;
425 DataTd
= OhciCreateTD (Ohc
);
426 if (DataTd
== NULL
) {
427 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
428 Status
= EFI_OUT_OF_RESOURCES
;
429 goto UNMAP_DATA_BUFF
;
431 OhciSetTDField (DataTd
, TD_PDATA
, 0);
432 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
433 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
434 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
435 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, DataToggle
);
436 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
437 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
438 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) DataMapPhyAddr
);
439 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(DataMapPhyAddr
+ ActualSendLength
- 1));
440 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
441 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
442 DataTd
->DataBuffer
= (UINT32
)DataMapPhyAddr
;
443 DataTd
->NextTDPointer
= 0;
444 OhciLinkTD (HeadTd
, DataTd
);
446 DataMapPhyAddr
+= ActualSendLength
;
447 LeftLength
-= ActualSendLength
;
452 StatusTd
= OhciCreateTD (Ohc
);
453 if (StatusTd
== NULL
) {
454 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));
455 Status
= EFI_OUT_OF_RESOURCES
;
456 goto UNMAP_DATA_BUFF
;
458 OhciSetTDField (StatusTd
, TD_PDATA
, 0);
459 OhciSetTDField (StatusTd
, TD_BUFFER_ROUND
, 1);
460 OhciSetTDField (StatusTd
, TD_DIR_PID
, StatusPidDir
);
461 OhciSetTDField (StatusTd
, TD_DELAY_INT
, 7);
462 OhciSetTDField (StatusTd
, TD_DT_TOGGLE
, 3);
463 OhciSetTDField (StatusTd
, TD_ERROR_CNT
, 0);
464 OhciSetTDField (StatusTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
465 OhciSetTDField (StatusTd
, TD_CURR_BUFFER_PTR
, 0);
466 OhciSetTDField (StatusTd
, TD_NEXT_PTR
, 0);
467 OhciSetTDField (StatusTd
, TD_BUFFER_END_PTR
, 0);
468 StatusTd
->ActualSendLength
= 0;
469 StatusTd
->DataBuffer
= 0;
470 StatusTd
->NextTDPointer
= 0;
471 OhciLinkTD (HeadTd
, StatusTd
);
475 EmptyTd
= OhciCreateTD (Ohc
);
476 if (EmptyTd
== NULL
) {
477 Status
= EFI_OUT_OF_RESOURCES
;
478 goto UNMAP_DATA_BUFF
;
480 OhciSetTDField (EmptyTd
, TD_PDATA
, 0);
481 OhciSetTDField (EmptyTd
, TD_BUFFER_ROUND
, 0);
482 OhciSetTDField (EmptyTd
, TD_DIR_PID
, 0);
483 OhciSetTDField (EmptyTd
, TD_DELAY_INT
, 0);
484 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
485 EmptyTd
->Word0
.DataToggle
= 0;
486 OhciSetTDField (EmptyTd
, TD_ERROR_CNT
, 0);
487 OhciSetTDField (EmptyTd
, TD_COND_CODE
, 0);
488 OhciSetTDField (EmptyTd
, TD_CURR_BUFFER_PTR
, 0);
489 OhciSetTDField (EmptyTd
, TD_BUFFER_END_PTR
, 0);
490 OhciSetTDField (EmptyTd
, TD_NEXT_PTR
, 0);
491 EmptyTd
->ActualSendLength
= 0;
492 EmptyTd
->DataBuffer
= 0;
493 EmptyTd
->NextTDPointer
= 0;
494 OhciLinkTD (HeadTd
, EmptyTd
);
495 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptyTd
;
496 OhciAttachTDListToED (Ed
, HeadTd
);
498 // For debugging, dump ED & TD buffer befor transferring
501 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);
503 OhciSetEDField (Ed
, ED_SKIP
, 0);
504 Status
= OhciSetHcControl (Ohc
, CONTROL_ENABLE
, 1);
505 if (EFI_ERROR(Status
)) {
506 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));
507 *TransferResult
= EFI_USB_ERR_SYSTEM
;
508 Status
= EFI_DEVICE_ERROR
;
509 goto UNMAP_DATA_BUFF
;
511 Status
= OhciSetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
, 1);
512 if (EFI_ERROR(Status
)) {
513 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));
514 *TransferResult
= EFI_USB_ERR_SYSTEM
;
515 Status
= EFI_DEVICE_ERROR
;
516 goto UNMAP_DATA_BUFF
;
518 gBS
->Stall(20 * 1000);
522 Status
= CheckIfDone (Ohc
, CONTROL_LIST
, Ed
, HeadTd
, &EdResult
);
524 while (Status
== EFI_NOT_READY
&& TimeCount
<= TimeOut
) {
527 Status
= CheckIfDone (Ohc
, CONTROL_LIST
, Ed
, HeadTd
, &EdResult
);
530 // For debugging, dump ED & TD buffer after transferring
532 //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);
534 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
536 if (EdResult
.ErrorCode
!= TD_NO_ERROR
) {
537 if (EdResult
.ErrorCode
== TD_TOBE_PROCESSED
) {
538 DEBUG ((EFI_D_INFO
, "Control pipe timeout, > %d mS\r\n", TimeOut
));
540 DEBUG ((EFI_D_INFO
, "Control pipe broken\r\n"));
544 DEBUG ((EFI_D_INFO
, "Control transfer successed\r\n"));
548 OhciSetEDField (Ed
, ED_SKIP
, 1);
550 OhciSetMemoryPointer (Ohc
, HC_CONTROL_HEAD
, NULL
);
552 HeadEd
->NextED
= Ed
->NextED
;
554 if(DataMapping
!= NULL
) {
555 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, DataMapping
);
561 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
562 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
566 if(ReqMapping
!= NULL
) {
567 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, ReqMapping
);
571 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
579 Submits bulk transfer to a bulk endpoint of a USB device.
581 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
582 @param DeviceAddress Represents the address of the target device on the USB,
583 which is assigned during USB enumeration.
584 @param EndPointAddress The combination of an endpoint number and an
585 endpoint direction of the target USB device.
586 Each endpoint address supports data transfer in
587 one direction except the control endpoint
588 (whose default endpoint address is 0).
589 It is the caller's responsibility to make sure that
590 the EndPointAddress represents a bulk endpoint.
591 @param MaximumPacketLength Indicates the maximum packet size the target endpoint
592 is capable of sending or receiving.
593 @param Data A pointer to the buffer of data that will be transmitted
594 to USB device or received from USB device.
595 @param DataLength When input, indicates the size, in bytes, of the data buffer
596 specified by Data. When output, indicates the actually
597 transferred data size.
598 @param DataToggle A pointer to the data toggle value. On input, it indicates
599 the initial data toggle value the bulk transfer should adopt;
600 on output, it is updated to indicate the data toggle value
601 of the subsequent bulk transfer.
602 @param TimeOut Indicates the maximum time, in microseconds, which the
603 transfer is allowed to complete.
604 TransferResult A pointer to the detailed result information of the
607 @retval EFI_SUCCESS The bulk transfer was completed successfully.
608 @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.
609 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
610 @retval EFI_TIMEOUT The bulk transfer failed due to timeout.
611 @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.
612 Caller should check TranferResult for detailed error information.
620 IN EFI_USB_HC_PROTOCOL
*This
,
621 IN UINT8 DeviceAddress
,
622 IN UINT8 EndPointAddress
,
623 IN UINT8 MaxPacketLength
,
625 IN OUT UINTN
*DataLength
,
626 IN OUT UINT8
*DataToggle
,
628 OUT UINT32
*TransferResult
631 USB_OHCI_HC_DEV
*Ohc
;
632 ED_DESCRIPTOR
*HeadEd
;
635 TD_DESCRIPTOR
*HeadTd
;
636 TD_DESCRIPTOR
*DataTd
;
637 TD_DESCRIPTOR
*EmptyTd
;
641 OHCI_ED_RESULT EdResult
;
643 EFI_PCI_IO_PROTOCOL_OPERATION MapOp
;
646 EFI_PHYSICAL_ADDRESS MapPyhAddr
;
648 UINTN ActualSendLength
;
655 Status
= EFI_SUCCESS
;
657 if (Data
== NULL
|| DataLength
== NULL
|| DataToggle
== NULL
|| TransferResult
== NULL
||
658 *DataLength
== 0 || (*DataToggle
!= 0 && *DataToggle
!= 1) ||
659 (MaxPacketLength
!= 8 && MaxPacketLength
!= 16 &&
660 MaxPacketLength
!= 32 && MaxPacketLength
!= 64)) {
661 return EFI_INVALID_PARAMETER
;
664 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
666 if ((EndPointAddress
& 0x80) != 0) {
667 DataPidDir
= TD_IN_PID
;
668 MapOp
= EfiPciIoOperationBusMasterWrite
;
670 DataPidDir
= TD_OUT_PID
;
671 MapOp
= EfiPciIoOperationBusMasterRead
;
674 EndPointNum
= (EndPointAddress
& 0xF);
675 EdResult
.NextToggle
= *DataToggle
;
677 Status
= OhciSetHcControl (Ohc
, BULK_ENABLE
, 0);
678 if (EFI_ERROR(Status
)) {
679 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));
680 *TransferResult
= EFI_USB_ERR_SYSTEM
;
681 return EFI_DEVICE_ERROR
;
683 Status
= OhciSetHcCommandStatus (Ohc
, BULK_LIST_FILLED
, 0);
684 if (EFI_ERROR(Status
)) {
685 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));
686 *TransferResult
= EFI_USB_ERR_SYSTEM
;
687 return EFI_DEVICE_ERROR
;
689 gBS
->Stall(20 * 1000);
691 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
693 Ed
= OhciCreateED (Ohc
);
695 return EFI_OUT_OF_RESOURCES
;
697 OhciSetEDField (Ed
, ED_SKIP
, 1);
698 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
699 OhciSetEDField (Ed
, ED_ENDPT_NUM
, EndPointNum
);
700 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
701 OhciSetEDField (Ed
, ED_SPEED
, HI_SPEED
);
702 OhciSetEDField (Ed
, ED_FORMAT
| ED_HALTED
| ED_DTTOGGLE
, 0);
703 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
704 OhciSetEDField (Ed
, ED_PDATA
, 0);
705 OhciSetEDField (Ed
, ED_ZERO
, 0);
706 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
707 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
708 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
709 HeadEd
= OhciAttachEDToList (Ohc
, BULK_LIST
, Ed
, NULL
);
712 MapLength
= *DataLength
;
713 Status
= Ohc
->PciIo
->Map (Ohc
->PciIo
, MapOp
, (UINT8
*)Data
, &MapLength
, &MapPyhAddr
, &Mapping
);
714 if (EFI_ERROR(Status
)) {
715 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));
722 LeftLength
= MapLength
;
723 ActualSendLength
= MapLength
;
726 while (LeftLength
> 0) {
727 ActualSendLength
= LeftLength
;
728 if (LeftLength
> MaxPacketLength
) {
729 ActualSendLength
= MaxPacketLength
;
731 DataTd
= OhciCreateTD (Ohc
);
732 if (DataTd
== NULL
) {
733 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
734 Status
= EFI_OUT_OF_RESOURCES
;
735 goto FREE_OHCI_TDBUFF
;
737 OhciSetTDField (DataTd
, TD_PDATA
, 0);
738 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
739 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
740 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
741 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, *DataToggle
);
742 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
743 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
744 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) MapPyhAddr
);
745 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(MapPyhAddr
+ ActualSendLength
- 1));
746 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
747 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
748 DataTd
->DataBuffer
= (UINT32
)MapPyhAddr
;
749 DataTd
->NextTDPointer
= 0;
754 OhciLinkTD (HeadTd
, DataTd
);
757 MapPyhAddr
+= ActualSendLength
;
758 LeftLength
-= ActualSendLength
;
763 EmptyTd
= OhciCreateTD (Ohc
);
764 if (EmptyTd
== NULL
) {
765 Status
= EFI_OUT_OF_RESOURCES
;
766 DEBUG ((EFI_D_INFO
, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));
767 goto FREE_OHCI_TDBUFF
;
769 OhciSetTDField (EmptyTd
, TD_PDATA
, 0);
770 OhciSetTDField (EmptyTd
, TD_BUFFER_ROUND
, 0);
771 OhciSetTDField (EmptyTd
, TD_DIR_PID
, 0);
772 OhciSetTDField (EmptyTd
, TD_DELAY_INT
, 0);
773 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);
774 EmptyTd
->Word0
.DataToggle
= 0;
775 OhciSetTDField (EmptyTd
, TD_ERROR_CNT
, 0);
776 OhciSetTDField (EmptyTd
, TD_COND_CODE
, 0);
777 OhciSetTDField (EmptyTd
, TD_CURR_BUFFER_PTR
, 0);
778 OhciSetTDField (EmptyTd
, TD_BUFFER_END_PTR
, 0);
779 OhciSetTDField (EmptyTd
, TD_NEXT_PTR
, 0);
780 EmptyTd
->ActualSendLength
= 0;
781 EmptyTd
->DataBuffer
= 0;
782 EmptyTd
->NextTDPointer
= 0;
783 OhciLinkTD (HeadTd
, EmptyTd
);
784 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptyTd
;
785 OhciAttachTDListToED (Ed
, HeadTd
);
787 OhciSetEDField (Ed
, ED_SKIP
, 0);
788 Status
= OhciSetHcCommandStatus (Ohc
, BULK_LIST_FILLED
, 1);
789 if (EFI_ERROR(Status
)) {
790 *TransferResult
= EFI_USB_ERR_SYSTEM
;
791 Status
= EFI_DEVICE_ERROR
;
792 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));
793 goto FREE_OHCI_TDBUFF
;
795 Status
= OhciSetHcControl (Ohc
, BULK_ENABLE
, 1);
796 if (EFI_ERROR(Status
)) {
797 *TransferResult
= EFI_USB_ERR_SYSTEM
;
798 Status
= EFI_DEVICE_ERROR
;
799 DEBUG ((EFI_D_INFO
, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));
800 goto FREE_OHCI_TDBUFF
;
802 gBS
->Stall(20 * 1000);
805 Status
= CheckIfDone (Ohc
, BULK_LIST
, Ed
, HeadTd
, &EdResult
);
806 while (Status
== EFI_NOT_READY
&& TimeCount
<= TimeOut
) {
809 Status
= CheckIfDone (Ohc
, BULK_LIST
, Ed
, HeadTd
, &EdResult
);
812 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
814 if (EdResult
.ErrorCode
!= TD_NO_ERROR
) {
815 if (EdResult
.ErrorCode
== TD_TOBE_PROCESSED
) {
816 DEBUG ((EFI_D_INFO
, "Bulk pipe timeout, > %d mS\r\n", TimeOut
));
818 DEBUG ((EFI_D_INFO
, "Bulk pipe broken\r\n"));
819 *DataToggle
= EdResult
.NextToggle
;
823 DEBUG ((EFI_D_INFO
, "Bulk transfer successed\r\n"));
825 //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);
828 OhciSetEDField (Ed
, ED_SKIP
, 1);
830 OhciSetMemoryPointer (Ohc
, HC_BULK_HEAD
, NULL
);
832 HeadEd
->NextED
= Ed
->NextED
;
836 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
837 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
840 if(Mapping
!= NULL
) {
841 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, Mapping
);
845 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
851 Submits an interrupt transfer to an interrupt endpoint of a USB device.
853 @param Ohc Device private data
854 @param DeviceAddress Represents the address of the target device on the USB,
855 which is assigned during USB enumeration.
856 @param EndPointAddress The combination of an endpoint number and an endpoint
857 direction of the target USB device. Each endpoint address
858 supports data transfer in one direction except the
859 control endpoint (whose default endpoint address is 0).
860 It is the caller's responsibility to make sure that
861 the EndPointAddress represents an interrupt endpoint.
862 @param IsSlowDevice Indicates whether the target device is slow device
863 or full-speed device.
864 @param MaxPacketLength Indicates the maximum packet size the target endpoint
865 is capable of sending or receiving.
866 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
867 the host and the target interrupt endpoint.
868 If FALSE, the specified asynchronous interrupt pipe
870 @param DataToggle A pointer to the data toggle value. On input, it is valid
871 when IsNewTransfer is TRUE, and it indicates the initial
872 data toggle value the asynchronous interrupt transfer
874 On output, it is valid when IsNewTransfer is FALSE,
875 and it is updated to indicate the data toggle value of
876 the subsequent asynchronous interrupt transfer.
877 @param PollingInterval Indicates the interval, in milliseconds, that the
878 asynchronous interrupt transfer is polled.
879 This parameter is required when IsNewTransfer is TRUE.
880 @param UCBuffer Uncacheable buffer
881 @param DataLength Indicates the length of data to be received at the
882 rate specified by PollingInterval from the target
883 asynchronous interrupt endpoint. This parameter
884 is only required when IsNewTransfer is TRUE.
885 @param CallBackFunction The Callback function.This function is called at the
886 rate specified by PollingInterval.This parameter is
887 only required when IsNewTransfer is TRUE.
888 @param Context The context that is passed to the CallBackFunction.
889 This is an optional parameter and may be NULL.
890 @param IsPeriodic Periodic interrupt or not
891 @param OutputED The correspoding ED carried out
892 @param OutputTD The correspoding TD carried out
895 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
896 submitted or canceled.
897 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
898 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
903 OhciInterruptTransfer (
904 IN USB_OHCI_HC_DEV
*Ohc
,
905 IN UINT8 DeviceAddress
,
906 IN UINT8 EndPointAddress
,
907 IN BOOLEAN IsSlowDevice
,
908 IN UINT8 MaxPacketLength
,
909 IN BOOLEAN IsNewTransfer
,
910 IN OUT UINT8
*DataToggle OPTIONAL
,
911 IN UINTN PollingInterval OPTIONAL
,
912 IN VOID
*UCBuffer OPTIONAL
,
913 IN UINTN DataLength OPTIONAL
,
914 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL
,
915 IN VOID
*Context OPTIONAL
,
916 IN BOOLEAN IsPeriodic OPTIONAL
,
917 OUT ED_DESCRIPTOR
**OutputED OPTIONAL
,
918 OUT TD_DESCRIPTOR
**OutputTD OPTIONAL
923 ED_DESCRIPTOR
*HeadEd
;
924 TD_DESCRIPTOR
*HeadTd
;
925 TD_DESCRIPTOR
*DataTd
;
926 TD_DESCRIPTOR
*EmptTd
;
932 INTERRUPT_CONTEXT_ENTRY
*Entry
;
938 EFI_PHYSICAL_ADDRESS MapPyhAddr
;
940 UINTN ActualSendLength
;
943 if (DataLength
> MAX_BYTES_PER_TD
) {
944 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Error param\r\n"));
945 return EFI_INVALID_PARAMETER
;
948 if ((EndPointAddress
& 0x80) != 0) {
950 DataPidDir
= TD_IN_PID
;
953 DataPidDir
= TD_OUT_PID
;
956 EndPointNum
= (EndPointAddress
& 0xF);
958 if (!IsNewTransfer
) {
959 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
960 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 0);
961 OhciFreeInterruptContext (Ohc
, DeviceAddress
, EndPointAddress
, DataToggle
);
962 Status
= OhciFreeInterruptEdByAddr (Ohc
, DeviceAddress
, EndPointNum
);
963 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 1);
964 gBS
->RestoreTPL (OldTpl
);
967 MapLength
= DataLength
;
968 Status
= Ohc
->PciIo
->Map(
970 EfiPciIoOperationBusMasterWrite
,
976 if (EFI_ERROR (Status
)) {
977 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));
982 while (PollingInterval
>= Index
* 2 && Depth
> 0) {
989 HeadEd
= OhciFindMinInterruptEDList (Ohc
, (UINT32
)Depth
);
990 if ((Ed
= OhciFindWorkingEd (HeadEd
, DeviceAddress
, EndPointNum
, EdDir
)) != NULL
) {
991 OhciSetEDField (Ed
, ED_SKIP
, 1);
993 Ed
= OhciCreateED (Ohc
);
995 Status
= EFI_OUT_OF_RESOURCES
;
996 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));
997 goto UNMAP_OHCI_XBUFF
;
999 OhciSetEDField (Ed
, ED_SKIP
, 1);
1000 OhciSetEDField (Ed
, ED_FUNC_ADD
, DeviceAddress
);
1001 OhciSetEDField (Ed
, ED_ENDPT_NUM
, EndPointNum
);
1002 OhciSetEDField (Ed
, ED_DIR
, ED_FROM_TD_DIR
);
1003 OhciSetEDField (Ed
, ED_SPEED
, IsSlowDevice
);
1004 OhciSetEDField (Ed
, ED_FORMAT
, 0);
1005 OhciSetEDField (Ed
, ED_MAX_PACKET
, MaxPacketLength
);
1006 OhciSetEDField (Ed
, ED_PDATA
| ED_ZERO
| ED_HALTED
| ED_DTTOGGLE
, 0);
1007 OhciSetEDField (Ed
, ED_TDHEAD_PTR
, 0);
1008 OhciSetEDField (Ed
, ED_TDTAIL_PTR
, 0);
1009 OhciSetEDField (Ed
, ED_NEXT_EDPTR
, 0);
1010 OhciAttachEDToList (Ohc
, INTERRUPT_LIST
, Ed
, HeadEd
);
1015 LeftLength
= MapLength
;
1016 ActualSendLength
= MapLength
;
1019 while (LeftLength
> 0) {
1020 ActualSendLength
= LeftLength
;
1021 if (LeftLength
> MaxPacketLength
) {
1022 ActualSendLength
= MaxPacketLength
;
1024 DataTd
= OhciCreateTD (Ohc
);
1025 if (DataTd
== NULL
) {
1026 Status
= EFI_OUT_OF_RESOURCES
;
1027 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));
1028 goto FREE_OHCI_TDBUFF
;
1030 OhciSetTDField (DataTd
, TD_PDATA
, 0);
1031 OhciSetTDField (DataTd
, TD_BUFFER_ROUND
, 1);
1032 OhciSetTDField (DataTd
, TD_DIR_PID
, DataPidDir
);
1033 OhciSetTDField (DataTd
, TD_DELAY_INT
, TD_NO_DELAY
);
1034 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, *DataToggle
);
1035 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
1036 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
1037 OhciSetTDField (DataTd
, TD_CURR_BUFFER_PTR
, (UINT32
) MapPyhAddr
);
1038 OhciSetTDField (DataTd
, TD_BUFFER_END_PTR
, (UINT32
)(MapPyhAddr
+ ActualSendLength
- 1));
1039 OhciSetTDField (DataTd
, TD_NEXT_PTR
, 0);
1040 DataTd
->ActualSendLength
= (UINT32
)ActualSendLength
;
1041 DataTd
->DataBuffer
= (UINT32
)MapPyhAddr
;
1042 DataTd
->NextTDPointer
= 0;
1047 OhciLinkTD (HeadTd
, DataTd
);
1050 MapPyhAddr
+= ActualSendLength
;
1051 LeftLength
-= ActualSendLength
;
1054 EmptTd
= OhciCreateTD (Ohc
);
1055 if (EmptTd
== NULL
) {
1056 Status
= EFI_OUT_OF_RESOURCES
;
1057 DEBUG ((EFI_D_ERROR
, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));
1058 goto FREE_OHCI_TDBUFF
;
1060 OhciSetTDField (EmptTd
, TD_PDATA
, 0);
1061 OhciSetTDField (EmptTd
, TD_BUFFER_ROUND
, 0);
1062 OhciSetTDField (EmptTd
, TD_DIR_PID
, 0);
1063 OhciSetTDField (EmptTd
, TD_DELAY_INT
, 0);
1064 //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);
1065 EmptTd
->Word0
.DataToggle
= 0;
1066 OhciSetTDField (EmptTd
, TD_ERROR_CNT
, 0);
1067 OhciSetTDField (EmptTd
, TD_COND_CODE
, 0);
1068 OhciSetTDField (EmptTd
, TD_CURR_BUFFER_PTR
, 0);
1069 OhciSetTDField (EmptTd
, TD_BUFFER_END_PTR
, 0);
1070 OhciSetTDField (EmptTd
, TD_NEXT_PTR
, 0);
1071 EmptTd
->ActualSendLength
= 0;
1072 EmptTd
->DataBuffer
= 0;
1073 EmptTd
->NextTDPointer
= 0;
1074 OhciLinkTD (HeadTd
, EmptTd
);
1075 Ed
->TdTailPointer
= (UINT32
)(UINTN
)EmptTd
;
1076 OhciAttachTDListToED (Ed
, HeadTd
);
1078 if (OutputED
!= NULL
) {
1081 if (OutputTD
!= NULL
) {
1085 if (CallBackFunction
!= NULL
) {
1086 Entry
= AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY
));
1087 if (Entry
== NULL
) {
1088 goto FREE_OHCI_TDBUFF
;
1091 Entry
->DeviceAddress
= DeviceAddress
;
1092 Entry
->EndPointAddress
= EndPointAddress
;
1094 Entry
->DataTd
= HeadTd
;
1095 Entry
->IsSlowDevice
= IsSlowDevice
;
1096 Entry
->MaxPacketLength
= MaxPacketLength
;
1097 Entry
->PollingInterval
= PollingInterval
;
1098 Entry
->CallBackFunction
= CallBackFunction
;
1099 Entry
->Context
= Context
;
1100 Entry
->IsPeriodic
= IsPeriodic
;
1101 Entry
->UCBuffer
= UCBuffer
;
1102 Entry
->UCBufferMapping
= Mapping
;
1103 Entry
->DataLength
= DataLength
;
1104 Entry
->Toggle
= DataToggle
;
1105 Entry
->NextEntry
= NULL
;
1106 OhciAddInterruptContextEntry (Ohc
, Entry
);
1108 OhciSetEDField (Ed
, ED_SKIP
, 0);
1110 if (OhciGetHcControl (Ohc
, PERIODIC_ENABLE
) == 0) {
1111 Status
= OhciSetHcControl (Ohc
, PERIODIC_ENABLE
, 1);
1120 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
1121 UsbHcFreeMem(Ohc
->MemPool
, DataTd
, sizeof(TD_DESCRIPTOR
));
1125 if ((HeadEd
!= Ed
) && HeadEd
&& Ed
) {
1126 while(HeadEd
->NextED
!= (UINT32
)(UINTN
)Ed
) {
1127 HeadEd
= (ED_DESCRIPTOR
*)(UINTN
)(HeadEd
->NextED
);
1129 HeadEd
->NextED
= Ed
->NextED
;
1130 UsbHcFreeMem(Ohc
->MemPool
, Ed
, sizeof(ED_DESCRIPTOR
));
1134 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, Mapping
);
1142 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
1144 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1145 @param DeviceAddress Represents the address of the target device on the USB,
1146 which is assigned during USB enumeration.
1147 @param EndPointAddress The combination of an endpoint number and an endpoint
1148 direction of the target USB device. Each endpoint address
1149 supports data transfer in one direction except the
1150 control endpoint (whose default endpoint address is 0).
1151 It is the caller's responsibility to make sure that
1152 the EndPointAddress represents an interrupt endpoint.
1153 @param IsSlowDevice Indicates whether the target device is slow device
1154 or full-speed device.
1155 @param MaxiumPacketLength Indicates the maximum packet size the target endpoint
1156 is capable of sending or receiving.
1157 @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
1158 the host and the target interrupt endpoint.
1159 If FALSE, the specified asynchronous interrupt pipe
1161 @param DataToggle A pointer to the data toggle value. On input, it is valid
1162 when IsNewTransfer is TRUE, and it indicates the initial
1163 data toggle value the asynchronous interrupt transfer
1165 On output, it is valid when IsNewTransfer is FALSE,
1166 and it is updated to indicate the data toggle value of
1167 the subsequent asynchronous interrupt transfer.
1168 @param PollingInterval Indicates the interval, in milliseconds, that the
1169 asynchronous interrupt transfer is polled.
1170 This parameter is required when IsNewTransfer is TRUE.
1171 @param DataLength Indicates the length of data to be received at the
1172 rate specified by PollingInterval from the target
1173 asynchronous interrupt endpoint. This parameter
1174 is only required when IsNewTransfer is TRUE.
1175 @param CallBackFunction The Callback function.This function is called at the
1176 rate specified by PollingInterval.This parameter is
1177 only required when IsNewTransfer is TRUE.
1178 @param Context The context that is passed to the CallBackFunction.
1179 This is an optional parameter and may be NULL.
1181 @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully
1182 submitted or canceled.
1183 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1184 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1191 OhciAsyncInterruptTransfer (
1192 IN EFI_USB_HC_PROTOCOL
*This
,
1193 IN UINT8 DeviceAddress
,
1194 IN UINT8 EndPointAddress
,
1195 IN BOOLEAN IsSlowDevice
,
1196 IN UINT8 MaxPacketLength
,
1197 IN BOOLEAN IsNewTransfer
,
1198 IN OUT UINT8
*DataToggle OPTIONAL
,
1199 IN UINTN PollingInterval OPTIONAL
,
1200 IN UINTN DataLength OPTIONAL
,
1201 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL
,
1202 IN VOID
*Context OPTIONAL
1206 USB_OHCI_HC_DEV
*Ohc
;
1209 if (DataToggle
== NULL
|| (EndPointAddress
& 0x80) == 0 ||
1210 (IsNewTransfer
&& (DataLength
== 0 ||
1211 (*DataToggle
!= 0 && *DataToggle
!= 1) || (PollingInterval
< 1 || PollingInterval
> 255)))) {
1212 return EFI_INVALID_PARAMETER
;
1215 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1216 if ( IsNewTransfer
) {
1217 UCBuffer
= AllocatePool(DataLength
);
1218 if (UCBuffer
== NULL
) {
1219 return EFI_OUT_OF_RESOURCES
;
1224 Status
= OhciInterruptTransfer (
1241 if ( IsNewTransfer
) {
1242 if (EFI_ERROR(Status
)) {
1243 gBS
->FreePool (UCBuffer
);
1252 Submits synchronous interrupt transfer to an interrupt endpoint
1255 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1256 @param DeviceAddress Represents the address of the target device on the USB,
1257 which is assigned during USB enumeration.
1258 @param EndPointAddress The combination of an endpoint number and an endpoint
1259 direction of the target USB device. Each endpoint
1260 address supports data transfer in one direction
1261 except the control endpoint (whose default
1262 endpoint address is 0). It is the caller's responsibility
1263 to make sure that the EndPointAddress represents
1264 an interrupt endpoint.
1265 @param IsSlowDevice Indicates whether the target device is slow device
1266 or full-speed device.
1267 @param MaxPacketLength Indicates the maximum packet size the target endpoint
1268 is capable of sending or receiving.
1269 @param Data A pointer to the buffer of data that will be transmitted
1270 to USB device or received from USB device.
1271 @param DataLength On input, the size, in bytes, of the data buffer specified
1272 by Data. On output, the number of bytes transferred.
1273 @param DataToggle A pointer to the data toggle value. On input, it indicates
1274 the initial data toggle value the synchronous interrupt
1275 transfer should adopt;
1276 on output, it is updated to indicate the data toggle value
1277 of the subsequent synchronous interrupt transfer.
1278 @param TimeOut Indicates the maximum time, in microseconds, which the
1279 transfer is allowed to complete.
1280 @param TransferResult A pointer to the detailed result information from
1281 the synchronous interrupt transfer.
1283 @retval EFI_UNSUPPORTED This interface not available.
1284 @retval EFI_INVALID_PARAMETER Parameters not follow spec
1291 OhciSyncInterruptTransfer (
1292 IN EFI_USB_HC_PROTOCOL
*This
,
1293 IN UINT8 DeviceAddress
,
1294 IN UINT8 EndPointAddress
,
1295 IN BOOLEAN IsSlowDevice
,
1296 IN UINT8 MaxPacketLength
,
1298 IN OUT UINTN
*DataLength
,
1299 IN OUT UINT8
*DataToggle
,
1301 OUT UINT32
*TransferResult
1304 USB_OHCI_HC_DEV
*Ohc
;
1307 TD_DESCRIPTOR
*HeadTd
;
1308 OHCI_ED_RESULT EdResult
;
1311 if ((EndPointAddress
& 0x80) == 0 || Data
== NULL
|| DataLength
== NULL
|| *DataLength
== 0 ||
1312 (IsSlowDevice
&& MaxPacketLength
> 8) || (!IsSlowDevice
&& MaxPacketLength
> 64) ||
1313 DataToggle
== NULL
|| (*DataToggle
!= 0 && *DataToggle
!= 1) || TransferResult
== NULL
) {
1314 return EFI_INVALID_PARAMETER
;
1317 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1318 UCBuffer
= AllocatePool (*DataLength
);
1319 if (UCBuffer
== NULL
) {
1320 return EFI_OUT_OF_RESOURCES
;
1322 Status
= OhciInterruptTransfer (
1340 if (!EFI_ERROR (Status
)) {
1341 Status
= CheckIfDone (Ohc
, INTERRUPT_LIST
, Ed
, HeadTd
, &EdResult
);
1342 while (Status
== EFI_NOT_READY
&& TimeOut
> 0) {
1345 Status
= CheckIfDone (Ohc
, INTERRUPT_LIST
, Ed
, HeadTd
, &EdResult
);
1348 *TransferResult
= ConvertErrorCode (EdResult
.ErrorCode
);
1350 CopyMem(Data
, UCBuffer
, *DataLength
);
1351 Status
= OhciInterruptTransfer (
1373 Submits isochronous transfer to a target USB device.
1375 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1376 @param DeviceAddress Represents the address of the target device on the USB,
1377 which is assigned during USB enumeration.
1378 @param EndPointAddress End point address
1379 @param MaximumPacketLength Indicates the maximum packet size that the
1380 default control transfer endpoint is capable of
1381 sending or receiving.
1382 @param Data A pointer to the buffer of data that will be transmitted
1383 to USB device or received from USB device.
1384 @param DataLength Indicates the size, in bytes, of the data buffer
1386 @param TransferResult A pointer to the detailed result information generated
1387 by this control transfer.
1389 @retval EFI_UNSUPPORTED This interface not available
1390 @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL
1397 OhciIsochronousTransfer (
1398 IN EFI_USB_HC_PROTOCOL
*This
,
1399 IN UINT8 DeviceAddress
,
1400 IN UINT8 EndPointAddress
,
1401 IN UINT8 MaximumPacketLength
,
1403 IN OUT UINTN DataLength
,
1404 OUT UINT32
*TransferResult
1407 if (Data
== NULL
|| DataLength
== 0 || TransferResult
== NULL
) {
1408 return EFI_INVALID_PARAMETER
;
1411 return EFI_UNSUPPORTED
;
1416 Submits Async isochronous transfer to a target USB device.
1418 @param his A pointer to the EFI_USB_HC_PROTOCOL instance.
1419 @param DeviceAddress Represents the address of the target device on the USB,
1420 which is assigned during USB enumeration.
1421 @param EndPointAddress End point address
1422 @param MaximumPacketLength Indicates the maximum packet size that the
1423 default control transfer endpoint is capable of
1424 sending or receiving.
1425 @param Data A pointer to the buffer of data that will be transmitted
1426 to USB device or received from USB device.
1427 @param IsochronousCallBack When the transfer complete, the call back function will be called
1428 @param Context Pass to the call back function as parameter
1430 @retval EFI_UNSUPPORTED This interface not available
1431 @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0
1437 OhciAsyncIsochronousTransfer (
1438 IN EFI_USB_HC_PROTOCOL
*This
,
1439 IN UINT8 DeviceAddress
,
1440 IN UINT8 EndPointAddress
,
1441 IN UINT8 MaximumPacketLength
,
1443 IN OUT UINTN DataLength
,
1444 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack
,
1445 IN VOID
*Context OPTIONAL
1449 if (Data
== NULL
|| DataLength
== 0) {
1450 return EFI_INVALID_PARAMETER
;
1453 return EFI_UNSUPPORTED
;
1458 Retrieves the number of root hub ports.
1460 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1461 @param NumOfPorts A pointer to the number of the root hub ports.
1463 @retval EFI_SUCCESS The port number was retrieved successfully.
1467 OhciGetRootHubNumOfPorts (
1468 IN EFI_USB_HC_PROTOCOL
*This
,
1469 OUT UINT8
*NumOfPorts
1472 USB_OHCI_HC_DEV
*Ohc
;
1473 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1475 if (NumOfPorts
== NULL
) {
1476 return EFI_INVALID_PARAMETER
;
1479 *NumOfPorts
= (UINT8
)OhciGetRootHubDescriptor(Ohc
, RH_NUM_DS_PORTS
);
1485 Retrieves the current status of a USB root hub port.
1487 @param This A pointer to the EFI_USB_HC_PROTOCOL.
1488 @param PortNumber Specifies the root hub port from which the status
1489 is to be retrieved. This value is zero-based. For example,
1490 if a root hub has two ports, then the first port is numbered 0,
1491 and the second port is numbered 1.
1492 @param PortStatus A pointer to the current port status bits and
1493 port status change bits.
1495 @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber
1496 was returned in PortStatus.
1497 @retval EFI_INVALID_PARAMETER Port number not valid
1503 OhciGetRootHubPortStatus (
1504 IN EFI_USB_HC_PROTOCOL
*This
,
1505 IN UINT8 PortNumber
,
1506 OUT EFI_USB_PORT_STATUS
*PortStatus
1509 USB_OHCI_HC_DEV
*Ohc
;
1512 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1514 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1515 if (PortNumber
>= NumOfPorts
) {
1516 return EFI_INVALID_PARAMETER
;
1518 PortStatus
->PortStatus
= 0;
1519 PortStatus
->PortChangeStatus
= 0;
1521 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_CURR_CONNECT_STAT
)) {
1522 PortStatus
->PortStatus
|= USB_PORT_STAT_CONNECTION
;
1524 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_ENABLE_STAT
)) {
1525 PortStatus
->PortStatus
|= USB_PORT_STAT_ENABLE
;
1527 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_SUSPEND_STAT
)) {
1528 PortStatus
->PortStatus
|= USB_PORT_STAT_SUSPEND
;
1530 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_OC_INDICATOR
)) {
1531 PortStatus
->PortStatus
|= USB_PORT_STAT_OVERCURRENT
;
1533 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_RESET_STAT
)) {
1534 PortStatus
->PortStatus
|= USB_PORT_STAT_RESET
;
1536 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_PORT_POWER_STAT
)) {
1537 PortStatus
->PortStatus
|= USB_PORT_STAT_POWER
;
1539 if (OhciReadRootHubPortStatus (Ohc
,PortNumber
, RH_LSDEVICE_ATTACHED
)) {
1540 PortStatus
->PortStatus
|= USB_PORT_STAT_LOW_SPEED
;
1542 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
)) {
1543 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_ENABLE
;
1545 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
)) {
1546 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_CONNECTION
;
1548 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
)) {
1549 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_SUSPEND
;
1551 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
)) {
1552 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_OVERCURRENT
;
1554 if (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
)) {
1555 PortStatus
->PortChangeStatus
|= USB_PORT_STAT_C_RESET
;
1562 Sets a feature for the specified root hub port.
1564 @param This A pointer to the EFI_USB_HC_PROTOCOL.
1565 @param PortNumber Specifies the root hub port whose feature
1566 is requested to be set.
1567 @param PortFeature Indicates the feature selector associated
1568 with the feature set request.
1570 @retval EFI_SUCCESS The feature specified by PortFeature was set for the
1571 USB root hub port specified by PortNumber.
1572 @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue
1573 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1577 OhciSetRootHubPortFeature (
1578 IN EFI_USB_HC_PROTOCOL
*This
,
1579 IN UINT8 PortNumber
,
1580 IN EFI_USB_PORT_FEATURE PortFeature
1583 USB_OHCI_HC_DEV
*Ohc
;
1588 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1589 if (PortNumber
>= NumOfPorts
) {
1590 return EFI_INVALID_PARAMETER
;
1593 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1595 Status
= EFI_SUCCESS
;
1598 switch (PortFeature
) {
1599 case EfiUsbPortPower
:
1600 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_POWER
);
1609 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_POWER_STAT
) == 0 &&
1610 RetryTimes
< MAX_RETRY_TIMES
);
1612 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1613 return EFI_DEVICE_ERROR
;
1617 case EfiUsbPortReset
:
1618 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_RESET
);
1627 } while ((OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
) == 0 ||
1628 OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT
) == 1) &&
1629 RetryTimes
< MAX_RETRY_TIMES
);
1631 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1632 return EFI_DEVICE_ERROR
;
1635 OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
);
1638 case EfiUsbPortEnable
:
1639 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_ENABLE
);
1648 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT
) == 0 &&
1649 RetryTimes
< MAX_RETRY_TIMES
);
1651 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1652 return EFI_DEVICE_ERROR
;
1657 case EfiUsbPortSuspend
:
1658 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_SET_PORT_SUSPEND
);
1667 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT
) == 0 &&
1668 RetryTimes
< MAX_RETRY_TIMES
);
1670 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1671 return EFI_DEVICE_ERROR
;
1676 return EFI_INVALID_PARAMETER
;
1684 Clears a feature for the specified root hub port.
1686 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1687 @param PortNumber Specifies the root hub port whose feature
1688 is requested to be cleared.
1689 @param PortFeature Indicates the feature selector associated with the
1690 feature clear request.
1692 @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the
1693 USB root hub port specified by PortNumber.
1694 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
1695 @retval EFI_DEVICE_ERROR Some error happened when clearing feature
1699 OhciClearRootHubPortFeature (
1700 IN EFI_USB_HC_PROTOCOL
*This
,
1701 IN UINT8 PortNumber
,
1702 IN EFI_USB_PORT_FEATURE PortFeature
1705 USB_OHCI_HC_DEV
*Ohc
;
1711 OhciGetRootHubNumOfPorts (This
, &NumOfPorts
);
1712 if (PortNumber
>= NumOfPorts
) {
1713 return EFI_INVALID_PARAMETER
;
1716 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
1718 Status
= EFI_SUCCESS
;
1720 switch (PortFeature
) {
1721 case EfiUsbPortEnable
:
1722 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_PORT_ENABLE
);
1731 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT
) == 1 &&
1732 RetryTimes
< MAX_RETRY_TIMES
);
1734 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1735 return EFI_DEVICE_ERROR
;
1739 case EfiUsbPortSuspend
:
1740 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_SUSPEND_STATUS
);
1749 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT
) == 1 &&
1750 RetryTimes
< MAX_RETRY_TIMES
);
1752 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1753 return EFI_DEVICE_ERROR
;
1757 case EfiUsbPortReset
:
1760 case EfiUsbPortPower
:
1761 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CLEAR_PORT_POWER
);
1770 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_POWER_STAT
) == 1 &&
1771 RetryTimes
< MAX_RETRY_TIMES
);
1773 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1774 return EFI_DEVICE_ERROR
;
1778 case EfiUsbPortConnectChange
:
1779 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
);
1788 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_CONNECT_STATUS_CHANGE
) == 1 &&
1789 RetryTimes
< MAX_RETRY_TIMES
);
1791 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1792 return EFI_DEVICE_ERROR
;
1796 case EfiUsbPortResetChange
:
1797 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
);
1806 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_RESET_STAT_CHANGE
) == 1 &&
1807 RetryTimes
< MAX_RETRY_TIMES
);
1809 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1810 return EFI_DEVICE_ERROR
;
1815 case EfiUsbPortEnableChange
:
1816 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
);
1825 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_ENABLE_STAT_CHANGE
) == 1 &&
1826 RetryTimes
< MAX_RETRY_TIMES
);
1828 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1829 return EFI_DEVICE_ERROR
;
1833 case EfiUsbPortSuspendChange
:
1834 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
);
1843 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_PORT_SUSPEND_STAT_CHANGE
) == 1 &&
1844 RetryTimes
< MAX_RETRY_TIMES
);
1846 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1847 return EFI_DEVICE_ERROR
;
1851 case EfiUsbPortOverCurrentChange
:
1852 Status
= OhciSetRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
);
1861 } while (OhciReadRootHubPortStatus (Ohc
, PortNumber
, RH_OC_INDICATOR_CHANGE
) == 1 &&
1862 RetryTimes
< MAX_RETRY_TIMES
);
1864 if (RetryTimes
>= MAX_RETRY_TIMES
) {
1865 return EFI_DEVICE_ERROR
;
1870 return EFI_INVALID_PARAMETER
;
1876 EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding
= {
1877 OHCIDriverBindingSupported
,
1878 OHCIDriverBindingStart
,
1879 OHCIDriverBindingStop
,
1887 Entry point for EFI drivers.
1889 @param ImageHandle EFI_HANDLE.
1890 @param SystemTable EFI_SYSTEM_TABLE.
1892 @retval EFI_SUCCESS Driver is successfully loaded.
1893 @return Others Failed.
1898 OHCIDriverEntryPoint (
1899 IN EFI_HANDLE ImageHandle
,
1900 IN EFI_SYSTEM_TABLE
*SystemTable
1903 return EfiLibInstallDriverBindingComponentName2 (
1906 &gOhciDriverBinding
,
1908 &gOhciComponentName
,
1909 &gOhciComponentName2
1915 Test to see if this driver supports ControllerHandle. Any
1916 ControllerHandle that has UsbHcProtocol installed will be supported.
1918 @param This Protocol instance pointer.
1919 @param Controller Handle of device to test.
1920 @param RemainingDevicePath Not used.
1922 @return EFI_SUCCESS This driver supports this device.
1923 @return EFI_UNSUPPORTED This driver does not support this device.
1928 OHCIDriverBindingSupported (
1929 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1930 IN EFI_HANDLE Controller
,
1931 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
1935 EFI_PCI_IO_PROTOCOL
*PciIo
;
1936 USB_CLASSC UsbClassCReg
;
1938 // Test whether there is PCI IO Protocol attached on the controller handle.
1940 Status
= gBS
->OpenProtocol (
1942 &gEfiPciIoProtocolGuid
,
1944 This
->DriverBindingHandle
,
1946 EFI_OPEN_PROTOCOL_BY_DRIVER
1949 if (EFI_ERROR (Status
)) {
1950 return EFI_UNSUPPORTED
;
1953 Status
= PciIo
->Pci
.Read (
1956 PCI_CLASSCODE_OFFSET
,
1957 sizeof (USB_CLASSC
) / sizeof (UINT8
),
1961 if (EFI_ERROR (Status
)) {
1962 Status
= EFI_UNSUPPORTED
;
1966 // Test whether the controller belongs to OHCI type
1968 if ((UsbClassCReg
.BaseCode
!= PCI_CLASS_SERIAL
) ||
1969 (UsbClassCReg
.SubClassCode
!= PCI_CLASS_SERIAL_USB
) ||
1970 (UsbClassCReg
.ProgInterface
!= PCI_IF_OHCI
)
1973 Status
= EFI_UNSUPPORTED
;
1976 gBS
->CloseProtocol (
1978 &gEfiPciIoProtocolGuid
,
1979 This
->DriverBindingHandle
,
1989 Allocate and initialize the empty OHCI device.
1991 @param PciIo The PCIIO to use.
1992 @param OriginalPciAttributes The original PCI attributes.
1994 @return Allocated OHCI device If err, return NULL.
2000 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2001 IN UINT64 OriginalPciAttributes
2004 USB_OHCI_HC_DEV
*Ohc
;
2007 EFI_PHYSICAL_ADDRESS PhyAddr
;
2012 Ohc
= AllocateZeroPool (sizeof (USB_OHCI_HC_DEV
));
2017 Ohc
->Signature
= USB_OHCI_HC_DEV_SIGNATURE
;
2020 Ohc
->UsbHc
.Reset
= OhciReset
;
2021 Ohc
->UsbHc
.GetState
= OhciGetState
;
2022 Ohc
->UsbHc
.SetState
= OhciSetState
;
2023 Ohc
->UsbHc
.ControlTransfer
= OhciControlTransfer
;
2024 Ohc
->UsbHc
.BulkTransfer
= OhciBulkTransfer
;
2025 Ohc
->UsbHc
.AsyncInterruptTransfer
= OhciAsyncInterruptTransfer
;
2026 Ohc
->UsbHc
.SyncInterruptTransfer
= OhciSyncInterruptTransfer
;
2027 Ohc
->UsbHc
.IsochronousTransfer
= OhciIsochronousTransfer
;
2028 Ohc
->UsbHc
.AsyncIsochronousTransfer
= OhciAsyncIsochronousTransfer
;
2029 Ohc
->UsbHc
.GetRootHubPortNumber
= OhciGetRootHubNumOfPorts
;
2030 Ohc
->UsbHc
.GetRootHubPortStatus
= OhciGetRootHubPortStatus
;
2031 Ohc
->UsbHc
.SetRootHubPortFeature
= OhciSetRootHubPortFeature
;
2032 Ohc
->UsbHc
.ClearRootHubPortFeature
= OhciClearRootHubPortFeature
;
2033 Ohc
->UsbHc
.MajorRevision
= 0x1;
2034 Ohc
->UsbHc
.MinorRevision
= 0x1;
2036 Ohc
->OriginalPciAttributes
= OriginalPciAttributes
;
2038 Ohc
->HccaMemoryBlock
= NULL
;
2039 Ohc
->HccaMemoryMapping
= NULL
;
2040 Ohc
->HccaMemoryBuf
= NULL
;
2041 Ohc
->HccaMemoryPages
= 0;
2042 Ohc
->InterruptContextList
= NULL
;
2043 Ohc
->ControllerNameTable
= NULL
;
2044 Ohc
->HouseKeeperTimer
= NULL
;
2046 Ohc
->MemPool
= UsbHcInitMemPool(PciIo
, TRUE
, 0);
2047 if(Ohc
->MemPool
== NULL
) {
2048 goto FREE_DEV_BUFFER
;
2052 Pages
= EFI_SIZE_TO_PAGES (Bytes
);
2054 Status
= PciIo
->AllocateBuffer (
2057 EfiBootServicesData
,
2063 if (EFI_ERROR (Status
)) {
2067 Status
= PciIo
->Map (
2069 EfiPciIoOperationBusMasterCommonBuffer
,
2076 if (EFI_ERROR (Status
) || (Bytes
!= 4096)) {
2080 Ohc
->HccaMemoryBlock
= (HCCA_MEMORY_BLOCK
*)(UINTN
)PhyAddr
;
2081 Ohc
->HccaMemoryMapping
= Map
;
2082 Ohc
->HccaMemoryBuf
= (VOID
*)(UINTN
)Buf
;
2083 Ohc
->HccaMemoryPages
= Pages
;
2088 PciIo
->FreeBuffer (PciIo
, Pages
, Buf
);
2090 UsbHcFreeMemPool (Ohc
->MemPool
);
2098 Free the OHCI device and release its associated resources.
2100 @param Ohc The OHCI device to release.
2105 IN USB_OHCI_HC_DEV
*Ohc
2108 OhciFreeFixedIntMemory (Ohc
);
2110 if (Ohc
->HouseKeeperTimer
!= NULL
) {
2111 gBS
->CloseEvent (Ohc
->HouseKeeperTimer
);
2114 if (Ohc
->ExitBootServiceEvent
!= NULL
) {
2115 gBS
->CloseEvent (Ohc
->ExitBootServiceEvent
);
2118 if (Ohc
->MemPool
!= NULL
) {
2119 UsbHcFreeMemPool (Ohc
->MemPool
);
2122 if (Ohc
->HccaMemoryMapping
!= NULL
) {
2123 Ohc
->PciIo
->FreeBuffer (Ohc
->PciIo
, Ohc
->HccaMemoryPages
, Ohc
->HccaMemoryBuf
);
2126 if (Ohc
->ControllerNameTable
!= NULL
) {
2127 FreeUnicodeStringTable (Ohc
->ControllerNameTable
);
2134 Uninstall all Ohci Interface.
2136 @param Controller Controller handle.
2137 @param This Protocol instance pointer.
2142 IN EFI_HANDLE Controller
,
2143 IN EFI_USB_HC_PROTOCOL
*This
2146 USB_OHCI_HC_DEV
*Ohc
;
2149 // Retrieve private context structure
2151 Ohc
= USB_OHCI_HC_DEV_FROM_THIS (This
);
2154 // Uninstall the USB_HC and USB_HC2 protocol
2156 gBS
->UninstallProtocolInterface (
2158 &gEfiUsbHcProtocolGuid
,
2163 // Cancel the timer event
2165 gBS
->SetTimer (Ohc
->HouseKeeperTimer
, TimerCancel
, 0);
2168 // Stop the host controller
2170 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| ISOCHRONOUS_ENABLE
| BULK_ENABLE
, 0);
2171 This
->Reset (This
, EFI_USB_HC_RESET_GLOBAL
);
2172 This
->SetState (This
, EfiUsbHcStateHalt
);
2177 OhciFreeDynamicIntMemory (Ohc
);
2180 // Restore original PCI attributes
2182 Ohc
->PciIo
->Attributes (
2184 EfiPciIoAttributeOperationSet
,
2185 Ohc
->OriginalPciAttributes
,
2190 // Free the private context structure
2197 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
2199 @param Event Pointer to this event
2200 @param Context Event handler private data
2204 OhcExitBootService (
2209 USB_OHCI_HC_DEV
*Ohc
;
2210 EFI_USB_HC_PROTOCOL
*UsbHc
;
2211 Ohc
= (USB_OHCI_HC_DEV
*) Context
;
2213 UsbHc
= &Ohc
->UsbHc
;
2215 // Stop the Host Controller
2217 //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);
2218 OhciSetHcControl (Ohc
, PERIODIC_ENABLE
| CONTROL_ENABLE
| ISOCHRONOUS_ENABLE
| BULK_ENABLE
, 0);
2219 UsbHc
->Reset (UsbHc
, EFI_USB_HC_RESET_GLOBAL
);
2220 UsbHc
->SetState (UsbHc
, EfiUsbHcStateHalt
);
2227 Starting the Usb OHCI Driver.
2229 @param This Protocol instance pointer.
2230 @param Controller Handle of device to test.
2231 @param RemainingDevicePath Not used.
2233 @retval EFI_SUCCESS This driver supports this device.
2234 @retval EFI_UNSUPPORTED This driver does not support this device.
2235 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
2236 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
2241 OHCIDriverBindingStart (
2242 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2243 IN EFI_HANDLE Controller
,
2244 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
2248 EFI_PCI_IO_PROTOCOL
*PciIo
;
2249 USB_OHCI_HC_DEV
*Ohc
;
2251 UINT64 OriginalPciAttributes
;
2252 BOOLEAN PciAttributesSaved
;
2255 // Open PCIIO, then enable the HC device and turn off emulation
2258 Status
= gBS
->OpenProtocol (
2260 &gEfiPciIoProtocolGuid
,
2262 This
->DriverBindingHandle
,
2264 EFI_OPEN_PROTOCOL_BY_DRIVER
2267 if (EFI_ERROR (Status
)) {
2271 PciAttributesSaved
= FALSE
;
2273 // Save original PCI attributes
2275 Status
= PciIo
->Attributes (
2277 EfiPciIoAttributeOperationGet
,
2279 &OriginalPciAttributes
2282 if (EFI_ERROR (Status
)) {
2285 PciAttributesSaved
= TRUE
;
2288 // Robustnesss improvement such as for UoL
2289 // Default is not required.
2291 //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
2292 // OhciTurnOffUsbEmulation (PciIo);
2295 Status
= PciIo
->Attributes (
2297 EfiPciIoAttributeOperationSupported
,
2301 if (!EFI_ERROR (Status
)) {
2302 Supports
&= EFI_PCI_DEVICE_ENABLE
;
2303 Status
= PciIo
->Attributes (
2305 EfiPciIoAttributeOperationEnable
,
2311 if (EFI_ERROR (Status
)) {
2315 //Allocate memory for OHC private data structure
2317 Ohc
= OhciAllocateDev(PciIo
, OriginalPciAttributes
);
2319 Status
= EFI_OUT_OF_RESOURCES
;
2323 //Status = OhciInitializeInterruptList ( Uhc );
2324 //if (EFI_ERROR (Status)) {
2331 Status
= gBS
->CreateEvent (
2332 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
2336 &Ohc
->HouseKeeperTimer
2338 if (EFI_ERROR (Status
)) {
2342 Status
= gBS
->SetTimer (Ohc
->HouseKeeperTimer
, TimerPeriodic
, 10 * 1000 * 10);
2343 if (EFI_ERROR (Status
)) {
2348 //Install Host Controller Protocol
2350 Status
= gBS
->InstallProtocolInterface (
2352 &gEfiUsbHcProtocolGuid
,
2353 EFI_NATIVE_INTERFACE
,
2356 if (EFI_ERROR (Status
)) {
2357 DEBUG ((EFI_D_INFO
, "Install protocol error"));
2361 // Create event to stop the HC when exit boot service.
2363 Status
= gBS
->CreateEventEx (
2368 &gEfiEventExitBootServicesGuid
,
2369 &Ohc
->ExitBootServiceEvent
2371 if (EFI_ERROR (Status
)) {
2372 DEBUG ((EFI_D_INFO
, "Create exit boot event error"));
2373 goto UNINSTALL_USBHC
;
2377 gOhciComponentName
.SupportedLanguages
,
2378 &Ohc
->ControllerNameTable
,
2379 L
"Usb Universal Host Controller",
2384 gOhciComponentName2
.SupportedLanguages
,
2385 &Ohc
->ControllerNameTable
,
2386 L
"Usb Universal Host Controller",
2393 gBS
->UninstallMultipleProtocolInterfaces (
2395 &gEfiUsbHcProtocolGuid
,
2404 if (PciAttributesSaved
) {
2406 // Restore original PCI attributes
2410 EfiPciIoAttributeOperationSet
,
2411 OriginalPciAttributes
,
2416 gBS
->CloseProtocol (
2418 &gEfiPciIoProtocolGuid
,
2419 This
->DriverBindingHandle
,
2426 Stop this driver on ControllerHandle. Support stopping any child handles
2427 created by this driver.
2429 @param This Protocol instance pointer.
2430 @param Controller Handle of device to stop driver on.
2431 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2432 @param ChildHandleBuffer List of handles for the children we need to stop.
2440 OHCIDriverBindingStop (
2441 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2442 IN EFI_HANDLE Controller
,
2443 IN UINTN NumberOfChildren
,
2444 IN EFI_HANDLE
*ChildHandleBuffer
2448 EFI_USB_HC_PROTOCOL
*UsbHc
;
2450 Status
= gBS
->OpenProtocol (
2452 &gEfiUsbHcProtocolGuid
,
2454 This
->DriverBindingHandle
,
2456 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2458 if (EFI_ERROR (Status
)) {
2462 OhciCleanDevUp(Controller
, UsbHc
);
2464 gBS
->CloseProtocol (
2466 &gEfiPciIoProtocolGuid
,
2467 This
->DriverBindingHandle
,