2 OHCI transfer scheduling routines.
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.
21 Add an item of interrupt context
23 @param Ohc UHC private data
24 @param NewEntry New entry to add
26 @retval EFI_SUCCESS Item successfully added
30 OhciAddInterruptContextEntry (
31 IN USB_OHCI_HC_DEV
*Ohc
,
32 IN INTERRUPT_CONTEXT_ENTRY
*NewEntry
35 INTERRUPT_CONTEXT_ENTRY
*Entry
;
38 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
40 if (Ohc
->InterruptContextList
== NULL
) {
41 Ohc
->InterruptContextList
= NewEntry
;
43 Entry
= Ohc
->InterruptContextList
;
44 while (Entry
->NextEntry
!= NULL
) {
45 Entry
= Entry
->NextEntry
;
47 Entry
->NextEntry
= NewEntry
;
50 gBS
->RestoreTPL (OriginalTPL
);
58 Free a interrupt context entry
60 @param Ohc UHC private data
61 @param Entry Pointer to an interrupt context entry
63 @retval EFI_SUCCESS Entry freed
64 @retval EFI_INVALID_PARAMETER Entry is NULL
68 OhciFreeInterruptContextEntry (
69 IN USB_OHCI_HC_DEV
*Ohc
,
70 IN INTERRUPT_CONTEXT_ENTRY
*Entry
75 return EFI_INVALID_PARAMETER
;
77 if (Entry
->UCBufferMapping
!= NULL
) {
78 Ohc
->PciIo
->Unmap(Ohc
->PciIo
, Entry
->UCBufferMapping
);
80 if (Entry
->UCBuffer
!= NULL
) {
81 FreePool(Entry
->UCBuffer
);
83 while (Entry
->DataTd
) {
85 Entry
->DataTd
= (TD_DESCRIPTOR
*)(UINTN
)(Entry
->DataTd
->NextTDPointer
);
86 UsbHcFreeMem(Ohc
->MemPool
, Td
, sizeof(TD_DESCRIPTOR
));
95 Free entries match the device address and endpoint address
97 @Param Ohc UHC private date
98 @Param DeviceAddress Item to free must match this device address
99 @Param EndPointAddress Item to free must match this end point address
100 @Param DataToggle DataToggle for output
102 @retval EFI_SUCCESS Items match the requirement removed
106 OhciFreeInterruptContext(
107 IN USB_OHCI_HC_DEV
*Ohc
,
108 IN UINT8 DeviceAddress
,
109 IN UINT8 EndPointAddress
,
110 OUT UINT8
*DataToggle
113 INTERRUPT_CONTEXT_ENTRY
*Entry
;
114 INTERRUPT_CONTEXT_ENTRY
*TempEntry
;
118 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
120 while (Ohc
->InterruptContextList
!= NULL
&&
121 Ohc
->InterruptContextList
->DeviceAddress
== DeviceAddress
&&
122 Ohc
->InterruptContextList
->EndPointAddress
== EndPointAddress
) {
123 TempEntry
= Ohc
->InterruptContextList
;
124 Ohc
->InterruptContextList
= Ohc
->InterruptContextList
->NextEntry
;
125 if (DataToggle
!= NULL
) {
126 *DataToggle
= (UINT8
) (TempEntry
->DataTd
->Word0
.DataToggle
& 0x1);
128 OhciFreeInterruptContextEntry (Ohc
, TempEntry
);
131 Entry
= Ohc
->InterruptContextList
;
133 gBS
->RestoreTPL (OriginalTPL
);
136 while (Entry
->NextEntry
!= NULL
) {
137 if (Entry
->NextEntry
->DeviceAddress
== DeviceAddress
&&
138 Entry
->NextEntry
->EndPointAddress
== EndPointAddress
) {
139 TempEntry
= Entry
->NextEntry
;
140 Entry
->NextEntry
= Entry
->NextEntry
->NextEntry
;
141 if (DataToggle
!= NULL
) {
142 *DataToggle
= (UINT8
) (TempEntry
->DataTd
->Word0
.DataToggle
& 0x1);
144 OhciFreeInterruptContextEntry (Ohc
, TempEntry
);
146 Entry
= Entry
->NextEntry
;
150 gBS
->RestoreTPL (OriginalTPL
);
158 Convert Error code from OHCI format to EFI format
160 @Param ErrorCode ErrorCode in OHCI format
162 @retval ErrorCode in EFI format
170 UINT32 TransferResult
;
174 TransferResult
= EFI_USB_NOERROR
;
177 case TD_TOBE_PROCESSED
:
178 case TD_TOBE_PROCESSED_2
:
179 TransferResult
= EFI_USB_ERR_NOTEXECUTE
;
182 case TD_DEVICE_STALL
:
183 TransferResult
= EFI_USB_ERR_STALL
;
186 case TD_BUFFER_OVERRUN
:
187 case TD_BUFFER_UNDERRUN
:
188 TransferResult
= EFI_USB_ERR_BUFFER
;
192 TransferResult
= EFI_USB_ERR_CRC
;
196 TransferResult
= EFI_USB_ERR_TIMEOUT
;
199 case TD_BITSTUFFING_ERROR
:
200 TransferResult
= EFI_USB_ERR_BITSTUFF
;
204 TransferResult
= EFI_USB_ERR_SYSTEM
;
207 return TransferResult
;
215 @Param Ohc UHC private data
216 @Param Td TD_DESCRIPTOR
217 @Param Result Result to return
219 @retval TRUE means OK
220 @retval FLASE means Error or Short packet
224 OhciCheckTDsResults (
225 IN USB_OHCI_HC_DEV
*Ohc
,
226 IN TD_DESCRIPTOR
*Td
,
230 UINT32 TdCompletionCode
;
232 *Result
= EFI_USB_NOERROR
;
235 TdCompletionCode
= Td
->Word0
.ConditionCode
;
237 *Result
|= ConvertErrorCode(TdCompletionCode
);
239 // if any error encountered, stop processing the left TDs.
245 Td
= (TD_DESCRIPTOR
*)(UINTN
)(Td
->NextTDPointer
);
254 Check the task status on an ED
256 @Param Ed Pointer to the ED task that TD hooked on
257 @Param HeadTd TD header for current transaction
259 @retval Task Status Code
265 IN ED_DESCRIPTOR
*Ed
,
266 IN TD_DESCRIPTOR
*HeadTd
,
267 OUT OHCI_ED_RESULT
*EdResult
270 while(HeadTd
!= NULL
) {
271 if (HeadTd
->NextTDPointer
== 0) {
274 if (HeadTd
->Word0
.ConditionCode
!= 0) {
275 return HeadTd
->Word0
.ConditionCode
;
277 EdResult
->NextToggle
= ((UINT8
)(HeadTd
->Word0
.DataToggle
) & BIT0
) ^ BIT0
;
278 HeadTd
= (TD_DESCRIPTOR
*)(UINTN
)(HeadTd
->NextTDPointer
);
280 if (OhciGetEDField (Ed
, ED_TDHEAD_PTR
) != OhciGetEDField (Ed
, ED_TDTAIL_PTR
)) {
281 return TD_TOBE_PROCESSED
;
288 Check the task status
290 @Param Ohc UHC private data
291 @Param ListType Pipe type
292 @Param Ed Pointer to the ED task hooked on
293 @Param HeadTd Head of TD corresponding to the task
294 @Param ErrorCode return the ErrorCode
296 @retval EFI_SUCCESS Task done
297 @retval EFI_NOT_READY Task on processing
298 @retval EFI_DEVICE_ERROR Some error occured
303 IN USB_OHCI_HC_DEV
*Ohc
,
304 IN DESCRIPTOR_LIST_TYPE ListType
,
305 IN ED_DESCRIPTOR
*Ed
,
306 IN TD_DESCRIPTOR
*HeadTd
,
307 OUT OHCI_ED_RESULT
*EdResult
310 EdResult
->ErrorCode
= TD_TOBE_PROCESSED
;
314 if (OhciGetHcCommandStatus (Ohc
, CONTROL_LIST_FILLED
) != 0) {
315 return EFI_NOT_READY
;
319 if (OhciGetHcCommandStatus (Ohc
, BULK_LIST_FILLED
) != 0) {
320 return EFI_NOT_READY
;
327 EdResult
->ErrorCode
= CheckEDStatus (Ed
, HeadTd
, EdResult
);
329 if (EdResult
->ErrorCode
== TD_NO_ERROR
) {
331 } else if (EdResult
->ErrorCode
== TD_TOBE_PROCESSED
) {
332 return EFI_NOT_READY
;
334 return EFI_DEVICE_ERROR
;
341 Convert TD condition code to Efi Status
343 @Param ConditionCode Condition code to convert
345 @retval EFI_SUCCESS No error occured
346 @retval EFI_NOT_READY TD still on processing
347 @retval EFI_DEVICE_ERROR Error occured in processing TD
352 OhciTDConditionCodeToStatus (
353 IN UINT32 ConditionCode
356 if (ConditionCode
== TD_NO_ERROR
) {
360 if (ConditionCode
== TD_TOBE_PROCESSED
) {
361 return EFI_NOT_READY
;
364 return EFI_DEVICE_ERROR
;
369 Invoke callbacks hooked on done TDs
371 @Param Entry Interrupt transfer transaction information data structure
372 @Param Context Ohc private data
377 OhciInvokeInterruptCallBack(
378 IN INTERRUPT_CONTEXT_ENTRY
*Entry
,
382 //Generally speaking, Keyboard driver should not
383 //check the Keyboard buffer if an error happens, it will be robust
384 //if we NULLed the buffer once error happens
386 Entry
->CallBackFunction (
393 Entry
->CallBackFunction (
394 (VOID
*)(UINTN
)(Entry
->DataTd
->DataBuffer
),
395 Entry
->DataTd
->ActualSendLength
,
405 Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs
407 @param Event Event handle
408 @param Context Device private data
420 USB_OHCI_HC_DEV
*Ohc
;
421 INTERRUPT_CONTEXT_ENTRY
*Entry
;
422 INTERRUPT_CONTEXT_ENTRY
*PreEntry
;
424 TD_DESCRIPTOR
*DataTd
;
425 TD_DESCRIPTOR
*HeadTd
;
431 Ohc
= (USB_OHCI_HC_DEV
*) Context
;
432 OriginalTPL
= gBS
->RaiseTPL(TPL_NOTIFY
);
434 Entry
= Ohc
->InterruptContextList
;
437 while(Entry
!= NULL
) {
439 OhciCheckTDsResults(Ohc
, Entry
->DataTd
, &Result
);
440 if (((Result
& EFI_USB_ERR_STALL
) == EFI_USB_ERR_STALL
) ||
441 ((Result
& EFI_USB_ERR_NOTEXECUTE
) == EFI_USB_ERR_NOTEXECUTE
)) {
443 Entry
= Entry
->NextEntry
;
447 if (Entry
->CallBackFunction
!= NULL
) {
448 OhciInvokeInterruptCallBack (Entry
, Result
);
449 if (Ohc
->InterruptContextList
== NULL
) {
450 gBS
->RestoreTPL (OriginalTPL
);
454 if (Entry
->IsPeriodic
) {
457 HeadTd
= Entry
->DataTd
;
460 if (Result
== EFI_USB_NOERROR
) {
462 // Update toggle if there is no error, and re-submit the interrupt Ed&Tds
464 if ((Ed
!= NULL
) && (DataTd
!= NULL
)) {
468 // From hcir1_0a.pdf 4.2.2
469 // ToggleCarry:This bit is the data toggle carry bit,
470 // Whenever a TD is retired, this bit is written to
471 // contain the last data toggle value(LSb of data Toggel
472 // file) from the retired TD.
473 // This field is not used for Isochronous Endpoints
478 Toggle
= (UINT8
) OhciGetEDField (Ed
, ED_DTTOGGLE
);
479 while(DataTd
!= NULL
) {
480 if (DataTd
->NextTDPointer
== 0) {
481 DataTd
->Word0
.DataToggle
= 0;
484 OhciSetTDField (DataTd
, TD_DT_TOGGLE
, Toggle
);
486 DataTd
= (TD_DESCRIPTOR
*)(UINTN
)(DataTd
->NextTDPointer
);
490 // HC will only update DataToggle, ErrorCount, ConditionCode
491 // CurrentBufferPointer & NextTD, so we only need to update
492 // them once we want to active them again
495 while (DataTd
!= NULL
) {
496 if (DataTd
->NextTDPointer
== 0) {
497 OhciSetTDField (DataTd
, TD_ERROR_CNT
| TD_COND_CODE
| TD_CURR_BUFFER_PTR
| TD_NEXT_PTR
, 0);
500 OhciSetTDField (DataTd
, TD_ERROR_CNT
, 0);
501 OhciSetTDField (DataTd
, TD_COND_CODE
, TD_TOBE_PROCESSED
);
502 DataTd
->NextTD
= DataTd
->NextTDPointer
;
503 DataTd
->CurrBufferPointer
= DataTd
->DataBuffer
;
504 DataTd
= (TD_DESCRIPTOR
*)(UINTN
)(DataTd
->NextTDPointer
);
507 // Active current Ed,Td
509 // HC will only update Halted, ToggleCarry & TDQueueHeadPointer,
510 // So we only need to update them once we want to active them again.
512 if ((Ed
!= NULL
) && (DataTd
!= NULL
)) {
513 Ed
->Word2
.TdHeadPointer
= (UINT32
)((UINTN
)HeadTd
>>4);
514 OhciSetEDField (Ed
, ED_HALTED
| ED_DTTOGGLE
, 0);
519 if (PreEntry
== NULL
) {
520 Ohc
->InterruptContextList
= Entry
->NextEntry
;
523 PreEntry
->NextEntry
= Entry
->NextEntry
;
525 OhciFreeInterruptContextEntry (Ohc
, PreEntry
);
526 gBS
->RestoreTPL (OriginalTPL
);
530 Entry
= Entry
->NextEntry
;
532 gBS
->RestoreTPL (OriginalTPL
);