summaryrefslogtreecommitdiff
path: root/Core/EM/usb/rt/usbCCID.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/usb/rt/usbCCID.c')
-rw-r--r--Core/EM/usb/rt/usbCCID.c5033
1 files changed, 5033 insertions, 0 deletions
diff --git a/Core/EM/usb/rt/usbCCID.c b/Core/EM/usb/rt/usbCCID.c
new file mode 100644
index 0000000..c5bac50
--- /dev/null
+++ b/Core/EM/usb/rt/usbCCID.c
@@ -0,0 +1,5033 @@
+//****************************************************************************
+//****************************************************************************
+//** **
+//** (C)Copyright 1985-2016, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Norcross, GA 30093 **
+//** **
+//** Phone (770)-246-8600 **
+//** **
+//****************************************************************************
+//****************************************************************************
+
+//****************************************************************************
+// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbCCID.c 19 10/16/16 10:12p Wilsonlee $
+//
+// $Revision: 19 $
+//
+// $Date: 10/16/16 10:12p $
+//****************************************************************************
+//****************************************************************************
+// Revision History
+// ----------------
+//
+// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbCCID.c $
+//
+// 19 10/16/16 10:12p Wilsonlee
+// [TAG] EIP288158
+// [Category] Improvement
+// [Description] Check if gUsbData is integrity.
+// [Files] amiusb.cif, usbsb.c, AmiUsbLib.cif, AmiUsbLib.sdl,
+// AmiUsbSmmGlobalDataValidationLib.c,
+// AmiUsbSmmGlobalDataValidationLib.cif,
+// AmiUsbSmmGlobalDataValidationLib.mak, Crc32.c, amiusb.c, amiusb.h,
+// ehci.c, elib.c, ohci.c, syskbc.c, uhci.c, usb.c, usbCCID.c, usbdef.h,
+// usbhid.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c, usbrt.mak, xhci.c,
+// amiusbhc.c, efiusbccid.c, efiusbmass.c, uhcd.c, usbmisc.c,
+// AmiUsbController.h, AmiUsbLibInclude.cif,
+// AmiUsbSmmGlobalDataValidationLib.h
+//
+// 18 7/07/16 1:09a Wilsonlee
+// [TAG] EIP277810
+// [Category] Improvement
+// [Description] Validate the memory buffer is entirely outside of SMM.
+// [Files] usbsb.c, amiusb.c, ehci.c, ohci.c, uhci.c, usbCCID.c,
+// usbdef.h, usbmass.c, xhci.c, amiusbhc.c, efiusbccid.c, efiusbmass.c,
+// uhcd.c, uhcd.h, usbmisc.c
+//
+// 17 3/02/16 9:41p Wilsonlee
+// [TAG] EIP254309
+// [Category] Bug Fix
+// [Severity] Normal
+// [Symptom] GK-FORCE K83 USB KB function abnormal.
+// [RootCause] This device has an interrupt out endpoint and doesn't
+// support "Set Report" request.
+// [Solution] Use the interrupt out endpoint instead of sending "Set
+// Report" request.
+// [Files] AmiUsbController.h, xhci.c, usbmass.c, usbkbd.h, usbkbd.c,
+// usbhub.c, usbhid.c, usbdef.h, usbCCID.c, usb.c, uhci.c, ohci.c, ehci.c,
+// amiusb.h, efiusbms,c, amiusbhc.c
+//
+// 16 4/10/15 3:10a Wilsonlee
+// [TAG] EIP207413
+// [Category] Improvement
+// [Description] Install UsbApiTable and UsbMassApitTable in
+// AmiUsbSmmProtocol.
+// [Files] amiusbhc.c, AmiUsbController.h, usbdef.h, usbCCID.c, uhci.c,
+// ehci.c, amiusbrtCCID.h, amiusb.h, amiusb.c, uhcd.c
+//
+// 15 3/05/15 3:54a Wilsonlee
+// [TAG] EIP203888
+// [Category] Improvement
+// [Description] RateAndProtocolManagement() default return changed from
+// EFI_DEVICE_ERROR to EFI_SUCCESS.
+// [Files] usbCCID.c
+//
+// 14 2/16/15 2:45a Wilsonlee
+// [TAG] EIP205373
+// [Category] Improvement
+// [Description] Cppcheck errors in Usb module.
+// [Files] usb.c, usbport.c, uhcd.c, usbCCID.c
+//
+// 13 6/26/14 1:16a Wilsonlee
+// [TAG] EIP173387
+// [Category] Improvement
+// [Description] Remove TODO comments.
+// [Files] usbsetup.c, xhci.c, usbmass.c, usbCCID.c, usb.c, uhci.c,
+// syskbc.c, usbport.c, usbbus.c, uhcd.c, UsbBotPeim.c, PeiXhci.c,
+// PeiEhci.c
+//
+// 12 4/30/14 6:14a Ryanchou
+// [TAG] EIP151374
+// [Category] Improvement
+// [Description] Calculates maximum data length to be reported in the
+// HID device.
+// [Files] ehci.c, ohci.c, uhci.c, usbCCID.c, usbdef.h, usbhid.c,
+// usbhub.c, xhci.c
+//
+// 11 2/26/14 1:55a Wilsonlee
+// [TAG] EIP149854
+// [Category] Improvement
+// [Description] Add data length parameter to polling callback function.
+// [Files] usbkbd.c, uhci.c, usb.c, usbhub.c, usbCCID.c, usbms.c,
+// usbhid.c, usbpoint.c, usbkbd.h, ehci.c, ohci.c, xhci.c, usbdef.h
+//
+// 10 2/11/14 11:47p Rameshr
+// [TAG] EIP152203
+// [Category] Improvement
+// [Description] Hardcoded value for bProtocolNum removed.
+// [Files] usbCCID.c
+//
+// 9 6/20/13 10:22p Wilsonlee
+// [TAG] EIP126814
+// [Category] Bug Fix
+// [Severity] Minor
+// [Symptom] Security code check fail in the function
+// USBAPI_CCIDRequest() in usbCCID.c.
+// [RootCause] The function USBAPI_CCIDRequest() in usbCCID.c reads data
+// from just outside the bounds of aUsbCCIDApiTable.
+// [Solution] Condition is fixed from ">" to ">=".
+// [Files] usbCCID.c
+//
+// 8 4/02/13 7:54a Rameshr
+// [TAG] EIP119028
+// [Category] Bug Fix
+// [Severity] Minor
+// [Symptom] Insert smart card incorrectly (backwards), system will hang
+// 0xA0 .
+// [RootCause] Invalid Status returned
+// [Solution] Add a check whether ATR data is successfully read and
+// processed, If not return error
+//
+// 7 3/19/13 3:59a Ryanchou
+// [TAG] EIP118177
+// [Category] Improvement
+// [Description] Dynamically allocate HCStrucTable at runtime.
+// [Files] usb.sdl, usbport.c, usbsb.c, amiusb.c, ehci.c, ohci.c,
+// syskbc.c, sysnokbc.c, uhci.c, usb.c, usbCCID.c, usbdef.h, usbhid.c,
+// usbhub.c, usbmass.c, usbrt.mak, usb.sd, amiusbhc.c, efiusbccid.c,
+// efiusbhid.c, efiusbmass.c, efiusbms.c, uhcd.c, uhcd.h, uhcd.mak,
+// usbmisc.c, usbsrc.sdl
+//
+// 6 1/23/13 4:36a Wilsonlee
+// [TAG] EIP109538
+// [Category] Improvement
+// [Description] Fix the code check error result.
+// [Files] usbkbd.c, usbCCID.c, usbbus.c, efiusbccid.c
+//
+// 5 11/10/12 6:39a Ryanchou
+// [TAG] EIP99431
+// [Category] Bug Fix
+// [Severity] Minor
+// [Symptom] Cannot use the UsbIo's UsbAsyncInterruptTransfer for
+// keyboard input
+// [RootCause] Stopping EFI USB keyboard driver does not stop the
+// endpoint polling, then application calls UsbAsyncInterruptTransfer,
+// error will be returned.
+// [Solution] Stops endpoint polling and release resource when
+// disconnecting the device driver. And improve the
+// UsbSyncInterruptTransfer.
+// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhci.c, usb.c,
+// usbCCID.c, usbdef.h, usbhub.c, usbkbd.c, usbmass.c, usbms.c,
+// usbpoint.c, amiusbhc.c, efiusbhid.c, usbbus.c, usbbus.h
+//
+// 4 9/28/12 2:38a Wilsonlee
+// [TAG] EIP93154
+// [Category] Improvement
+// [Description] Change the unit of the FixedDelay from 15 us to 1 us.
+// [Files] amiusb.h, xhci.c, ehci.c, ohci.c, uhci.c, usb.c, usbCCID.c,
+// usbmass.c, usbhub.c, elib.c
+//
+// 3 5/02/12 1:55a Rajeshms
+// [TAG] EIP83117
+// [Category] Improvement
+// [Description] Extend the Support to different smart card Readers and
+// smart Cards.
+// [Files] usbCCID.c, amiusbrtCCID.h, usbdef.h, efiusbccid.c,
+// AmiusbCCID.h
+//
+// 2 9/22/11 1:24a Rajeshms
+// [TAG] EIP67832
+// [Category] Bug Fix
+// [Severity] Important
+// [Symptom] When ICC(Smart Card) is unplugged and inserted again , it
+// is not detected.
+// [RootCause] The ChildHandle for the smart card where protocol is
+// installed is not made to zero when it was unplugged.
+// [Solution] The ChilHandle is changed to zero when smart card is
+// unplugged.
+// [Files] usbCCID.c
+//
+// 1 7/12/11 8:04a Ryanchou
+// [TAG] EIP56918
+// [Category] New Feature
+// [Description] Added CCID device support.
+// [Files] amiusb.c, amiusb.h, amiusbrtCCID.h, ehci.c, ohci.c, uhci.c,
+// usb.c, UsbCCID.c, usbdef.h, usbrt.cif, usbsetup.c, efiusbccid.c,
+// framework.cif, uhcd.c, uhcd.cif, uhcd.h, usbsrc.sdl, AmiusbCCID.h,
+// AmiUsbController.h, AmiUSBProtocols.cif
+//
+//
+//****************************************************************************
+
+//<AMI_FHDR_START>
+//-----------------------------------------------------------------------------
+//
+// Name: UsbCCID.c
+//
+// Description: AMI USB CCID Device class support driver
+//
+//-----------------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include "amidef.h"
+#include "usbdef.h"
+#include "amiusb.h"
+#include "amidxelib.h"
+#if USB_RUNTIME_DRIVER_IN_SMM
+#include <AmiBufferValidationLib.h>
+#endif
+
+extern USB_GLOBAL_DATA *gUsbData;
+extern BOOLEAN gCheckUsbApiParameter;
+
+UINT8 gSequence = 0;
+
+VOID _FAR_ *
+USB_MemAlloc(
+ UINT16 wNumBlk
+);
+
+UINT8
+USB_MemFree (
+ VOID _FAR_ * fpPtr,
+ UINT16 wNumBlk
+);
+
+void FixedDelay(
+ IN UINTN
+);
+
+typedef VOID (*API_FUNC)(URP_STRUC*);
+
+extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC pfnCallBackFunction);
+
+// Fi Max Di
+UINT16 FiFmaxDi[] = { 372, 4, 0,
+ 372, 5, 1,
+ 558, 6, 2,
+ 744, 8, 4,
+ 1116, 12, 8,
+ 1488, 16, 16,
+ 1860, 20, 32,
+ 0, 0, 64,
+ 0, 0, 12,
+ 512, 5, 20,
+ 768, 7, 0,
+ 1024, 10, 0,
+ 1536, 15, 0,
+ 2048, 20, 0,
+ 0, 0, 0,
+ 0, 0, 0
+ };
+
+//<AMI_THDR_START>
+//----------------------------------------------------------------------------
+// Name: USBCCIDAPITable - USB CCID API Function Dispatch Table
+//
+// Type: Function Dispatch Table
+//
+// Description: This is the table of functions used by USB CCID API
+//
+//----------------------------------------------------------------------------
+//<AMI_THDR_END>
+
+API_FUNC aUsbCCIDApiTable[] = {
+
+ USBCCIDAPISmartClassDescriptorSMM, // USB Mass API Sub-Func 00h
+ USBCCIDAPIAtrSMM, // USB Mass API Sub-Func 01h
+ USBCCIDAPIPowerupSlotSMM, // USB Mass API Sub-Func 02h
+ USBCCIDAPIPowerDownSlotSMM, // USB Mass API Sub-Func 03h
+ USBCCIDAPIGetSlotStatusSMM, // USB Mass API Sub-Func 04h
+ USBCCIDAPIXfrBlockSMM, // USB Mass API Sub-Func 05h
+ USBCCIDAPIGetParametersSMM, // USB Mass API Sub-Func 06h
+
+};
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDFillDriverEntries
+//
+// Description: This function fills DEV_DRIVER structure
+//
+// Input:
+// fpDevDriver Pointer to the DEV driver
+//
+// Output:
+// None
+//
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+USBCCIDFillDriverEntries (
+ IN OUT DEV_DRIVER *fpDevDriver
+)
+{
+
+ fpDevDriver->bDevType = BIOS_DEV_TYPE_STORAGE;
+ fpDevDriver->bBaseClass = BASE_CLASS_CCID_STORAGE;
+ fpDevDriver->bSubClass = SUB_CLASS_CCID;
+ fpDevDriver->bProtocol = PROTOCOL_CCID;
+ fpDevDriver->bProtocol = 0;
+ fpDevDriver->pfnDeviceInit = USBCCIDInitialize;
+ fpDevDriver->pfnCheckDeviceType = USBCCIDCheckForDevice;
+ fpDevDriver->pfnConfigureDevice = USBCCIDConfigureDevice;
+ fpDevDriver->pfnDisconnectDevice = USBCCIDDisconnectDevice;
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPISmartClassDescriptorSMM
+//
+// Description: This function is part of the USB BIOS MASS API inside SMM
+//
+// Input:
+// fpURPPointer Pointer to the URP structure
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// fpURP->bRetValue USB_SUCESS if data is returned
+//
+// Notes: This API returns 36h bytes of SMART Class Descriptor to the caller.
+// Input Buffer of 36h bytes long is provided by the caller. Caller is
+// USBCCIDAPISmartClassDescriptor in EfiUsbCCID.C
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBCCIDAPISmartClassDescriptorSMM(
+ IN OUT URP_STRUC *Urp
+)
+{
+
+ DEV_INFO *DevInfo;
+ EFI_STATUS EfiStatus = EFI_SUCCESS;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (gCheckUsbApiParameter) {
+ EfiStatus = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDSmartClassDescriptor.fpResponseBuffer),
+ (UINT32)sizeof(SMARTCLASS_DESC));
+ if (EFI_ERROR(EfiStatus)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ gCheckUsbApiParameter = FALSE;
+ }
+#endif
+
+ DevInfo = (DEV_INFO *)(Urp->ApiData.CCIDSmartClassDescriptor.fpDevInfo);
+
+ // Check whether it is a valid CCID Device
+ if (!DevInfo || !DevInfo->pCCIDDescriptor) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ EfiStatus = UsbDevInfoValidation(DevInfo);
+
+ if (EFI_ERROR(EfiStatus)) {
+ Urp->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ MemCopy((UINT8 *)DevInfo->pCCIDDescriptor,
+ (UINT8 *)(Urp->ApiData.CCIDSmartClassDescriptor.fpResponseBuffer),
+ (UINT32)sizeof(SMARTCLASS_DESC)
+ );
+
+ Urp->bRetValue = USB_SUCCESS;
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIAtrSMM
+//
+// Description: This function is part of the USB BIOS MASS API inside SMM
+//
+// Input: fpURPPointer Pointer to the URP structure, it contains the following:
+//
+// Output: fpURPPointer Pointer to the URP structure
+// fpURP->bRetValue : USB_SUCESS if data is returned
+//
+// Notes: This API returns ATR data if present
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+USBCCIDAPIAtrSMM (
+ IN OUT URP_STRUC *Urp
+
+)
+{
+
+ DEV_INFO *DevInfo;
+ ICC_DEVICE *IccDevice;
+ EFI_STATUS EfiStatus = EFI_SUCCESS;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (gCheckUsbApiParameter) {
+ EfiStatus = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDAtr.ATRData),
+ MAX_ATR_LENGTH);
+ if (EFI_ERROR(EfiStatus)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ gCheckUsbApiParameter = FALSE;
+ }
+#endif
+
+ DevInfo = (DEV_INFO *)(Urp->ApiData.CCIDAtr.fpDevInfo);
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!DevInfo || !DevInfo->pCCIDDescriptor) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ EfiStatus = UsbDevInfoValidation(DevInfo);
+
+ if (EFI_ERROR(EfiStatus)) {
+ Urp->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ Urp->bRetValue = USB_ERROR;
+
+ //
+ // Locate the ICCDevice
+ //
+ IccDevice = GetICCDevice(DevInfo, Urp->ApiData.CCIDAtr.Slot);
+
+ if (IccDevice) {
+ if (IccDevice->ConfiguredStatus & ATRDATAPRESENT) {
+ MemCopy((UINT8 *)IccDevice->RawATRData, (UINT8 *)(Urp->ApiData.CCIDAtr.ATRData), MAX_ATR_LENGTH);
+ Urp->bRetValue = USB_SUCCESS;
+ }
+ }
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIPowerupSlotSMM
+//
+// Description: This function is part of the USB BIOS MASS API inside SMM
+//
+// Input:
+// fpURPPointer Pointer to the URP structure
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// fpURP->bRetValue : USB_SUCESS if data is returned
+//
+// Notes: This API powers up the particular slot in CCID and returns ATR data if successful
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+USBCCIDAPIPowerupSlotSMM (
+ IN OUT URP_STRUC *Urp
+
+)
+{
+
+ EFI_STATUS Status;
+ DEV_INFO *DevInfo;
+ ICC_DEVICE *IccDevice;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (gCheckUsbApiParameter) {
+ Status = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDPowerupSlot.ATRData),
+ MAX_ATR_LENGTH);
+ if (EFI_ERROR(Status)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ gCheckUsbApiParameter = FALSE;
+ }
+#endif
+
+ DevInfo = (DEV_INFO *)(Urp->ApiData.CCIDPowerupSlot.fpDevInfo);
+
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!DevInfo || !DevInfo->pCCIDDescriptor) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ Status = UsbDevInfoValidation(DevInfo);
+
+ if (EFI_ERROR(Status)) {
+ Urp->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Locate the ICCDevice
+ //
+ IccDevice = GetICCDevice(DevInfo, Urp->ApiData.CCIDPowerupSlot.Slot);
+
+ if (IccDevice) {
+ //
+ // The slot has been already discovered. Check the status.
+ //
+ if (IccDevice->ConfiguredStatus & VOLTAGEAPPLIED) {
+ //
+ // Power down the device
+ //
+ PCtoRDRIccPowerOff (DevInfo, IccDevice);
+ RDRToPCSlotStatus(DevInfo, IccDevice);
+ }
+ }
+
+ Status = ICCInsertEvent(DevInfo, Urp->ApiData.CCIDPowerupSlot.Slot);
+
+ //
+ // If the card has been successfully poweredup copy ATR data
+ //
+ if (!IccDevice) {
+ IccDevice = GetICCDevice(DevInfo, Urp->ApiData.CCIDPowerupSlot.Slot);
+ if (!IccDevice) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ }
+ Urp->ApiData.CCIDPowerupSlot.bStatus = IccDevice->bStatus;
+ Urp->ApiData.CCIDPowerupSlot.bError = IccDevice->bError;
+
+ if (IccDevice->ConfiguredStatus & ATRDATAPRESENT) {
+ MemCopy((UINT8 *)IccDevice->RawATRData, (UINT8 *)(Urp->ApiData.CCIDPowerupSlot.ATRData), MAX_ATR_LENGTH);
+ }
+
+ Urp->bRetValue = USB_SUCCESS;
+
+ if (Status == EFI_DEVICE_ERROR) {
+ Urp->bRetValue = USB_ERROR;
+ }
+
+ return;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIPowerDownSlotSMM
+//
+// Description: This function is part of the USB BIOS MASS API inside SMM
+//
+// Input:
+// fpURPPointer Pointer to the URP structure, it contains the following:
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// fpURP->bRetValue : USB_SUCESS if data is returned
+//
+// Notes: This API powers down the particular slot.
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+USBCCIDAPIPowerDownSlotSMM (
+ IN OUT URP_STRUC *fpURP
+
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ DEV_INFO *fpDevInfo;
+ ICC_DEVICE *fpICCDevice;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ fpDevInfo = (DEV_INFO *) (fpURP->ApiData.CCIDPowerdownSlot.fpDevInfo);
+
+ fpURP->bRetValue = USB_ERROR;
+
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!fpDevInfo || !fpDevInfo->pCCIDDescriptor) {
+
+ return;
+
+ }
+
+ Status = UsbDevInfoValidation(fpDevInfo);
+
+ if (EFI_ERROR(Status)) {
+ fpURP->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ fpURP->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Locate the ICCDevice
+ //
+ fpICCDevice = GetICCDevice(fpDevInfo, fpURP->ApiData.CCIDPowerdownSlot.Slot);
+
+ if (fpICCDevice) {
+ //
+ // The slot has been already discovered. Check the status.
+ //
+ if (fpICCDevice->ConfiguredStatus & ICCPRESENT) {
+
+ //
+ // Power down the device
+ //
+ Status = PCtoRDRIccPowerOff (fpDevInfo, fpICCDevice);
+ RDRToPCSlotStatus(fpDevInfo, fpICCDevice);
+
+ fpICCDevice->ConfiguredStatus &= (~VOLTAGEAPPLIED);
+
+ fpURP->ApiData.CCIDPowerdownSlot.bStatus = fpICCDevice->bStatus;
+ fpURP->ApiData.CCIDPowerdownSlot.bError = fpICCDevice->bError;
+
+ }
+ }
+
+ fpURP->bRetValue = USB_SUCCESS;
+
+ if (Status == EFI_DEVICE_ERROR){
+ fpURP->bRetValue = USB_ERROR;
+ }
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIGetSlotStatusSMM
+//
+// Description: This function is part of the USB BIOS MASS API inside SMM
+//
+// Input:
+// fpURPPointer Pointer to the URP structure, it contains the following:
+// UINT8 *bStatus;
+// UINT8 *bError;
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// bRetValue Return value
+// bClockStatus Return Value
+//
+// Notes: This API returns information from RDR_to_PC_SlotStatus.
+// Caller is USBCCIDAPIGetSlotStatus in EfiUsbCCID.C
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBCCIDAPIGetSlotStatusSMM (
+ IN OUT URP_STRUC *fpURP
+)
+{
+
+ EFI_STATUS Status;
+ DEV_INFO *fpDevInfo;
+ ICC_DEVICE *fpICCDevice;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ fpDevInfo = (DEV_INFO *) (fpURP->ApiData.CCIDGetSlotStatus.fpDevInfo);
+
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!fpDevInfo || !fpDevInfo->pCCIDDescriptor) {
+
+ fpURP->bRetValue = USB_ERROR;
+ return;
+
+ }
+
+ Status = UsbDevInfoValidation(fpDevInfo);
+
+ if (EFI_ERROR(Status)) {
+ fpURP->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ fpURP->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Locate the ICCDevice
+ //
+ fpICCDevice = GetICCDevice(fpDevInfo, fpURP->ApiData.CCIDGetSlotStatus.Slot);
+ if (!fpICCDevice || !(fpICCDevice->ConfiguredStatus & ICCPRESENT)) {
+
+ fpURP->ApiData.CCIDGetSlotStatus.bStatus = 0x42;
+ fpURP->ApiData.CCIDGetSlotStatus.bError = 0xFE;
+ fpURP->bRetValue = USB_ERROR;
+ return;
+
+ }
+
+ //
+ // Issue the cmd
+ //
+ Status = PCToRDRGetSlotStatus(fpDevInfo, fpICCDevice);
+
+ if (EFI_ERROR(Status)){
+ fpURP->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Get the response
+ //
+ Status = RDRToPCSlotStatus(fpDevInfo, fpICCDevice);
+
+ fpURP->ApiData.CCIDGetSlotStatus.bStatus = fpICCDevice->bStatus;
+ fpURP->ApiData.CCIDGetSlotStatus.bError = fpICCDevice->bError;
+ fpURP->ApiData.CCIDGetSlotStatus.bClockStatus = fpICCDevice->bClockStatus;
+
+ fpURP->bRetValue = USB_SUCCESS;
+
+ if (Status == EFI_DEVICE_ERROR){
+ fpURP->bRetValue = USB_ERROR;
+ }
+
+ return;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIXfrBlockSMM
+//
+// Description: This function is part of the USB BIOS MASS API.
+//
+// Input:
+// fpURPPointer Pointer to the URP structure, it contains the following:
+// IN UINTN CmdLength
+// IN UINTN fpCmdBuffer
+// OUT UINT8 bStatus
+// OUT UINT8 bError
+// IN OUT UINTN ResponseLength - Points to the buffer length of fpResponseBuffer
+// OUT UINTN fpResponseBuffer
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// OUT UINT8 bStatus
+// OUT UINT8 bError
+// IN OUT UINTN ResponseLength - Points to the actual response bytes in fpResponseBuffer on return
+// OUT UINTN fpResponseBuffer
+//
+// Note: This API excutes PC_to_RDR_XfrBlock cmd and returns the response from
+// RDR_to_PC_DataBlock to the caller.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBCCIDAPIXfrBlockSMM (
+ IN OUT URP_STRUC *Urp
+)
+{
+
+ EFI_STATUS Status;
+ DEV_INFO *DevInfo;
+ ICC_DEVICE *IccDevice;
+ UINT32 CmdLength = (UINT32)Urp->ApiData.CCIDXfrBlock.CmdLength;
+ UINT8 *CmdBuffer = (UINT8 *)Urp->ApiData.CCIDXfrBlock.fpCmdBuffer;
+ UINT8 IsBlock = (BOOLEAN)Urp->ApiData.CCIDXfrBlock.ISBlock;
+ UINT32 *ResponseLength = (UINT32 *)&(Urp->ApiData.CCIDXfrBlock.ResponseLength);
+ UINT8 *ResponseBuffer = (UINT8 *)(Urp->ApiData.CCIDXfrBlock.fpResponseBuffer);
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (gCheckUsbApiParameter) {
+ Status = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDXfrBlock.fpCmdBuffer),
+ Urp->ApiData.CCIDXfrBlock.CmdLength);
+ if (EFI_ERROR(Status)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ Status = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDXfrBlock.fpResponseBuffer),
+ Urp->ApiData.CCIDXfrBlock.ResponseLength);
+ if (EFI_ERROR(Status)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ gCheckUsbApiParameter = FALSE;
+ }
+#endif
+
+ DevInfo = (DEV_INFO *)(Urp->ApiData.CCIDXfrBlock.fpDevInfo);
+
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!DevInfo || !DevInfo->pCCIDDescriptor) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ Status = UsbDevInfoValidation(DevInfo);
+
+ if (EFI_ERROR(Status)) {
+ Urp->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Locate the ICCDevice
+ //
+ IccDevice = GetICCDevice(DevInfo, Urp->ApiData.CCIDXfrBlock.Slot);
+
+ if (!IccDevice || !(IccDevice->ConfiguredStatus & ICCPRESENT)) {
+
+ Urp->ApiData.CCIDXfrBlock.bStatus = 0x42;
+ Urp->ApiData.CCIDXfrBlock.bError = 0xFE;
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+
+ //
+ // Only T0/T1 are recognized
+ //
+ if (IccDevice->bProtocolNum > 1) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Check for T0/T1
+ //
+ if (IccDevice->bProtocolNum){
+ switch (((SMARTCLASS_DESC*)DevInfo->pCCIDDescriptor)->dwFeatures & 0x70000) {
+
+ case TDPU_LEVEL_EXCHANGE:
+
+ Status = TxRxT1TDPUChar(DevInfo, IccDevice, CmdLength, CmdBuffer, IsBlock, ResponseLength, ResponseBuffer);
+ break;
+
+ case CHARACTER_LEVEL_EXCHANGE:
+
+ Status = TxRxT1TDPUChar(DevInfo, IccDevice, CmdLength, CmdBuffer, IsBlock, ResponseLength, ResponseBuffer);
+ break;
+
+ case SHORT_ADPU_LEVEL_EXCHANGE:
+ case EXT_ADPU_LEVEL_EXCHANGE:
+ Status = TxRxT1Adpu(DevInfo, IccDevice, CmdLength, CmdBuffer, ResponseLength, ResponseBuffer);
+ break;
+ }
+ } else {
+ // T0 not supported yet
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ Urp->ApiData.CCIDXfrBlock.bStatus = IccDevice->bStatus;
+ Urp->ApiData.CCIDXfrBlock.bError = IccDevice->bError;
+
+ Urp->bRetValue = USB_SUCCESS;
+
+ if (Status == EFI_DEVICE_ERROR) {
+ Urp->bRetValue = USB_ERROR;
+ }
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDAPIGetParametersSMM
+//
+// Description: This function is part of the USB BIOS MASS API.
+//
+// Input:
+// fpURPPointer Pointer to the URP structure, it contains the following:
+// OUT UINT8 bStatus;
+// OUT UINT8 bError;
+// IN OUT UINTN ResponseLength;
+// OUT UINTN fpResponseBuffer;
+// IN UINT8 Slot;
+// OUT UINTN fpDevInfo;
+//
+// Output:
+// fpURPPointer Pointer to the URP structure
+// bRetValue Return value
+//
+// Notes: This API returns the response to RDR_to_PCParameters cmd
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBCCIDAPIGetParametersSMM (
+ IN OUT URP_STRUC *Urp
+
+)
+{
+
+ EFI_STATUS Status;
+ DEV_INFO *DevInfo;
+ ICC_DEVICE *IccDevice;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (gCheckUsbApiParameter) {
+ Status = AmiValidateMemoryBuffer((VOID*)(Urp->ApiData.CCIDGetParameters.fpResponseBuffer),
+ Urp->ApiData.CCIDGetParameters.ResponseLength);
+ if (EFI_ERROR(Status)) {
+ USB_DEBUG(3, "UsbCcid Invalid Pointer, Buffer is in SMRAM.\n");
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+ gCheckUsbApiParameter = FALSE;
+ }
+#endif
+
+ DevInfo = (DEV_INFO *)(Urp->ApiData.CCIDGetParameters.fpDevInfo);
+
+ //
+ // Check whether it is a valid CCID Device
+ //
+ if (!DevInfo || !DevInfo->pCCIDDescriptor) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ Status = UsbDevInfoValidation(DevInfo);
+
+ if (EFI_ERROR(Status)) {
+ Urp->bRetValue = USB_PARAMETER_ERROR;
+ return;
+ }
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Locate the ICCDevice
+ //
+ IccDevice = GetICCDevice(DevInfo, Urp->ApiData.CCIDGetParameters.Slot);
+ if (!IccDevice || !(IccDevice->ConfiguredStatus & ICCPRESENT)) {
+ Urp->ApiData.CCIDGetParameters.bStatus = 0x42;
+ Urp->ApiData.CCIDGetParameters.bError = 0xFE;
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ // Should we check for device presence in data area. The call will find that out anyways.
+
+ //
+ // Issue the cmd
+ //
+ Status = PCToRDRGetParameters(DevInfo, IccDevice);
+
+ if (EFI_ERROR(Status)){
+ Urp->bRetValue = USB_ERROR;
+ return;
+ }
+
+ //
+ // Get the response
+ //
+ Status = RDRToPCParameters(DevInfo, IccDevice);
+ if (!EFI_ERROR(Status)) {
+ Urp->ApiData.CCIDGetParameters.ResponseLength = 6;
+ if (IccDevice->bProtocolNum){
+ Urp->ApiData.CCIDGetParameters.ResponseLength = 8;
+ }
+ //
+ // Update the Data
+ //
+ MemCopy((UINT8 *)&(IccDevice->bProtocolNum),
+ (UINT8 *)(Urp->ApiData.CCIDGetParameters.fpResponseBuffer),
+ (UINT32)(Urp->ApiData.CCIDGetParameters.ResponseLength)
+ );
+ }
+
+ Urp->ApiData.CCIDGetParameters.bStatus = IccDevice->bStatus;
+ Urp->ApiData.CCIDGetParameters.bError = IccDevice->bError;
+
+ Urp->bRetValue = USB_SUCCESS;
+
+ if (Status == EFI_DEVICE_ERROR) {
+ Urp->bRetValue = USB_ERROR;
+ }
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBAPI_CCIDRequest
+//
+// Description: This routine services the USB API function number 30h. It
+// handles all the CCID related calls from the higher
+// layer. Different sub-functions are invoked depending on
+// the sub-function number
+//
+// Input:
+// fpURPPointer Pointer to the URP structure
+// fpURPPointer.bSubFunc Subfunction number
+//
+// Output:
+// URP structure is updated with the relevant information
+//
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBAPI_CCIDRequest (
+ URP_STRUC *fpURP
+)
+{
+ UINT8 bCCIDFuncIndex = fpURP->bSubFunc;
+ UINT8 bNumberOfCCIDFunctions = sizeof aUsbCCIDApiTable / sizeof (API_FUNC *);
+
+ //
+ // Make sure function number is valid
+ //
+ if (bCCIDFuncIndex >= bNumberOfCCIDFunctions) {
+ //fpURP->bRetValue = USBAPI_INVALID_FUNCTION;
+ USB_DEBUG(3, "UsbApi CCIDRequest Invalid function#%x\n", bCCIDFuncIndex);
+ return;
+ }
+ //
+ // Function number is valid - call it
+ //
+ aUsbCCIDApiTable[bCCIDFuncIndex](fpURP);
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCtoRDRIccPowerOn
+//
+// Description: PC_TO_RDR_XFRBLOCK cmd is issued to the device
+//
+// Input
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT32 CmdLength,
+// IN UINT8 *CmdBuffer,
+// IN UINT8 BlockWaitingTime,
+// IN UINT16 LevelParameter
+//
+// Output :
+// EFI_STATUS
+//
+// Notes: This function sends PC_TO_RDR_XFRBLOCK to the device.
+// See section 6.1.4 of CCID spec 1.1 for the details.
+// CmdBuffer points to abData.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCToRDRXfrBlock (
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT32 CmdLength,
+ IN UINT8 *CmdBuffer,
+ IN UINT8 BlockWaitingTime,
+ IN UINT16 LevelParameter
+
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_XFRBLOCK_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+ UINT32 i;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCToRDRXfrBlock ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_XFRBLOCK_STRUC) + CmdLength));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_XFRBLOCK_STRUC) + CmdLength, 0);
+
+ //
+ // Prepare the cmd buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_XFRBLOCK;
+ fpCmdBuffer->dwLength = CmdLength;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+ fpCmdBuffer->bBWI = BlockWaitingTime;
+ fpCmdBuffer->wLevelParameter = LevelParameter;
+
+ //
+ // Copy the cmd
+ //
+ if (CmdLength) {
+ MemCopy(CmdBuffer, (UINT8 *)fpCmdBuffer + sizeof(PC_TO_RDR_XFRBLOCK_STRUC), CmdLength);
+ }
+
+
+ USB_DEBUG (DEBUG_LEVEL_3, "\n");
+ for (i=0; i< sizeof(PC_TO_RDR_XFRBLOCK_STRUC) + CmdLength; i++) {
+ USB_DEBUG (DEBUG_LEVEL_3, "%02X ", ((UINT8 *)fpCmdBuffer)[i]);
+ }
+ USB_DEBUG (DEBUG_LEVEL_3, "\n");
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_XFRBLOCK_STRUC) + CmdLength
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_XFRBLOCK_STRUC) + CmdLength));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCtoRDRIccPowerOn
+//
+// Description: PC_TO_RDR_ICCPOWERON cmd is issued to the CCID
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT8 PowerLevel - 00:Automatic Voltage selection, 01:5.0v, 02:3.0v, 03:1.8v
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: See section 6.1.1 of CCID spec Rev 1.1 for more details
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCtoRDRIccPowerOn(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT8 PowerLevel
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_ICCPOWERON_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCtoRDRIccPowerOn ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_ICCPOWERON_STRUC)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_ICCPOWERON_STRUC), 0);
+
+ //
+ // Prepare the cmd buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_ICCPOWERON;
+ fpCmdBuffer->dwLength = 0;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+ fpCmdBuffer->bPowerSlot = PowerLevel;
+ fpCmdBuffer->abRFU = 0;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_ICCPOWERON_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_ICCPOWERON_STRUC)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCtoRDRIccPowerOff
+//
+// Description: PC_TO_RDR_ICCPOWEROFF cmd is issued to the CCID
+//
+// Input :
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output :
+// EFI_STATUS
+//
+// Notes: See section 6.1.2 of CCID spec Rev 1.1 for more details
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCtoRDRIccPowerOff(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_ICCPOWEROFF_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCtoRDRIccPowerOff ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_ICCPOWEROFF_STRUC)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_ICCPOWEROFF_STRUC), 0);
+
+ //
+ // Prepare the buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_ICCPOWEROFF;
+ fpCmdBuffer->dwLength = 0;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_ICCPOWEROFF_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ else {
+ fpICCDevice->ConfiguredStatus = 0;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_ICCPOWEROFF_STRUC)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCToRDRGetSlotStatus
+//
+// Description: PC_TO_RDR_GETSLOTSTATUS cmd is issued to CCID
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+//Notes: See section 6.1.3 of CCID spec Rev 1.1 for more details
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCToRDRGetSlotStatus(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_GETSLOT_STATUS_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCToRDRGetSlotStatus ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_GETSLOT_STATUS_STRUC)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_GETPARAMETERS_STRUC), 0);
+
+ //
+ // Prepare cmd buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_GETSLOTSTATUS;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_GETSLOT_STATUS_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_GETSLOT_STATUS_STRUC)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCToRDRGetParameters
+//
+// Description: PC_TO_RDR_GETPARAMETERS cmd is issued to CCID
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: See section 6.1.5 of CCID spec Rev 1.1 for more details
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCToRDRGetParameters(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_GETPARAMETERS_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCToRDRGetParameters ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_GETPARAMETERS_STRUC)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_GETPARAMETERS_STRUC), 0);
+
+ //
+ // Prepare cmd buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_GETPARAMETERS;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_GETPARAMETERS_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_GETPARAMETERS_STRUC)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCToRDRSetParameters
+//
+// Description: PC_TO_RDR_SETPARAMETERS cmd is issued to CCID
+//
+// Input :
+// IN DEV_INFO *fpDevInfo
+// IN ICC_DEVICE *fpICCDevice
+// IN UINT8 ProtocolNum - 0 : T=0, 1 : T=1
+// IN VOID *Data - Points to data from abProtocolDataStructure
+// in PC_TO_RDR_SETPARAMETERS
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: See section 6.1.7 of CCID spec Rev 1.1 for more details
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCToRDRSetParameters(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT8 ProtocolNum,
+ IN VOID *Data
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_SETPARAMETERS_T0_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+ UINT8 Length = ProtocolNum == 0 ? sizeof(PROTOCOL_DATA_T0) : sizeof(PROTOCOL_DATA_T1);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCToRDRSetParameters ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(Length + sizeof(RDR_HEADER)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, Length + sizeof(RDR_HEADER), 0);
+
+ //
+ // Prepare
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_SETPARAMETERS;
+ fpCmdBuffer->dwLength = Length;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+ fpCmdBuffer->bProtocolNum = ProtocolNum;
+
+ MemCopy ((UINT8 *)Data, (UINT8 *)fpCmdBuffer +sizeof(RDR_HEADER), Length);
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ Length + sizeof(RDR_HEADER)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(Length + sizeof(RDR_HEADER)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: PCToRDRSetDataRateAndClockFrequency
+//
+// Description: PC_TO_RDR_SETDATARATEANDCLOCK cmd is issued.
+// Response for this cmd is from RDR_TO_PC_DATARATEANDCLOCK
+//
+// Input:
+// IN DEV_INFO *fpDevInfo
+// IN ICC_DEVICE *fpICCDevice
+// IN UINT32 ClockFrequency - ICC Clock Frequency in KHz
+// IN UINT32 DataRate - ICC data rate in bpd
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: See section 6.1.14 of CCID spec Rev 1.1 for more details
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+PCToRDRSetDataRateAndClockFrequency(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT32 ClockFrequency,
+ IN UINT32 DataRate
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC *fpCmdBuffer;
+ UINT32 dwData;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "PCToRDRGetParameters ....");
+
+ fpCmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC)));
+ ASSERT(fpCmdBuffer);
+ if (!fpCmdBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpCmdBuffer, sizeof(PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC), 0);
+
+ //
+ // Prepare cmd buffer
+ //
+ fpCmdBuffer->bMessageType = PC_TO_RDR_SETDATARATEANDCLOCK;
+ fpCmdBuffer->dwLength = 8;
+ fpCmdBuffer->bSlot = fpICCDevice->Slot;
+ fpCmdBuffer->bSeq = gSequence;
+ fpCmdBuffer->dwCloclFrequency = ClockFrequency;
+ fpCmdBuffer->dwDataRate = DataRate;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, 0,
+ (UINT8 *)fpCmdBuffer,
+ sizeof(PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ USB_MemFree(fpCmdBuffer, (UINT8)GET_MEM_BLK_COUNT(sizeof(PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC)));
+
+ USB_DEBUG (DEBUG_LEVEL_3, "%r ....", Status);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: RDRToPCDataBlock
+//
+// Description: RDR_TO_PC_DATABLOCK cmd is issued to the CCID.
+// This is on response to PCI_to_RDR_XfrBlock
+//
+// Input:
+// IN DEV_INFO *fpDevInfo
+// IN ICC_DEVICE *fpICCDevice
+// IN OUT UINT32 *dwLength - # of bytes in Buffer
+// OUT UINT8 *Buffer - Points to abData in RDR_TO_PC_DATABLOCK
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: See section 6.2.1 of CCID spec Rev 1.1 for more details
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+RDRToPCDataBlock(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN OUT UINT32 *dwLength,
+ OUT UINT8 *Buffer
+
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ RDR_TO_PC_DATABLOCK_STRUC* fpReceiveBuffer;
+ UINT32 dwData;
+ UINT8 Iterations = 3;
+ UINT32 InputLength = *dwLength;
+ UINT32 i;
+
+ //
+ // Allocate memory for receiving data
+ //
+ fpReceiveBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_DATABLOCK_STRUC) + *dwLength));
+ ASSERT(fpReceiveBuffer);
+ if (!fpReceiveBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpReceiveBuffer, sizeof(RDR_TO_PC_DATABLOCK_STRUC) + *dwLength, 0);
+
+ do {
+ //
+ // Get the response
+ //
+ fpReceiveBuffer->bMessageType = RDR_TO_PC_DATABLOCK;
+ fpReceiveBuffer->dwLength = *dwLength;
+ fpReceiveBuffer->bSlot = fpICCDevice->Slot;
+ fpReceiveBuffer->bSeq = gSequence;
+ fpReceiveBuffer->bStatus = 0;
+ fpReceiveBuffer->bError = 0;
+ fpReceiveBuffer->bChainParameter = 0;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, BIT7,
+ (UINT8 *)fpReceiveBuffer,
+ sizeof(RDR_TO_PC_DATABLOCK_STRUC) + *dwLength
+ );
+
+ USB_DEBUG (DEBUG_LEVEL_3, "\n");
+
+ for (i=0; i< sizeof(RDR_TO_PC_DATABLOCK_STRUC) + fpReceiveBuffer->dwLength; i++) {
+ USB_DEBUG (DEBUG_LEVEL_3, "%02X ", ((UINT8 *)fpReceiveBuffer)[i]);
+ }
+
+ USB_DEBUG (DEBUG_LEVEL_3, "\n");
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit_RDRToPCDataBlock;
+ }
+
+ //
+ // Check for time extension
+ //
+ if ((fpReceiveBuffer->bStatus & 0xC0) == 0x80) {
+ FixedDelay(fpReceiveBuffer->bError * fpICCDevice->WaitTime * 1000);
+ } else {
+ break;
+ }
+
+ Iterations--;
+ } while (Iterations);
+
+ // Should the cmd be aborted if the response isn't received???
+
+ //
+ // Processed without error if Zero
+ //
+ if (fpReceiveBuffer->bStatus & 0xC0) {
+ Status = EFI_DEVICE_ERROR;
+
+ if ((fpReceiveBuffer->bStatus & 0x3) == 0x2) {
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ if (Iterations && !EFI_ERROR(Status)) {
+
+ fpICCDevice->bChainParameter = fpReceiveBuffer->bChainParameter;
+
+ //
+ // If response is successful get the data
+ //
+ if (fpReceiveBuffer->dwLength && fpReceiveBuffer->dwLength <= *dwLength) {
+
+ // Copy data
+ MemCopy ((UINT8 *)fpReceiveBuffer + sizeof(RDR_TO_PC_DATABLOCK_STRUC),
+ Buffer,
+ fpReceiveBuffer->dwLength
+ );
+
+ }
+
+ if (fpReceiveBuffer->dwLength > *dwLength) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Update the o/p buffer length
+ //
+ *dwLength = fpReceiveBuffer->dwLength;
+
+ } else {
+
+ Status = EFI_DEVICE_ERROR;
+ *dwLength = 0;
+ }
+
+ //
+ // Save the last cmd status
+ //
+ fpICCDevice->bStatus = fpReceiveBuffer->bStatus;
+ fpICCDevice->bError = fpReceiveBuffer->bError;
+
+
+ //
+ // if success exit
+ //
+ if (!EFI_ERROR(Status) && !fpICCDevice->bStatus) {
+ Status = EFI_SUCCESS;
+ goto exit_RDRToPCDataBlock;
+ }
+
+ // Card not present?
+ Status = EFI_NOT_FOUND;
+ if ((fpReceiveBuffer->bStatus & 7) == 2) goto exit_RDRToPCDataBlock;
+
+ //
+ // Other errors
+ //
+ Status = EFI_DEVICE_ERROR;
+
+exit_RDRToPCDataBlock:
+
+ gSequence++;
+
+ USB_MemFree(fpReceiveBuffer,
+ (UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_DATABLOCK_STRUC) + InputLength)
+ );
+
+ USB_DEBUG (DEBUG_LEVEL_3, " Status : %r bStatus : %02X bError : %02X\n", Status, fpICCDevice->bStatus, fpICCDevice->bError);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: RDRToPCSlotStatus
+//
+// Description: RDR_TO_PC_SLOTSTATUS cmd is issued to CCID.
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: bStatus, BError and bClockStatus is updated.
+// See section 6.2.2 of CCID spec Rev 1.1 for more details.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+RDRToPCSlotStatus(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ RDR_TO_PC_SLOTSTATUS_STRUC *fpReceiveBuffer;
+ UINT32 dwData;
+ UINT8 Iterations = 3;
+
+ fpReceiveBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_SLOTSTATUS_STRUC)));
+ ASSERT(fpReceiveBuffer);
+ if (!fpReceiveBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpReceiveBuffer, sizeof(RDR_TO_PC_SLOTSTATUS_STRUC), 0);
+ do {
+ //
+ // Read the PCSlot Status
+ //
+ fpReceiveBuffer->bMessageType = RDR_TO_PC_SLOTSTATUS;
+ fpReceiveBuffer->dwLength = 0;
+ fpReceiveBuffer->bSlot = fpICCDevice->Slot;
+ fpReceiveBuffer->bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, BIT7,
+ (UINT8 *)fpReceiveBuffer,
+ sizeof(RDR_TO_PC_SLOTSTATUS_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit_RDRToPCSlotStatus;
+ }
+
+ //
+ // Check for time extension
+ //
+ if ((fpReceiveBuffer->bStatus & 0xC0) == 0x80) {
+ FixedDelay(fpReceiveBuffer->bError * fpICCDevice->WaitTime * 1000);
+ } else {
+ break;
+ }
+
+ Iterations--;
+ } while (Iterations);
+
+
+ //
+ // Save the last cmd status
+ //
+ fpICCDevice->bStatus = fpReceiveBuffer->bStatus;
+ fpICCDevice->bError = fpReceiveBuffer->bError;
+
+ // Processed without error if Zero
+ if (fpReceiveBuffer->bStatus & 0xC0) {
+ Status = EFI_DEVICE_ERROR;
+
+ if ((fpReceiveBuffer->bStatus & 0x3) == 0x2) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ }
+
+ if (Iterations && !EFI_ERROR(Status)) {
+ //
+ // Update the last ClockStatus
+ //
+ fpICCDevice->bClockStatus = fpReceiveBuffer->bClockStatus;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+exit_RDRToPCSlotStatus:
+
+ gSequence++;
+
+ USB_MemFree(fpReceiveBuffer,
+ (UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_SLOTSTATUS_STRUC))
+ );
+
+ USB_DEBUG (DEBUG_LEVEL_3, " Status : %r bStatus : %02X bError : %02X\n", Status, fpICCDevice->bStatus, fpICCDevice->bError);
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: RDRToPCParameters
+//
+// Description: RDR_TO_PC_SLOTSTATUS cmd is issued
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+// abProtocolDataStructure is copied
+//
+//
+// Notes: bStatus, BErroris updated. See section 6.2.3 of CCID spec
+// Rev 1.1 for more details.
+// bProtocolNum and abProtocolDatStructure is captured.
+//
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+RDRToPCParameters(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ RDR_TO_PC_PARAMETERS_T1_STRUC *fpReceiveBuffer;
+ UINT32 dwData;
+ UINT8 Iterations = 3;
+
+ fpReceiveBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_PARAMETERS_T1_STRUC)));
+ ASSERT(fpReceiveBuffer);
+ if (!fpReceiveBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpReceiveBuffer, sizeof(RDR_TO_PC_PARAMETERS_T1_STRUC), 0);
+
+ do {
+
+ //
+ // Read the PCSlot Status
+ //
+ fpReceiveBuffer->Header.bMessageType = RDR_TO_PC_PARAMETERS;
+ fpReceiveBuffer->Header.dwLength = 0;
+ fpReceiveBuffer->Header.bSlot = fpICCDevice->Slot;
+ fpReceiveBuffer->Header.bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, BIT7,
+ (UINT8 *)fpReceiveBuffer,
+ sizeof(RDR_TO_PC_PARAMETERS_T1_STRUC)
+ );
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit_RDRToPCParameters;
+ }
+
+ //
+ // Check for time extension
+ //
+ if ((fpReceiveBuffer->Header.bStatus & 0xC0) == 0x80) {
+ FixedDelay(fpReceiveBuffer->Header.bError * fpICCDevice->WaitTime * fpICCDevice->etu);
+ } else {
+ break;
+ }
+
+ Iterations--;
+
+ } while (Iterations);
+
+ //
+ // Save the last cmd status
+ //
+ fpICCDevice->bStatus = fpReceiveBuffer->Header.bStatus;
+ fpICCDevice->bError = fpReceiveBuffer->Header.bError;
+
+ //
+ // Processed without error if Zero
+ //
+ if (fpReceiveBuffer->Header.bStatus & 0xC0) {
+ Status = EFI_DEVICE_ERROR;
+
+ if ((fpReceiveBuffer->Header.bStatus & 0x3) == 0x2) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ }
+
+ if (Iterations && !EFI_ERROR(Status)) {
+
+ //
+ // Update the Data
+ //
+ MemCopy((UINT8 *)&(fpReceiveBuffer->Header.Data),
+ (UINT8 *)&(fpICCDevice->bProtocolNum),
+ sizeof(RDR_TO_PC_PARAMETERS_T1_STRUC) - 9);
+
+ } else {
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+exit_RDRToPCParameters:
+
+ gSequence++;
+
+ USB_MemFree(fpReceiveBuffer,
+ (UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_PARAMETERS_T1_STRUC))
+ );
+
+ USB_DEBUG (DEBUG_LEVEL_3, " Status : %r bStatus : %02X bError : %02X\n", Status, fpICCDevice->bStatus, fpICCDevice->bError);
+
+ PrintPCParameters((UINT8 *)&(fpICCDevice->bProtocolNum));
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: RDRToPCDataRateAndClockFrequency
+//
+// Description: RDR_TO_PC_DATARATEANDCLOCK cmd is issued.
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: Returns dwClockFrequency and dwDataRate.
+// See section 6.2.5 of CCID spec Rev 1.1 for more details.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+RDRToPCDataRateAndClockFrequency(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC *fpReceiveBuffer;
+ UINT32 dwData;
+ UINT8 Iterations = 3;
+
+ fpReceiveBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC)));
+ ASSERT(fpReceiveBuffer);
+ if (!fpReceiveBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpReceiveBuffer, sizeof(RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC), 0);
+
+ do {
+
+ //
+ // Read the PCSlot Status
+ //
+ fpReceiveBuffer->bMessageType = RDR_TO_PC_DATARATEANDCLOCK;
+ fpReceiveBuffer->dwLength = 8;
+ fpReceiveBuffer->bSlot = fpICCDevice->Slot;
+ fpReceiveBuffer->bSeq = gSequence;
+
+ dwData = USBCCIDIssueBulkTransfer(fpDevInfo, BIT7,
+ (UINT8 *)fpReceiveBuffer,
+ sizeof(RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC));
+
+ //
+ // Handle Error if any. This error is due to blk transfer
+ //
+ if (!dwData) {
+ Status = EFI_DEVICE_ERROR;
+ goto exit_RDRToPCDataRateAndClockFrequency;
+ }
+
+ //
+ // Check for time extension
+ //
+ if ((fpReceiveBuffer->bStatus & 0xC0) == 0x80) {
+ FixedDelay(fpReceiveBuffer->bError * fpICCDevice->WaitTime * 1000);
+ } else {
+ break;
+ }
+
+ Iterations--;
+
+ } while (Iterations);
+
+
+ //
+ // Processed without error if Zero
+ //
+ if (fpReceiveBuffer->bStatus & 0xC0) {
+ Status = EFI_DEVICE_ERROR;
+
+ if ((fpReceiveBuffer->bStatus & 0x3) == 0x2) {
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ if (Iterations && !EFI_ERROR(Status)) {
+
+ fpICCDevice->dwClockFrequency = fpReceiveBuffer->dwClockFrequency;
+ fpICCDevice->dwDataRate = fpReceiveBuffer->dwDataRate;
+
+ } else {
+
+ Status = EFI_DEVICE_ERROR;
+
+ }
+
+ //
+ // Save the last cmd status
+ //
+ fpICCDevice->bStatus = fpReceiveBuffer->bStatus;
+ fpICCDevice->bError = fpReceiveBuffer->bError;
+
+exit_RDRToPCDataRateAndClockFrequency:
+
+ gSequence++;
+
+ USB_MemFree(fpReceiveBuffer,
+ (UINT8)GET_MEM_BLK_COUNT(sizeof(RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC))
+ );
+
+ USB_DEBUG (DEBUG_LEVEL_3, " Status : %r bStatus : %02X bError : %02X\n",
+ Status, fpICCDevice->bStatus, fpICCDevice->bError);
+
+ USB_DEBUG (DEBUG_LEVEL_3, " dwClockFrequency : %4x dwDataRate : %4x\n",
+ fpICCDevice->dwClockFrequency, fpICCDevice->dwDataRate);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: TxRxT1Adpu
+//
+// Description: Transmit/Receive T1 ADPU
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT32 CmdLength,
+// IN UINT8 *CmdBuffer,
+// IN UINT8 BlockWaitingTime,
+// IN UINT16 LevelParameter
+//
+// Output:
+//
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+TxRxT1Adpu (
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT32 CmdLength,
+ IN UINT8 *CmdBuffer,
+ OUT UINT32 *ResponseLength,
+ OUT UINT8 *ResponseBuffer
+)
+{
+
+ EFI_STATUS Status;
+
+ //
+ // Issue the cmd
+ //
+ Status = PCToRDRXfrBlock(fpDevInfo, fpICCDevice, CmdLength, CmdBuffer, 0, 0);
+
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ //
+ // Get the response
+ //
+ Status = RDRToPCDataBlock(fpDevInfo, fpICCDevice, ResponseLength, ResponseBuffer);
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: TxRxT1TDPUChar
+//
+// Description: Transmit/Receive T1 TDPU/Character
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT32 CmdLength,
+// IN UINT8 *CmdBuffer,
+// IN UINT8 ISBlock,
+// OUT UINT32 *ResponseLength,
+// OUT UINT8 *ResponseBuffer
+//
+// Output:
+//
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+TxRxT1TDPUChar (
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT32 CmdLength,
+ IN UINT8 *CmdBuffer,
+ IN UINT8 ISBlock,
+ IN OUT UINT32 *ResponseLength,
+ OUT UINT8 *ResponseBuffer
+)
+{
+
+ EFI_STATUS Status;
+ UINT8 Pcb = ISBlock;
+ UINT32 InfLength = CmdLength;
+ UINT8 *InfBuffer = CmdBuffer;
+
+ UINT32 IBlockFrameLength = 0; // Used for I-Block
+ UINT8 *IBlockFrame = NULL;
+
+ UINT32 SendBlockFrameLength = 0; // Place holder for the block currently sent
+ UINT8 *SendBlockFrame = NULL;
+
+ UINT32 RBlockFrameLength = 0; // Used for R-Block
+ UINT8 *RBlockFrame = NULL;
+
+ UINT32 SBlockFrameLength = 0; // Used for S-Block
+ UINT8 *SBlockFrame = NULL;
+
+ UINT32 lResponseLength = 0; // Response buffer for all the blocks I/S/R
+ UINT32 OrglResponseLength = 0;
+ UINT8 *lResponseBuffer;
+
+ UINT8 wLevelParameter = 0;
+
+ UINT8 ReceiveStatus;
+ UINT8 bBWIByte = 0;
+
+ UINT32 UserBufferLength = *ResponseLength;
+ UINT32 lResponseBufferAddDataPtr = 0;
+
+ BOOLEAN T1Char = ((SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor)->dwFeatures & TDPU_LEVEL_EXCHANGE ? FALSE : TRUE;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return EFI_DEVICE_ERROR;
+ }
+ // Initialize Chaining is off
+ fpICCDevice->Chaining = FALSE;
+ *ResponseLength = 0;
+
+ // Update Pcb with Nas only for IBlocks
+ if (!ISBlock) {
+ Pcb = ((fpICCDevice->NaSInterface & 1) << 6);
+ }
+
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, Pcb,
+ CmdLength, CmdBuffer,
+ &wLevelParameter, &IBlockFrameLength,
+ &IBlockFrame
+ );
+
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ SendBlockFrameLength = IBlockFrameLength;
+ SendBlockFrame = IBlockFrame;
+
+ if (UserBufferLength < 2) lResponseLength = 2;
+
+ lResponseLength += (UserBufferLength + 3 + (fpICCDevice->EpilogueFields == 0 ? 1 : 2));
+
+ lResponseBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(lResponseLength));
+ ASSERT(lResponseBuffer);
+ if (!lResponseBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill(lResponseBuffer, lResponseLength, 0);
+
+ OrglResponseLength = lResponseLength;
+
+ fpICCDevice->T1CharCmdDataPhase = TRUE; // Always Cmd Phase first
+
+ do {
+
+ Status = PCToRDRXfrBlock(fpDevInfo, fpICCDevice,
+ SendBlockFrameLength, SendBlockFrame,
+ bBWIByte, wLevelParameter
+ );
+
+ if (EFI_ERROR(Status)){
+ break;
+ }
+
+ //
+ // Get the response
+ //
+ lResponseLength = OrglResponseLength - lResponseBufferAddDataPtr;
+ Status = RDRToPCDataBlock(fpDevInfo, fpICCDevice, &lResponseLength, lResponseBuffer + lResponseBufferAddDataPtr);
+
+ if (EFI_ERROR(Status)){
+ break;
+ }
+
+ // Check for errors
+ ReceiveStatus = HandleReceivedBlock(fpDevInfo, fpICCDevice,
+ IBlockFrameLength, IBlockFrame,
+ SendBlockFrameLength, SendBlockFrame,
+ lResponseBuffer
+ );
+
+ bBWIByte = 0;
+
+ switch (ReceiveStatus) {
+
+ case BLOCK_TRANSMISION_SUCCESS:
+ break;
+
+ case RESEND_BLOCK:
+ break;
+
+ case SEND_R_BLOCK_1:
+ case SEND_R_BLOCK_0:
+
+ // Check if Chaining is in progress
+ if (fpICCDevice->Chaining) {
+
+ // Copy the data from lResponseBuffer to the user buffer
+ //
+ // If success copy the data to Response buffer
+ //
+ if (lResponseBuffer[2] && ((UserBufferLength - *ResponseLength) < lResponseBuffer[2])) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ MemCopy(lResponseBuffer+3, ResponseBuffer + *ResponseLength, lResponseBuffer[2]);
+ *ResponseLength += lResponseBuffer[2];
+ lResponseBufferAddDataPtr = 0; // Reset to use the lResponseBuffer from the beginning
+
+ // Clear out the PCB/length feild so that by mistake the buffer is interpreted as valid data
+ lResponseBuffer[1] = 0;
+ lResponseBuffer[2] = 0;
+ lResponseLength = OrglResponseLength;
+
+ }
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, ReceiveStatus == SEND_R_BLOCK_1 ? 0x80 | 0x10 : 0x80,
+ 0, NULL, &wLevelParameter,
+ &RBlockFrameLength, &RBlockFrame
+ );
+
+ if (EFI_ERROR(Status)) {
+ ReceiveStatus = BLOCK_TRANSMISSION_TERMINATE;
+ }
+ SendBlockFrameLength = RBlockFrameLength;
+ SendBlockFrame = RBlockFrame;
+ fpICCDevice->T1CharCmdDataPhase = TRUE;
+ break;
+
+ case I_BLOCK_RESEND:
+
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, Pcb, CmdLength,
+ CmdBuffer, &wLevelParameter,
+ &IBlockFrameLength, &IBlockFrame
+ );
+
+ if (EFI_ERROR(Status)) {
+ ReceiveStatus = BLOCK_TRANSMISSION_TERMINATE;
+ }
+ SendBlockFrameLength = IBlockFrameLength;
+ SendBlockFrame = IBlockFrame;
+ fpICCDevice->T1CharCmdDataPhase = TRUE;
+ break;
+
+ case WTX_RESPONSE:
+
+ bBWIByte = lResponseBuffer[3];
+
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, WTX_RESPONSE,
+ lResponseBuffer[2], lResponseBuffer + 3,
+ &wLevelParameter, &SBlockFrameLength,
+ &SBlockFrame
+ );
+
+ if (EFI_ERROR(Status)) {
+ ReceiveStatus = BLOCK_TRANSMISSION_TERMINATE;
+ }
+
+ SendBlockFrameLength = SBlockFrameLength;
+ SendBlockFrame = SBlockFrame;
+ fpICCDevice->T1CharCmdDataPhase = TRUE;
+ break;
+
+ case GET_DATA_T1_CHAR:
+
+ //
+ // Issue a PCToRDRXfrBlock with dwLength to zero.
+ // Check Page 68 of CCID spec Rev 1.1, Apr 22, 2005
+ //
+
+ SendBlockFrameLength = 0;
+ // Assumption : only LRC is supported
+ wLevelParameter = lResponseBuffer[2] + 1;
+
+ //
+ // Since the prologue is received in the first three bytes increment
+ // the address so that data is recived after that
+ //
+ lResponseBufferAddDataPtr += 3;
+
+ //
+ // Indicate it is data phase now
+ //
+ fpICCDevice->T1CharCmdDataPhase = FALSE;
+ break;
+
+ case IFS_RESPONSE:
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, IFS_RESPONSE,
+ lResponseBuffer[2], lResponseBuffer + 3,
+ &wLevelParameter, &SBlockFrameLength,
+ &SBlockFrame
+ );
+
+ if (EFI_ERROR(Status)) {
+ ReceiveStatus = BLOCK_TRANSMISSION_TERMINATE;
+ }
+
+ SendBlockFrameLength = SBlockFrameLength;
+ SendBlockFrame = SBlockFrame;
+ fpICCDevice->T1CharCmdDataPhase = TRUE;
+ break;
+
+ case ABORT_RESPONSE:
+ Status = ConstructBlockFrame(fpDevInfo, fpICCDevice,
+ fpICCDevice->NAD, ABORT_RESPONSE,
+ lResponseBuffer[2], lResponseBuffer + 3,
+ &wLevelParameter, &SBlockFrameLength,
+ &SBlockFrame
+ );
+
+ if (EFI_ERROR(Status)) {
+ ReceiveStatus = BLOCK_TRANSMISSION_TERMINATE;
+ }
+
+ SendBlockFrameLength = SBlockFrameLength;
+ SendBlockFrame = SBlockFrame;
+ fpICCDevice->T1CharCmdDataPhase = TRUE;
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (ReceiveStatus == BLOCK_TRANSMISION_SUCCESS) {
+ break;
+ }
+ }while (1);
+
+ //
+ // If success copy the data to Response buffer for the last I-Block that was received.
+ //
+ if (lResponseBuffer[2] && ((UserBufferLength - *ResponseLength) < lResponseBuffer[2])) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (lResponseBuffer[2] && ((UserBufferLength - *ResponseLength) >= lResponseBuffer[2])) {
+ MemCopy(lResponseBuffer+3, ResponseBuffer + *ResponseLength, lResponseBuffer[2]);
+ *ResponseLength += lResponseBuffer[2];
+ }
+
+ //
+ // Free up memory I-Block allocated here
+ //
+ if (IBlockFrame && IBlockFrameLength) {
+ USB_MemFree(IBlockFrame, (UINT8)GET_MEM_BLK_COUNT(IBlockFrameLength));
+ }
+
+ //
+ // Free up S-Block memory allocated here
+ //
+ if (SBlockFrame && SBlockFrameLength) {
+ USB_MemFree(SBlockFrame, (UINT8)GET_MEM_BLK_COUNT(SBlockFrameLength));
+ }
+
+ if (lResponseBuffer && OrglResponseLength) {
+ USB_MemFree(lResponseBuffer, (UINT8)GET_MEM_BLK_COUNT(OrglResponseLength));
+ }
+
+
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: ConstructBlockFrame
+//
+// Description: Construct the Block Frame for the CCID
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT8 Nad,
+// IN UINT8 PCB,
+// IN UINT32 InfLength,
+// IN UINT8 *InfBuffer,
+// OUT UINT8 *wLevelParameter,
+// OUT UINT32 *BlockFrameLength,
+// OUT UINT8 **BlockFrame
+//
+// Output:
+// EFI_STATUS EFI Status
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+ConstructBlockFrame(
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT8 Nad,
+ IN UINT8 PCB,
+ IN UINT32 InfLength,
+ IN UINT8 *InfBuffer,
+ OUT UINT8 *wLevelParameter,
+ OUT UINT32 *BlockFrameLength,
+ OUT UINT8 **BlockFrame
+)
+{
+
+ UINT32 BufLengthRequired = InfLength + 3 +
+ (fpICCDevice->EpilogueFields == 0 ? 1 : 2);
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check if the input buffer if already allocated is enough for the current case.
+ // If not free it up and allocate again.
+ //
+
+ if (BufLengthRequired > *BlockFrameLength) {
+ if (*BlockFrame) {
+ USB_MemFree(*BlockFrame, (UINT8)GET_MEM_BLK_COUNT(*BlockFrameLength));
+ *BlockFrame = NULL;
+
+ }
+ }
+
+ *BlockFrameLength = InfLength + 3 + (fpICCDevice->EpilogueFields == 0 ? 1 : 2);
+
+ //
+ // if BlockFrame is NULL only then allocate memory. Assumption is if Memory
+ // has been allocated before then it is sufficent enough for the length needed.
+ //
+ if (!*BlockFrame) {
+ //
+ // Allocate length needed to contruct the Block Frame
+ //
+ *BlockFrame = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(*BlockFrameLength));
+
+ if (!*BlockFrame) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ MemFill(*BlockFrame, *BlockFrameLength, 0);
+
+ (*BlockFrame)[0] = Nad;
+ (*BlockFrame)[1] = PCB;
+ (*BlockFrame)[2] = InfLength;
+
+ if (InfLength) {
+ MemCopy((UINT8 *)InfBuffer, (UINT8 *)(*BlockFrame + 3), InfLength);
+ }
+
+ //
+ // Update Checksum
+ //
+ (*BlockFrame)[*BlockFrameLength - 1] = 0;
+
+ if (fpICCDevice->EpilogueFields == 0) {
+ CalculateLRCChecksum(*BlockFrame, *BlockFrameLength);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // For Character transfer update wLevelParameter also
+ //
+ if (!(((SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor)->dwFeatures & 0x70000)) {
+ *wLevelParameter = 3;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: HandleReceivedBlock
+//
+// Description: Process the Recevied data from CCID device
+//
+// Input:
+// IN DEV_INFO *fpDevInfo,
+// IN ICC_DEVICE *fpICCDevice,
+// IN UINT32 OriginalBlockFrameLength,
+// IN UINT8 *OriginalBlockFrame,
+// IN UINT32 SentBlockFrameLength,
+// IN UINT8 *SentBlockFrame,
+// IN UINT8 *ReceivedBlockFrame
+//
+// Output:
+//
+//
+// Notes:
+// For Character exchange control will come twice for S(Response), I-Block with M bit set. So while counting
+// number of exchnages this needs to be taken care of.
+// Refer to ISO/IEC 7816-1 First edition 1998-10-15 for different scenarios mentioned in this function.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+UINT8
+HandleReceivedBlock (
+ IN DEV_INFO *fpDevInfo,
+ IN ICC_DEVICE *fpICCDevice,
+ IN UINT32 OriginalBlockFrameLength,
+ IN UINT8 *OriginalBlockFrame,
+ IN UINT32 SentBlockFrameLength,
+ IN UINT8 *SentBlockFrame,
+ IN UINT8 *ReceivedBlockFrame
+)
+{
+
+ UINT8 ReturnParameter = BLOCK_TRANSMISION_SUCCESS;
+ BOOLEAN T1Char = ((SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor)->dwFeatures & 0x70000 ? FALSE : TRUE;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return BLOCK_TRANSMISSION_TERMINATE;
+ }
+
+ // It is easy to support T1 TDPU & CHAR as they are almost same except that
+ // prologue and data are received separatly in T1 Char.
+ // The trick here will be that when data is received we can combine the
+ // previously received prologue and the INF/Epilogue received
+ // later so that it will be similar to T1 TDPU. Then all the processing will be same.
+
+ if (!ReceivedBlockFrame){ // if no response
+
+ if (fpICCDevice->RBlockCounter == 2) {
+ return BLOCK_TRANSMISSION_TERMINATE;
+ }
+
+
+
+ // If I-Block sent before and no response, send R-Block with the expected I Block(N(R). Rule 7.1/Rule 7.6
+ if (!(SentBlockFrame[1] & 0x80)) {
+
+ fpICCDevice->RBlockCounter++;
+
+ if (fpICCDevice->NaSCard) {
+ return SEND_R_BLOCK_0;
+ } else {
+ return SEND_R_BLOCK_1;
+ }
+ }
+
+ }
+
+ // Reset the RBlock Counter if the response we received isn't a R-Block.
+ if ((ReceivedBlockFrame[1] & 0xC0) != RBLOCK) {
+ fpICCDevice->RBlockCounter = 0;
+ }
+
+ //
+ // Is the block received an I-Block?
+ //
+ if (!(ReceivedBlockFrame[1] & 0x80)) {
+
+ //
+ // It is T1 Char and also if in cmd phase handle it.
+ //
+ if (T1Char && fpICCDevice->T1CharCmdDataPhase) {
+
+ // Save the N(s) from the card for later use.
+ fpICCDevice->NaSCard = (ReceivedBlockFrame[1] & NSBIT) >> 6;
+
+ // If data needs to be received
+ if (ReceivedBlockFrame[2]){
+ return GET_DATA_T1_CHAR;
+ } else {
+ return BLOCK_TRANSMISION_SUCCESS;
+ }
+
+ }
+
+ // It is T1TDPU or it is T1 Char but in data phase
+
+
+ // Is Mbit set, then nothing more to do
+ if (!(ReceivedBlockFrame[1] & 0x20)) {
+ //
+ // Toggle N(S) bit only after a successful I Block Transmission
+ //
+ fpICCDevice->Chaining = FALSE;
+ fpICCDevice->NaSInterface = !(fpICCDevice->NaSInterface);
+
+ return BLOCK_TRANSMISION_SUCCESS;
+ }
+ else {
+ // Since Mbit is set, Send R-Block with the next N(s) expected from card. Section 5, Rules 2.2 and 5
+
+ fpICCDevice->Chaining = TRUE;
+
+ if (fpICCDevice->NaSCard){
+ return SEND_R_BLOCK_0;
+ }
+ else {
+ return SEND_R_BLOCK_1;
+ }
+ }
+ }
+
+ // No difference between T1 Char and T1 Tdpu in R-phase
+
+ //
+ // Is the Block received is a R block?
+ //
+ if ((ReceivedBlockFrame[1] & 0xC0) == RBLOCK) {
+
+
+ // Is there an error?
+ if (ReceivedBlockFrame[1] & 0x03) {
+ //Re-transmit it
+ if ((SentBlockFrame[1] & 0xc0) == 0x00) {
+ return I_BLOCK_RESEND;
+ }
+ else {
+ return RESEND_BLOCK;
+ }
+ }
+
+ if (T1Char && fpICCDevice->T1CharCmdDataPhase) {
+ return GET_DATA_T1_CHAR;
+ }
+
+ if (fpICCDevice->RBlockCounter == 3) {
+ fpICCDevice->RBlockCounter = 0;
+ return BLOCK_TRANSMISSION_TERMINATE;
+ }
+ fpICCDevice->RBlockCounter++;
+
+ if (fpICCDevice->Chaining == FALSE) {
+
+ //
+ // if the received R-Block is same as the last sent I-Block AND Chaining is not in progress, resend I-Block. Scenario 8
+ //
+ if ((ReceivedBlockFrame[1] & 0x10) >> 4 == (fpICCDevice->NaSInterface & 1) << 6) {
+ return I_BLOCK_RESEND;
+ }
+ else {
+ //
+ // Scenario 11/12
+ //
+ if (fpICCDevice->NaSInterface & 1) {
+ return SEND_R_BLOCK_1;
+ } else {
+ return SEND_R_BLOCK_0;
+ }
+ }
+ }
+ else {
+ //
+ // Chaining is in progress...
+ //
+ //
+ // Scenario 5
+ //
+ if ((ReceivedBlockFrame[1] & 0x10) >> 4 != (fpICCDevice->NaSInterface & 1) << 6) {
+ // return I_BLOCK;
+ }
+ //
+ // Scenario 23
+ //
+ if (ReceivedBlockFrame[1] == SentBlockFrame[1]) {
+ if (ReceivedBlockFrame[1] & 0x10) {
+ return SEND_R_BLOCK_1;
+ } else {
+ return SEND_R_BLOCK_0;
+ }
+ }
+
+ }
+
+ // We can try giving S-Synch also if it doesn't respond to R-Block.
+ // S-Synch can be done only for 2nd Iblock on-wards.
+ }
+
+ //
+ // Is the Block Received is a S block?
+ //
+ if ((ReceivedBlockFrame[1] & 0xC0) == 0xC0) {
+
+ switch (ReceivedBlockFrame[1]) {
+
+ case IFS_REQUEST:
+
+ if (T1Char && fpICCDevice->T1CharCmdDataPhase) {
+ ReturnParameter = GET_DATA_T1_CHAR;
+ break;
+ }
+ // Save the new IFSD data
+ fpICCDevice->IFSD = ReceivedBlockFrame[3];
+ ReturnParameter = IFS_RESPONSE;
+ break;
+
+ case IFS_RESPONSE:
+ //
+ // It is T1 Char and also if in cmd phase handle it.
+ //
+ if (T1Char && fpICCDevice->T1CharCmdDataPhase) {
+
+ // If data needs to be received
+ if (ReceivedBlockFrame[2]){
+ return GET_DATA_T1_CHAR;
+ } else {
+ return BLOCK_TRANSMISION_SUCCESS;
+ }
+ }
+ break;
+
+ case ABORT_REQUEST:
+ fpICCDevice->Chaining = FALSE;
+ ReturnParameter = ABORT_RESPONSE;
+ break;
+
+ case ABORT_RESPONSE:
+ break;
+
+ case WTX_REQUEST:
+
+ if (T1Char && fpICCDevice->T1CharCmdDataPhase) {
+ ReturnParameter = GET_DATA_T1_CHAR;
+ break;
+ }
+
+ ReturnParameter = WTX_RESPONSE;
+ break;
+
+ case RESYNCH_RESPONSE:
+ break;
+
+ case WTX_RESPONSE: // Won't be received from card. Card will only generate WTX request.
+ break;
+ case RESYNCH_REQUEST: // Card won't issue ReSynch
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+ return ReturnParameter;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: CalculateLRCChecksum
+//
+// Description: Calculates LRC checksum
+//
+// Input:
+// UINT8 *BlockFrame
+// UINT32 BlockFrameLength
+//
+// Output:
+// ICC_DEVICE* or NULL
+//
+// Notes:
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+CalculateLRCChecksum (
+ UINT8 *BlockFrame,
+ UINT32 BlockFrameLength
+)
+{
+ UINT32 i = 0;
+
+ for (; i < BlockFrameLength - 1; i++ ){
+ BlockFrame[BlockFrameLength-1] ^= BlockFrame[i];
+ }
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: GetICCDevice
+//
+// Description: Search the linked list to find the ICC_DEVICE for the given slot #.
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// UINT8 Slot
+//
+// Output:
+// ICC_DEVICE* or NULL
+//
+// Notes:
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+ICC_DEVICE*
+GetICCDevice(
+ DEV_INFO *fpDevInfo,
+ UINT8 Slot
+)
+{
+ ICC_DEVICE *fpICCDevice;
+ DLINK *dlink;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ dlink = fpDevInfo->ICCDeviceList.pHead;
+
+ for ( ; dlink; dlink = dlink->pNext) {
+
+ fpICCDevice = OUTTER(dlink, ICCDeviceLink, ICC_DEVICE);
+
+ //
+ // Slot # matches
+ //
+ if (fpICCDevice->Slot == Slot) {
+ if (((UINT8*)fpICCDevice < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)((UINTN)fpICCDevice + sizeof(ICC_DEVICE)) > MemBlockEnd)) {
+ return NULL;
+ }
+ return fpICCDevice;
+ }
+
+ }
+
+ return NULL;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: UpdateATRDataInfo
+//
+// Description: The routine update the Transmision protocol supported and other
+// timing related data
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// None
+//
+// Notes: This function looks into ATR data and updates CLASS A/B/C information,
+// calculates ETU, WaitTime etc
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+UpdateATRDataInfo(
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+ UINT8 bData;
+ UINT8 i=1;
+
+ //
+ // T0 is mandatory
+ //
+ fpICCDevice->AtrData.T0 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.NumberofHystoricalBytes = fpICCDevice->RawATRData[i] & 0xF;
+ i++;
+
+ //
+ // Update TA1
+ //
+ if (fpICCDevice->AtrData.T0 & 0x10) {
+ fpICCDevice->AtrData.TA1 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TA1Present = TRUE;
+ i++;
+ } else {
+ //
+ // Default value if TA1 is not present
+ //
+ fpICCDevice->AtrData.TA1 = 0x11;
+ }
+
+ bData = fpICCDevice->AtrData.TA1;
+ fpICCDevice->GlobalFi = FiFmaxDi[(bData >> 4) * 3];
+ fpICCDevice->GlobalFmax = (UINT8)FiFmaxDi[(bData >> 4) * 3 + 1];
+ fpICCDevice->GlobalDi = (UINT8)FiFmaxDi[(bData& 0xF) * 3 + 2];
+
+
+ //
+ // Update TB1
+ //
+ if (fpICCDevice->AtrData.T0 & 0x20) {
+ fpICCDevice->AtrData.TB1 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TB1Present = TRUE;
+ i++;
+ }
+
+ //
+ // Update TC1
+ //
+ if (fpICCDevice->AtrData.T0 & 0x40) {
+ fpICCDevice->AtrData.TC1 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TC1Present = TRUE;
+ i++;
+ }
+
+ //
+ // Update TD1
+ //
+ if (fpICCDevice->AtrData.T0 & 0x80) {
+ fpICCDevice->AtrData.TD1 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TD1Present = TRUE;
+ i++;
+ }
+
+ if (fpICCDevice->AtrData.TD1) {
+
+ //
+ // Update TA2
+ //
+ if (fpICCDevice->AtrData.TD1 & 0x10) {
+ fpICCDevice->AtrData.TA2 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TA2Present = TRUE;
+ fpICCDevice->SpecificMode = fpICCDevice->AtrData.TA2 & BIT7 ? TRUE : FALSE;
+ i++;
+ }
+
+ //
+ // Update TB2
+ //
+ if (fpICCDevice->AtrData.TD1 & 0x20) {
+ fpICCDevice->AtrData.TB2 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TB2Present = TRUE;
+ i++;
+ }
+
+ //
+ // Update TC2
+ //
+ if (fpICCDevice->AtrData.TD1 & 0x40) {
+ fpICCDevice->AtrData.TC2 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TC2Present = TRUE;
+ i++;
+ }
+
+ //
+ // Update TD2
+ //
+ if (fpICCDevice->AtrData.TD1 & 0x80) {
+ fpICCDevice->AtrData.TD2 = fpICCDevice->RawATRData[i];
+ fpICCDevice->AtrData.TD2Present = TRUE;
+ i++;
+ }
+ }
+
+ //
+ // Check if T15 is present else only CLASS A is supported.
+ // By default CLASS A is supported
+ //
+ fpICCDevice->ClassABC = 1;
+
+ for (bData = 1; bData < MAX_ATR_LENGTH ;){
+
+ //
+ // Is it T15?
+ //
+ if ((fpICCDevice->RawATRData[bData] & 0xF) == 0xF){
+ fpICCDevice->ClassABC = fpICCDevice->RawATRData[bData + 1] & 0x3F;
+ fpICCDevice->StopClockSupport = fpICCDevice->RawATRData[bData + 1] >> 5;
+
+ fpICCDevice->AtrData.TD15 = fpICCDevice->RawATRData[bData];
+ fpICCDevice->AtrData.TD15Present = TRUE;
+
+ fpICCDevice->AtrData.TA15 = fpICCDevice->RawATRData[bData + 1];
+ fpICCDevice->AtrData.TA15Present = TRUE;
+
+ break;
+ } else {
+ // We need info on how many Transmission Protocols are supported by the
+ // card and what are those. Use these loop to do that.
+ if (bData > 1) { // Skip T0
+ i = fpICCDevice->TransmissionProtocolSupported;
+ fpICCDevice->TransmissionProtocolSupported |= ( 1 << (fpICCDevice->RawATRData[bData] & 0x0F));
+ if (i != fpICCDevice->TransmissionProtocolSupported) {
+ fpICCDevice->NumofTransmissionProtocolSupported++;
+ }
+ }
+
+ // No more valid TDx?
+ if (!(fpICCDevice->RawATRData[bData] & 0x80)) break;
+ bData += FindNumberOfTs(fpICCDevice->RawATRData[bData]);
+ }
+ }
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: GetDefaultProtocol
+//
+// Description: Find the First offerred Transmission protocol.
+//
+// Input:
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// TRANSMISSION_PROTOCOL
+//
+// Notes: Section 8.2.3 ISO 7816-3 2006-11-01: TD1 encodes first offered protocol.
+// If TD1 not present assume T0.
+//
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+TRANSMISSION_PROTOCOL GetDefaultProtocol (
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ if (fpICCDevice->AtrData.TD1Present) {
+ return fpICCDevice->AtrData.TD1 & 0xf;
+ }
+
+ return T0_PROTOCOL;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: FindBestTA1Value
+//
+// Description: CCID which doesn't perform "Automatic parameter config. based on ATR
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// UINT8 Best TA1 value
+//
+// Notes:
+// 1. Calculate the Baud rate using TA1 value
+//
+// 2. If in CCID bNumDataRatesSupported = 0 then any value between dwDatRate
+// and dwMaxDataRate is supported
+//
+// 3. Check if ICC baud rate is less tha dwMaxDataRate. If yes use that.
+//
+// 4. If bNumDataRatesSupported is not zero get all possible values and try to
+// match it and use that value.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+UINT8
+FindBestTA1Value (
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ UINT32 ICCBaudrate;
+ UINT8 Di = fpICCDevice->GlobalDi;
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return 0;
+ }
+ //
+ // If Automatic parameter conf. based on ATR data is
+ //
+ if (CCIDDescriptor->dwFeatures & AUTO_PARAMETER_CONFIG) {
+ return fpICCDevice->AtrData.TA1;
+ }
+
+ ICCBaudrate = (fpICCDevice->GlobalFmax * 1000 * fpICCDevice->GlobalDi)/fpICCDevice->GlobalFi;
+
+ if (fpDevInfo->DataRates && fpDevInfo->ClockFrequencies) {
+ /*
+ // Find the match
+ for (i = fpDevInfo->pCCIDDescriptor->bNumDataRatesSupported; i; --i) {
+ // Since the values may not match exactly give some leeway
+ if (ICCBaudrate >= (fpDevInfo->DataRates[i] - 1000) && ICCBaudrate <= (fpDevInfo->DataRates[i] + 1000)){
+ // See whether the matched baud rate can be achieved with the supported frequencies
+ for (j = fpDevInfo->pCCIDDescriptor->bNumDataRatesSupported; j; --j) {
+ if (fpICCDevice->GlobalFmax == fpDevInfo->ClockFrequencies[i]) break;
+ }
+ if (j) {
+ CalcBaudRate =
+ }
+ else {
+ }
+ break;
+ }
+ }
+ */
+ } else {
+ if (ICCBaudrate <= CCIDDescriptor->dwMaxDataRate) {
+ return fpICCDevice->AtrData.TA1;
+ } else {
+ //
+ // Can we decrement the Di value and try to match it
+ //
+ for ( ; Di ; --Di){
+ ICCBaudrate = (fpICCDevice->GlobalFmax * 1000 * Di)/fpICCDevice->GlobalFi;
+ if (ICCBaudrate <= CCIDDescriptor->dwMaxDataRate) {
+ return ((fpICCDevice->AtrData.TA1 & 0xF0) | Di);
+ }
+ }
+ }
+ }
+
+ //
+ // Worst case return the default value.
+ // Actuall we should fail saying this CCID/ICC combination isn't supported.
+ //
+ return fpICCDevice->AtrData.TA1;
+
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: CalculateTimingValues
+//
+// Description: Based on the agreed upon TA1 value and Transmission protocol
+// calculate the timing values
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// None
+//
+// Notes:
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+CalculateTimingValues (
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ UINT8 NValue;
+ UINT8 bData;
+ UINT8 TDCount = 0;
+
+ fpICCDevice->bmFindIndex = fpICCDevice->AtrData.TA1;
+
+ //
+ // NValue defaults to zero if TC1 not present
+ //
+ NValue = fpICCDevice->AtrData.TC1Present == TRUE ? fpICCDevice->AtrData.TC1 : 0;
+
+ //
+ // Calculate 1 etu in micro sec
+ //
+ fpICCDevice->etu = fpICCDevice->GlobalFi / (fpICCDevice->GlobalDi * fpICCDevice->GlobalFmax);
+
+ //
+ // Extra Gaurd Time GT in etu units (section 8.3)
+ //
+ if (fpICCDevice->AtrData.TA15Present) {
+ fpICCDevice->ExtraGuardTime = 12 +
+ (NValue / fpICCDevice->GlobalFmax * fpICCDevice->GlobalFi/ fpICCDevice->GlobalDi);
+ } else {
+ fpICCDevice->ExtraGuardTime = 12 + (NValue / fpICCDevice->GlobalFmax) ;
+ }
+
+ // Update Wait Time (see section 10.2)
+ // WT = WI * 960 * Fi /f where WI is TC2
+ // Default if TC2 is not present
+ bData = 10;
+
+ if (fpICCDevice->AtrData.TC2Present) {
+ bData = fpICCDevice->AtrData.TC2;
+ }
+
+ //
+ // Calculate WT (wait time between two characters) in ETU units
+ //
+ fpICCDevice->WTwaittime = 960 * fpICCDevice->GlobalFi/(fpICCDevice->GlobalFmax);
+
+
+ // update Block Width time and Epilogue bit
+ // BWT = 11etu + 2 ^ BWI * 960 * Fd /f (Section 11.4.3)
+ // Default BWI is 4. Bit 7:4 in first TB for T1 encodes BWI
+ // Fd = 372 (sec section 8.1)
+
+ // Default values (11.4.3)
+ fpICCDevice->BWI = 4;
+ fpICCDevice->CWI = 13;
+ fpICCDevice->IFSC = 32;
+ fpICCDevice->IFSD = 32;
+ fpICCDevice->NAD = 0;
+
+ for (bData = 1; bData < MAX_ATR_LENGTH; ){
+
+ // Look for the First TD for T= 1. It should from TD2
+ if (TDCount < 2) {
+ if (fpICCDevice->RawATRData[bData] & 0x80) {
+ TDCount++;
+ bData += FindNumberOfTs(fpICCDevice->RawATRData[bData]);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ // Is it T1?
+ if ((fpICCDevice->RawATRData[bData] & 0xF) == 0x1){
+
+ if (fpICCDevice->RawATRData[bData] & 0x10) {
+ fpICCDevice->IFSC = fpICCDevice->RawATRData[bData + 1];
+ }
+
+ if (fpICCDevice->RawATRData[bData] & 0x20) {
+ fpICCDevice->BWI = (fpICCDevice->RawATRData[bData + 2] & 0xF0) >> 4;
+ fpICCDevice->CWI = fpICCDevice->RawATRData[bData + 2] & 0xF;
+ }
+
+ // Section 11.4.4
+ if (fpICCDevice->RawATRData[bData] & 0x40) {
+ fpICCDevice->EpilogueFields = (fpICCDevice->RawATRData[bData + 3] & 0x1);
+ }
+
+ break;
+ }
+
+ //
+ // No more valid TDx?
+ //
+ if (!(fpICCDevice->RawATRData[bData] & 0x80)) break;
+
+ bData += FindNumberOfTs(fpICCDevice->RawATRData[bData]);
+
+ }
+
+ //
+ // Block Widthtime in ETU units
+ //
+ fpICCDevice->BWT = ((1 << (fpICCDevice->BWI - 1)) * 960 * 372 /(fpICCDevice->GlobalFmax)) + 11;
+
+ PrintTimingInfo(fpICCDevice);
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: IssuePPSCmd
+//
+// Description: Issue PPS cmd to select T0/T1
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// ICC_DEVICE *fpICCDevice
+// UINT8 *Data : Points to the buffer which is sent to CCID.
+// Refer Section 9.2 of 7816-3 spec for the format
+//
+// Output:
+// EFI_STATUS
+//
+// Notes:
+// This command is issued to CCID which doesn't support AUTO_PARAMETER_CONFIG
+// or when default values or not acceptable
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+IssuePPSCmd(
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice,
+ UINT8 *Data,
+ UINT8 DataLength
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT8 *ResponseBuffer;
+ UINT32 ResponseLength = DataLength;
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Allocate memory for receiving data
+ //
+ ResponseBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(DataLength));
+ ASSERT(ResponseBuffer);
+ if (!ResponseBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)ResponseBuffer, DataLength, 0);
+
+
+ //
+ //Check what level of Transmission Protocol is supported
+ //
+ ResponseLength = 0;
+ if (!(CCIDDescriptor->dwFeatures & 0x70000)){
+ ResponseLength = 2; // For Character exchange only 2 bytes expected.
+ }
+
+
+ Status = PCToRDRXfrBlock(fpDevInfo, fpICCDevice, DataLength, Data, 0, ResponseLength);
+ if (CCIDDescriptor->dwFeatures & 0x70000){
+ ResponseLength = 4; // For TDPU expected data is 4
+ }
+ Status = RDRToPCDataBlock(fpDevInfo, fpICCDevice, &ResponseLength, ResponseBuffer);
+
+ // If length is not same and only Character level Transmission is supported,
+ // issue another XfrBlock cmd to get the rest of the data
+ if ((ResponseLength != DataLength) && !(CCIDDescriptor->dwFeatures & 0x70000)) {
+
+ DataLength = ResponseLength;
+ ResponseLength = 2;
+ Status = PCToRDRXfrBlock(fpDevInfo, fpICCDevice, 0, Data, 0, ResponseLength);
+ Status = RDRToPCDataBlock(fpDevInfo, fpICCDevice, &ResponseLength, ResponseBuffer + DataLength);
+
+ }
+
+ //
+ // I/P and O/P should be identical for success
+ //
+ USB_MemFree(ResponseBuffer, (UINT8)GET_MEM_BLK_COUNT(DataLength));
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: VoltageSelection
+//
+// Description: Based on the dwFeatures register setting, power up CCID/ICC
+//
+// Input:
+// DEV_INFO *fpDevInfo,
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: Based on dwFeatures value from SMART Class Descriptor either
+// do an automatic Power-on or go through a manual
+// power up sequence and then callect the ATR data.
+//
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+VoltageSelection(
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_DEVICE_ERROR;
+ EFI_STATUS ATRStatus = EFI_DEVICE_ERROR;
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+ //
+ // Get all voltage level supported by CCID
+ //
+ UINT8 VoltageLevelCCID = CCIDDescriptor->bVoltageSupport;
+ //
+ // Select the lowest voltage
+ //
+ UINT8 VoltageMask = VOLT_18;
+ //
+ // Successful poweron will result in ATR data
+ //
+ UINT32 BufferLength = MAX_ATR_LENGTH;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Make sure the first selection is valid
+ //
+ do {
+
+ if (VoltageLevelCCID & VoltageMask) {
+ break;
+ }
+
+ VoltageMask = VoltageMask >> 1;
+
+ }while (VoltageMask);
+
+ //
+ // If Automatic Voltage selection is supported go for it.
+ // Discard the initialization done above
+ if (CCIDDescriptor->dwFeatures & AUTO_ACTIVATION_VOLT_SELECTION){
+ //
+ // Automatic Voltage selection is supported
+ //
+ VoltageLevelCCID = AUTO_VOLT;
+ VoltageMask = 0;
+ }
+
+ do {
+
+ //
+ // Issue the cmd to Power it up
+ //
+ Status = PCtoRDRIccPowerOn (fpDevInfo,
+ fpICCDevice,
+ ((VoltageLevelCCID & VoltageMask) == 4) ? 3 : VoltageMask);
+
+ if(EFI_ERROR(Status)) {
+ break;
+ }
+
+ //
+ // Get the response to IccPoweron
+ //
+ BufferLength = MAX_ATR_LENGTH;
+ Status = RDRToPCDataBlock ( fpDevInfo,
+ fpICCDevice,
+ &BufferLength,
+ fpICCDevice->RawATRData
+ );
+
+ //
+ // if successfully powered up, ATR data should be available
+ //
+ if (!EFI_ERROR(Status) && BufferLength) {
+
+ fpICCDevice->ConfiguredStatus |= (ICCPRESENT | VOLTAGEAPPLIED | ATRDATAPRESENT);
+
+ PrintATRData(fpICCDevice->RawATRData);
+
+ // From the ATR data, get the required information
+ UpdateATRDataInfo(fpDevInfo, fpICCDevice);
+
+ // ATR data got successfully and configured successfully.
+ ATRStatus = EFI_SUCCESS;
+ break;
+
+ }
+
+ //
+ // if Card not present
+ //
+ if ((fpICCDevice->bStatus & 7) == 2) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ //
+ // ICC is present but some error
+ //
+ fpICCDevice->ConfiguredStatus |= ICCPRESENT;
+
+ //
+ // Card present but voltage selection is not OK. Power it off and select next voltage
+ //
+ Status = PCtoRDRIccPowerOff (fpDevInfo, fpICCDevice);
+ if (EFI_ERROR(Status)) break;
+
+ Status = RDRToPCSlotStatus(fpDevInfo, fpICCDevice);
+ if (EFI_ERROR(Status)) break;
+
+ VoltageMask = VoltageMask >> 1;
+
+ //
+ // 10 msec delay before applying the next power class Spec 6.2.3
+ //
+ FixedDelay (10 * 1000);
+
+ } while (VoltageMask);
+
+ // Return the status of the ATR data read and configuration
+ return ATRStatus;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: RateAndProtocolManagement
+//
+// Description: Based on the ATR data and the dwFeature register contend
+// do the Rate and Protocol programming
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: Based on data received from Power-on sequence (ATR data) and dwFetaures value,
+// Speed of communicatin is established.
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+RateAndProtocolManagement(
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ PROTOCOL_DATA_T1 Data = {0};
+ UINT8 PPSData[] = {0xFF, 0x10, 0x11, 0x00};
+ UINT8 Counter;
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+ UINT32 ClockFrequency = CCIDDescriptor->dwMaximumClock;
+ UINT32 DataRate = CCIDDescriptor->dwMaxDataRate;
+ BOOLEAN FlagToIssueSetParameters = FALSE;
+ TRANSMISSION_PROTOCOL FirstOfferredProtocol;
+ UINT8 DefaultTA1 = fpICCDevice->AtrData.TA1;
+ UINT8 SetIFS[] = {0xFC};
+ UINT32 ResponseLength;
+ UINT8 ResponseBuffer[20];
+ UINT32 ExchangeLevel = (CCIDDescriptor->dwFeatures & 0x70000);
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return EFI_DEVICE_ERROR;
+ }
+ FirstOfferredProtocol = GetDefaultProtocol(fpICCDevice);
+
+ fpICCDevice->bProtocolNum = (UINT8)FirstOfferredProtocol;
+
+ //
+ // Check whether TA1 value is good enough for the reader. If not get the right value
+ //
+ fpICCDevice->AtrData.TA1 = FindBestTA1Value(fpDevInfo, fpICCDevice);
+
+
+ //
+ // Check if more than one transmission protocol is supported.
+ // If yes then there may be a need for PPSCmd (ISO 7816-3:2006(E) Sec: 6.3.1)
+ // Check if Automatic PPS negotiation done by CCID or not. If not issue one.
+ // If TA2 is present Card is in Specific mode. So no need for PPS (7816-3:2006 see sec 6.3 fig 4)
+ //
+
+ // When PPS exchange must be made? (Page 19 CCID Rev 1.1)
+ // 1. If both AUTO_PPS_NEGOTIATION_CCID AND AUTO_PPS_NEGOTIATION_ACTIVE are not set PPS must be given in case of TDPU or Character
+ // OR
+ // 2. if AUTO_PPS_NEGOTIATION_ACTIVE is present AND TA2 not present AND the preferred protocol isn't USE_T0_T1_PROTOCOL
+
+ if (((CCIDDescriptor->dwFeatures & (AUTO_PPS_NEGOTIATION_CCID | AUTO_PPS_NEGOTIATION_ACTIVE)) == 0 &&
+ (ExchangeLevel <= 0x10000 ) && !fpICCDevice->AtrData.TA2Present) ||
+ ((CCIDDescriptor->dwFeatures & AUTO_PPS_NEGOTIATION_ACTIVE) && !fpICCDevice->AtrData.TA2Present &&
+ fpICCDevice->NumofTransmissionProtocolSupported > 1 && FirstOfferredProtocol != USE_T0_T1_PROTOCOL)) {
+ //
+ // Update PPS data if in case PPSCmd needs to be issued
+ //
+ PPSData[1] |= FirstOfferredProtocol;
+
+ //
+ // Update PPS2
+ //
+ PPSData[2] = fpICCDevice->AtrData.TA1;
+
+ //
+ // Update checksum
+ //
+ for (Counter = 0; Counter < sizeof (PPSData) - 1; Counter++) {
+ PPSData[sizeof (PPSData) - 1] ^= PPSData[Counter];
+ }
+
+ Status = IssuePPSCmd(fpDevInfo, fpICCDevice, PPSData, sizeof (PPSData));
+ }
+
+ if (CCIDDescriptor->dwFeatures & AUTO_PARAMETER_CONFIG) {
+
+ //
+ // Issue GetParameters to get the Transmission Protocol and other parameters
+ //
+ Status = PCToRDRGetParameters(fpDevInfo, fpICCDevice);
+ if (EFI_ERROR(Status)) return Status;
+
+ Status = RDRToPCParameters(fpDevInfo, fpICCDevice);
+ if (EFI_ERROR(Status)) return Status;
+
+ fpICCDevice->ExtraGuardTime = fpICCDevice->bGuardTime;
+ fpICCDevice->WTwaittime = fpICCDevice->bWaitingInteger;
+ fpICCDevice->IFSC = fpICCDevice->bIFSC;
+ fpICCDevice->NAD = fpICCDevice->nNadValue;
+
+ } else {
+
+ //
+ // Now that the TA1 value and the protocol has been finalized,
+ // It is time to calculate the different timing parameters.
+ //
+ CalculateTimingValues (fpDevInfo, fpICCDevice);
+ }
+
+ //
+ //If Automatic Parameters config. based on ATR data is not
+ //supported then issue SetParameters cmd
+ //
+ if (!(CCIDDescriptor->dwFeatures & AUTO_PPS_NEGOTIATION_ACTIVE)){ // 0x80
+
+ //
+ // Use the superset of the T0/T1 structure (ie T1 structure) even if it is T0. It should work.
+ //
+ Data.bmFindDindex = fpICCDevice->bmFindIndex;
+ Data.bmTCCKST1 = fpICCDevice->bProtocolNum == 0 ? 0 : (fpICCDevice->EpilogueFields | 0x10);
+ Data.bGuardTimeT1 = fpICCDevice->ExtraGuardTime;
+
+ Data.bWaitingIntergersT1 = fpICCDevice->bProtocolNum == 0 ?
+ fpICCDevice->WTwaittime : (fpICCDevice->BWI << 4 | fpICCDevice->CWI);
+
+ Data.bClockStop = fpICCDevice->bClockStop;
+ Data.bIFSC = fpICCDevice->IFSC;
+ Data.bNadValue = fpICCDevice->NAD;
+
+ Status = PCToRDRSetParameters(fpDevInfo, fpICCDevice, fpICCDevice->bProtocolNum, (VOID *)&Data);
+
+ if (!EFI_ERROR(Status)){
+ Status = RDRToPCParameters(fpDevInfo, fpICCDevice);
+ } else {
+ //
+ // Handle failure cases. Look at it later.
+ //
+ }
+ }
+
+ //
+ // Based on T0 or T1 update Waittime. For T0 use WTWaittime, for T1 use BWT.
+ //
+ if (fpICCDevice->bProtocolNum) {
+ fpICCDevice->WaitTime = fpICCDevice->BWT;
+ } else {
+ fpICCDevice->WaitTime = fpICCDevice->WTwaittime;
+ }
+
+ //
+ // If Automatic ICC Clock Freq AND Automatic Buad Rate selection
+ // isn't supported issue SetDataRateAndClock cmd
+ //
+ if (!(CCIDDescriptor->dwFeatures & (AUTO_BAUD_RATE_SELECTION |AUTO_ICC_CLOCK_FREQ))){
+
+ }
+
+ //
+ // Check if IFSC/IFSD needs to be increased. Default value is 0x20. T1 and TDPU/Char needs this cmd.
+ //
+ if (fpICCDevice->bProtocolNum){
+ switch(CCIDDescriptor->dwFeatures & 0x70000) {
+ case CHARACTER_LEVEL_EXCHANGE:
+ // Both SUZCR90 and O2Micro oz77c6l1 didn't respond to SBlock call below without this delay
+ FixedDelay(10 * 1000); // 10msec delay. No break. Let the flow continue below.
+ case TDPU_LEVEL_EXCHANGE:
+ ResponseLength = 1;
+ SetIFS[0] = (UINT8)CCIDDescriptor->dwMaxIFSD;
+ Status = TxRxT1TDPUChar (fpDevInfo, fpICCDevice, sizeof (SetIFS), SetIFS, IFS_REQUEST, &ResponseLength, ResponseBuffer);
+ // Update the received IFSD
+ if (!EFI_ERROR(Status) && ResponseLength == 1){
+ fpICCDevice->IFSD = ResponseBuffer[0];
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: ConfigureCCID
+//
+// Description: This function powers up, sets the clock/rate etc
+// (configure CCID based on device capability)
+//
+// Input:
+// DEV_INFO *fpDevInfo,
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: VoltageSelection, RateAndProtocolManagement
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+ConfigureCCID(
+ DEV_INFO *fpDevInfo,
+ ICC_DEVICE *fpICCDevice
+)
+{
+ EFI_STATUS Status;
+ UINT8 RetryCount = 3;
+
+ //
+ // Power up the device
+ //
+ do {
+ Status = VoltageSelection(fpDevInfo, fpICCDevice);
+ RetryCount--;
+
+ //
+ // check for errors and do try to recover
+ //
+ if(EFI_ERROR(Status) || fpICCDevice->bStatus) {
+ //
+ // If card present but not powered up retry it.
+ // If card not present the exit immediatly
+ //
+ if (fpICCDevice->bStatus == 2) {
+ break;
+ }
+ } else {
+ break;
+ }
+
+ }while (RetryCount);
+
+ //
+ //Configure the data Rate and select the Protocol
+ //
+ if (!EFI_ERROR(Status)){
+ Status = RateAndProtocolManagement (fpDevInfo, fpICCDevice);
+ }
+
+ if (EFI_ERROR(Status)) {
+ fpICCDevice->ConfiguredStatus = CONFIGFAILED;
+ }
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDIssueBulkTransfer
+//
+// Description: This function executes a bulk transaction on the USB. The
+// transfer may be either DATA_IN or DATA_OUT packets containing
+// data sent from the host to the device or vice-versa. This
+// function wil not return until the request either completes
+// successfully or completes with error (due to time out, etc.)
+// Size of data can be upto 64K
+//
+// Input: - DeviceInfo structure (if available else 0)
+// - Transfer direction
+// Bit 7 : Data direction
+// 0 Host sending data to device
+// 1 Device sending data to host
+// Bit 6-0 : Reserved
+// - Buffer containing data to be sent to the device or
+// buffer to be used to receive data. Value in
+// - Length request parameter, number of bytes of data
+// to be transferred in or out of the host controller
+//
+// Output: Amount of data transferred
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+USBCCIDIssueBulkTransfer (
+ DEV_INFO* fpDevInfo,
+ UINT8 bXferDir,
+ UINT8* fpCmdBuffer,
+ UINT32 dSize
+)
+{
+ return (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable
+ [fpDevInfo->bHCNumber - 1]->bHCType)].pfnHCDBulkTransfer)
+ (gUsbData->HcTable[fpDevInfo->bHCNumber -1],
+ fpDevInfo, bXferDir,
+ fpCmdBuffer, dSize);
+
+ // Handle Bulk Transfer error here
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDIssueControlTransfer
+//
+// Description: Issues Control Pipe request to default pipe
+//
+// Parameters: pDevInfo DeviceInfo structure (if available else 0)
+// wRequest Request type (low byte)
+// Bit 7 : Data direction
+// 0 = Host sending data to device
+// 1 = Device sending data to host
+// Bit 6-5 : Type
+// 00 = Standard USB request
+// 01 = Class specific
+// 10 = Vendor specific
+// 11 = Reserved
+// Bit 4-0 : Recipient
+// 00000 = Device
+// 00001 = Interface
+// 00010 = Endpoint
+// 00100 - 11111 = Reserved
+// Request code, a one byte code describing
+// the actual device request to be executed
+// (ex: 1 : ABORT, 2 : GET_CLOCK_FREQUENCIES, 3: GET_DATA_RATES)
+// wIndex wIndex request parameter (meaning varies)
+// wValue wValue request parameter (meaning varies)
+// fpBuffer Buffer containing data to be sent to the
+// device or buffer to be used to receive data
+// wLength wLength request parameter, number of bytes
+// of data to be transferred in or out
+// of the host controller
+//
+// Output: Number of bytes actually transferred
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+USBCCIDIssueControlTransfer(
+ DEV_INFO* fpDevInfo,
+ UINT16 wRequest,
+ UINT16 wIndex,
+ UINT16 wValue,
+ UINT8 *fpBuffer,
+ UINT16 wLength
+)
+{
+
+ //
+ // Not tested due to lack of H/W which supports it
+ //
+ return (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable
+ [fpDevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer)
+ (gUsbData->HcTable[fpDevInfo->bHCNumber - 1],
+ fpDevInfo,
+ wRequest,
+ wIndex,
+ wValue,
+ fpBuffer,
+ wLength);
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: FindNumberOfTs
+//
+// Description: Returns the # of Ts present in TDx
+//
+// Input:
+// UINT8 Data
+//
+// Output:
+// UINT8 - Returns number of TDx present in ATR data
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+UINT8
+FindNumberOfTs(
+ UINT8 Data
+)
+{
+ UINT8 Count = 0;
+ UINT8 Mask = 0x10;
+
+ for ( ;Mask; Mask = Mask << 1){
+ if (Data & Mask) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: PrintPCParameters
+//
+// Description: This function prints the information gathered from GetPCParameters
+//
+// Input:
+// UINT8 * Data
+//
+// OutPut:
+// None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+PrintPCParameters(
+ UINT8 * Data
+)
+{
+
+ USB_DEBUG (DEBUG_LEVEL_3, "bProtocolNum : %02X\n", Data[0]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bmFindexDIndex : %02X\n", Data[1]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bmTCCKST0 : %02X\n", Data[2]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bGaurdTime : %02X\n", Data[3]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bWaitingInterger : %02X\n", Data[4]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bClockStop : %02X\n", Data[5]);
+ USB_DEBUG (DEBUG_LEVEL_3, "bIFSC : %02X\n", Data[6]); // Valid only for T1
+ USB_DEBUG (DEBUG_LEVEL_3, "bNadValue : %02X\n", Data[7]); // Valid only for T1
+
+ return;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: PrintTimingInfo
+//
+// Description: This function prints the information gathered from ATR data
+//
+// Input:
+// ICC_DEVICE *fpICCDevice
+//
+// Output:
+// None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+PrintTimingInfo(
+ ICC_DEVICE *fpICCDevice
+)
+{
+
+ USB_DEBUG (DEBUG_LEVEL_3, "etu : %02X \n", fpICCDevice->etu);
+ USB_DEBUG (DEBUG_LEVEL_3, "GlobalFi : %04x \n", fpICCDevice->GlobalFi);
+ USB_DEBUG (DEBUG_LEVEL_3, "GlobalFmax : %02X \n", fpICCDevice->GlobalFmax);
+ USB_DEBUG (DEBUG_LEVEL_3, "GlobalDi : %02X \n", fpICCDevice->GlobalDi);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "SpecificMode : %02X \n", fpICCDevice->SpecificMode);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "ClassABC : %02X \n", fpICCDevice->ClassABC);
+ USB_DEBUG (DEBUG_LEVEL_3, "StopClockSupport : %02X \n", fpICCDevice->StopClockSupport);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "ExtraGuardTime : %02X \n", fpICCDevice->ExtraGuardTime);
+ USB_DEBUG (DEBUG_LEVEL_3, "WTwaittime : %08x \n", fpICCDevice->WTwaittime);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "BWI : %02X \n", fpICCDevice->BWI);
+ USB_DEBUG (DEBUG_LEVEL_3, "CWI : %02X \n", fpICCDevice->CWI);
+ USB_DEBUG (DEBUG_LEVEL_3, "IFSC : %02X \n", fpICCDevice->IFSC);
+ USB_DEBUG (DEBUG_LEVEL_3, "NAD : %02X \n", fpICCDevice->NAD);
+ USB_DEBUG (DEBUG_LEVEL_3, "EpilogueFields : %02X \n", fpICCDevice->EpilogueFields);
+ USB_DEBUG (DEBUG_LEVEL_3, "BWT : %02X \n", fpICCDevice->BWT);
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: PrintATRData
+//
+// Description: This function Prints the RAW ATR Data
+//
+// Input:
+// UINT8 *ATRData
+//
+// Output:
+// None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+PrintATRData(
+ UINT8 *ATRData
+)
+{
+
+ UINT8 TDx = 2;
+ UINT8 i;
+
+
+ USB_DEBUG (DEBUG_LEVEL_3, " ATR Data \n");
+
+ for (i=0; i< 32; i++) {
+ USB_DEBUG (DEBUG_LEVEL_3, "%02X ", ATRData[i]);
+ }
+
+ i = 0;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "\nTS : %02X \n", ATRData[i++]);
+
+ TDx = ATRData[i];
+ USB_DEBUG (DEBUG_LEVEL_3, "T0 : %02X \n", ATRData[i++]);
+ USB_DEBUG (DEBUG_LEVEL_3, "TA1 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB1 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC1 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD1 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA2 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB2 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC2 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD2 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA3 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB3 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC3 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD3 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA4 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB4 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC4 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD4 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA5 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB5 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC5 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD5 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA6 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB6 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC6 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD6 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ if (!(TDx & 0x80)) return;
+ TDx = ATRData[i-1];
+
+ USB_DEBUG (DEBUG_LEVEL_3, "TA7 : %02X \n", TDx & 0x10 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TB7 : %02X \n", TDx & 0x20 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TC7 : %02X \n", TDx & 0x40 ? ATRData[i++] : 0);
+ USB_DEBUG (DEBUG_LEVEL_3, "TD7 : %02X \n", TDx & 0x80 ? ATRData[i++] : 0);
+
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: PrintDescriptorInformation
+//
+// Description: Prints SMART class Descriptor data
+//
+// Input:
+// SMARTCLASS_DESC *fpCCIDDesc
+//
+// Output:
+// None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID
+PrintDescriptorInformation (
+ SMARTCLASS_DESC *fpCCIDDesc
+)
+{
+
+ CHAR8 *Strings[] = {"CHARACTER", "TDPU", "Short ADPU", "Extended ADPU"};
+ UINT8 Exchange = (fpCCIDDesc->dwFeatures & 0x70000) >> 16;
+
+ USB_DEBUG (DEBUG_LEVEL_3, "Sizeof SMART Class Descriptor : %X\n", sizeof (SMARTCLASS_DESC));
+ USB_DEBUG (DEBUG_LEVEL_3, "bDescLength : %04X\n", fpCCIDDesc->bDescLength);
+ USB_DEBUG (DEBUG_LEVEL_3, "bDescType : %04X\n", fpCCIDDesc->bDescType);
+ USB_DEBUG (DEBUG_LEVEL_3, "bcdCCID : %04X\n", fpCCIDDesc->bcdCCID);
+ USB_DEBUG (DEBUG_LEVEL_3, "bMaxSlotIndex : %04X\n", fpCCIDDesc->bMaxSlotIndex);
+ USB_DEBUG (DEBUG_LEVEL_3, "bVoltageSupport : %04X\n", fpCCIDDesc->bVoltageSupport);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwProtocols : %04X\n", fpCCIDDesc->dwProtocols);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwDefaultClock : %04X\n", fpCCIDDesc->dwDefaultClock);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwMaximumClock : %04X\n", fpCCIDDesc->dwMaximumClock);
+ USB_DEBUG (DEBUG_LEVEL_3, "bNumClockSupported : %04X\n", fpCCIDDesc->bNumClockSupported);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwDataRate : %04X\n", fpCCIDDesc->dwDataRate);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwMaxDataRate : %04X\n", fpCCIDDesc->dwMaxDataRate);
+ USB_DEBUG (DEBUG_LEVEL_3, "bNumDataRatesSupported : %04X\n", fpCCIDDesc->bNumDataRatesSupported);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwMaxIFSD : %04X\n", fpCCIDDesc->dwMaxIFSD);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwSynchProtocols : %04X\n", fpCCIDDesc->dwSynchProtocols);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwMechanical : %04X\n", fpCCIDDesc->dwMechanical);
+ USB_DEBUG (DEBUG_LEVEL_3, "dwFeatures : %04X\n", fpCCIDDesc->dwFeatures);
+ USB_DEBUG (DEBUG_LEVEL_3, "bClassGetResponse : %04X\n", fpCCIDDesc->dwMaxCCIDMessageLength);
+ USB_DEBUG (DEBUG_LEVEL_3, "bClassGetResponse : %04X\n", fpCCIDDesc->bClassGetResponse);
+ USB_DEBUG (DEBUG_LEVEL_3, "bClassEnvelope : %04X\n", fpCCIDDesc->bClassEnvelope);
+ USB_DEBUG (DEBUG_LEVEL_3, "wLcdLayout : %04X\n", fpCCIDDesc->wLcdLayout);
+ USB_DEBUG (DEBUG_LEVEL_3, "bPINSupport : %04X\n", fpCCIDDesc->bPINSupport);
+ USB_DEBUG (DEBUG_LEVEL_3, "bMaxCCIDBusySlots : %04X\n", fpCCIDDesc->bMaxCCIDBusySlots);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "*************************************\n");
+ USB_DEBUG (DEBUG_LEVEL_3, " Device is in:");
+ USB_DEBUG (DEBUG_LEVEL_3, "%s Exchange mode\n", Strings[Exchange]);
+ USB_DEBUG (DEBUG_LEVEL_3, "*************************************\n");
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCID_ProcessInterruptData
+//
+// Description: This routine is called when InterruptIN messages is generated
+//
+// Input: pHCStruc Pointer to HCStruc
+// pDevInfo Pointer to device information structure
+// pTD Pointer to the polling TD
+// pBuffer Pointer to the data buffer
+//
+// Output:
+// UEB_ERROR/USB_SUCCESS
+//
+// Notes: When an ICC card is inserted or removed Interrupt message is generated.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+USBCCID_ProcessInterruptData (
+ HC_STRUC *HcStruc,
+ DEV_INFO *DevInfo,
+ UINT8 *Td,
+ UINT8 *Buffer,
+ UINT16 DataLength
+)
+{
+
+ EFI_STATUS Status;
+ UINT8 Data;
+ UINT8 Slot = 0;
+ UINT8 bmSlotICCByte = 0;
+ UINT32 SlotICCStatus = *(UINT32 *)(Buffer + 1);
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)DevInfo->pCCIDDescriptor;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+
+ if (((UINT8*)DevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)DevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return USB_ERROR;
+ }
+
+ USB_DEBUG(DEBUG_LEVEL_3, "USBCCID_ProcessInterruptData.... %X %X %X %X\n",
+ *Buffer, *(Buffer +1), *(Buffer + 2), *(Buffer + 3));
+
+
+ switch (*Buffer) {
+
+ //
+ // ICC Card either inserted or Removed
+ //
+ case RDR_TO_PC_NOTIFYSLOTCHANGE:
+
+ //
+ // Find the # of bytes in this notification
+ //
+ Slot = CCIDDescriptor->bMaxSlotIndex + 1; // Make it 1 based
+ bmSlotICCByte = (CCIDDescriptor->bMaxSlotIndex + 1) >> 2;
+
+ if (Slot & 0x3) {
+ bmSlotICCByte++;
+ }
+
+ Slot = 0;
+ do {
+ Data = (SlotICCStatus >> Slot) & 0x3;
+ //
+ // Is there a change in status
+ //
+ if ((Data & 0x3) == 3) {
+ Status = ICCInsertEvent (DevInfo, Slot);
+ }
+ if ((Data & 0x3) == 2) {
+ Status = ICCRemovalEvent (DevInfo, Slot);
+ }
+ Slot++;
+ } while (Slot < (CCIDDescriptor->bMaxSlotIndex + 1));
+
+ break;
+
+ case RDR_TO_PC_HARDWAREERROR:
+
+ USB_DEBUG(DEBUG_LEVEL_3, "RDR To PC Hardware Error Slot %X Sequence %X Error Code %X \n",
+ *Buffer, *(Buffer +1), *(Buffer + 2));
+ break;
+
+ default:
+ break;
+ }
+
+ return USB_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: ICCRemovalEvent
+//
+// Description: In response to Device removal, Interrupt-in message is received.
+// Icc Device is removed from the linked list.
+//
+// Input:
+// DEV_INFO *fpDevInfo,
+// UINT8 Slot
+//
+// Output:
+// EFI_STATUS
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+ICCRemovalEvent(
+ DEV_INFO *fpDevInfo,
+ UINT8 Slot
+)
+{
+
+ ICC_DEVICE *fpICCDevice;
+
+ fpICCDevice = GetICCDevice(fpDevInfo, Slot);
+
+ if (fpICCDevice) {
+
+ // Don't free up the memory. EFI driver (EfiUsbCCID) makes use of this data area to
+ // find whether ICC has been removed or added.
+ // Before freeing up, clear the bytes
+
+// MemFill((UINT8 *)fpICCDevice, sizeof(ICC_DEVICE), 0);
+
+ //
+ //Free up the memory and remove it from linked list
+ //
+// DListDelete (&(fpDevInfo->ICCDeviceList), &(fpICCDevice->ICCDeviceLink));
+// USB_MemFree(fpICCDevice, (UINT8)GET_MEM_BLK_COUNT(sizeof(ICC_DEVICE)));
+
+ if (fpICCDevice->ConfiguredStatus) {
+ fpICCDevice->ConfiguredStatus = 0;
+ } else {
+ //
+ // Handle if IccRemovalEven is called multiple times
+ //
+ return EFI_SUCCESS;
+ }
+
+ USB_DEBUG(DEBUG_LEVEL_3, "ICC device removed - Slot : %X\n", Slot);
+
+ if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) {
+ ICC_SmiQueuePut((void *)fpICCDevice);
+ }
+ }
+
+ USB_DEBUG(DEBUG_LEVEL_3, "Removal: fpDevInfo %X fpICCDevice %X\n", fpDevInfo, fpICCDevice);
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: ICCInsertEvent
+//
+// Description: In response to Device Insertion, Interrupt-in message is received.
+// Icc Device is added to the linked list and configured.
+//
+// Input:
+// DEV_INFO *fpDevInfo,
+// UINT8 Slot
+//
+// Output:
+// EFI_STATUS
+//
+// Notes: ConfigureCCID, GetICCDevice
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+ICCInsertEvent(
+ DEV_INFO *fpDevInfo,
+ UINT8 Slot
+)
+{
+
+ EFI_STATUS Status;
+ ICC_DEVICE *fpICCDevice;
+ BOOLEAN NewDeviceAdded = FALSE;
+
+ //
+ // Check if the device already exist. if so use it.
+ //
+ fpICCDevice = GetICCDevice(fpDevInfo, Slot);
+
+ if (!fpICCDevice) {
+ //
+ // Alocate memory for ICC_DEVICE and attach it to the linked list
+ //
+ fpICCDevice = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(ICC_DEVICE)));
+ ASSERT(fpICCDevice);
+ if (!fpICCDevice) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemFill((UINT8 *)fpICCDevice, sizeof(ICC_DEVICE), 0);
+
+ //
+ // Add to the slot list
+ //
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (fpDevInfo->ICCDeviceList.pHead != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pHead),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ if (fpDevInfo->ICCDeviceList.pTail != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pTail),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+#endif
+ DListAdd(&(fpDevInfo->ICCDeviceList), &(fpICCDevice->ICCDeviceLink));
+ NewDeviceAdded = TRUE;
+
+ }
+
+#if CCID_USE_INTERRUPT_INSERTION_REMOVAL
+ // Handle Multiple ICCInsertEvent calls. Some cards generate
+ // Interrupt in Interrupt-IN endpoint and some don't.
+ // For card which don't generate the intterupt, CCID API should be used to power up the device.
+ if (fpICCDevice->ConfiguredStatus) {
+
+ if (fpICCDevice->ConfiguredStatus == CONFIGFAILED) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+
+ }
+#endif
+
+ fpICCDevice->ChildHandle = 0;
+ fpICCDevice->Slot = Slot;
+ fpICCDevice->WaitTime = INITWAITTIME;
+
+ Status = ConfigureCCID(fpDevInfo, fpICCDevice);
+
+#if CCID_USE_INTERRUPT_INSERTION_REMOVAL
+ if(EFI_ERROR(Status)){
+
+ //
+ //Free up the memory and remove it from linked list
+ //
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (fpDevInfo->ICCDeviceList.pHead != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pHead),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ if (fpDevInfo->ICCDeviceList.pTail != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pTail),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+#endif
+ DListDelete (&(fpDevInfo->ICCDeviceList), &(fpICCDevice->ICCDeviceLink));
+ USB_MemFree(fpICCDevice, (UINT8)GET_MEM_BLK_COUNT(sizeof(ICC_DEVICE)));
+
+ } else {
+ USB_DEBUG(DEBUG_LEVEL_3, "ICC device added - Slot : %X\n", Slot);
+
+ if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) {
+ ICC_SmiQueuePut((void *)fpICCDevice);
+ }
+ }
+
+#else
+ //
+ // Even if configuration failed install the protocol in polling mode.
+ //
+ USB_DEBUG(DEBUG_LEVEL_3, "ICC device added - Slot : %X\n", Slot);
+
+ if ((gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) && NewDeviceAdded) {
+ ICC_SmiQueuePut((void *)fpICCDevice);
+ }
+#endif
+
+ USB_DEBUG(DEBUG_LEVEL_3, "Insert : fpDevInfo %X fpICCDevice %X\n", fpDevInfo, fpICCDevice);
+
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+//
+// Procedure: ICC_SmiQueuePut
+//
+// Description: Puts the pointer into the queue for processing.
+// updates queue head and tail. This data is read from EfiUSBCCID.C
+// which installs AMI_CCID_IO_PROTOCOL
+//
+// Input:
+// (void *)fpICCDevice
+//
+// Output:
+// None
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+ICC_SmiQueuePut(
+ VOID * d
+)
+{
+ QUEUE_T* q = &gUsbData->ICCQueueCnnctDisc;
+
+ while (q->head >= q->maxsize) {
+ q->head -= q->maxsize;
+ }
+
+ q->data[q->head++] = d;
+ if (q->head == q->maxsize) {
+ q->head -= q->maxsize;
+ }
+ if (q->head == q->tail) {
+ //Drop data from queue
+ q->tail++;
+ while (q->tail >= q->maxsize) {
+ q->tail -= q->maxsize;
+ }
+ }
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: DoDevInfoInitialization
+//
+// Description: Do some USB device info data initialization
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// UINT8 *fpDesc
+// UINT16 wStart
+// UINT16 wEnd
+//
+// Output:
+// EFI_STATUS
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+EFI_STATUS
+DoDevInfoInitialization (
+ DEV_INFO *fpDevInfo,
+ UINT8 *fpDesc,
+ UINT16 wStart,
+ UINT16 wEnd
+)
+{
+
+ UINT8 bTemp;
+ ENDP_DESC *fpEndpDesc;
+ INTRF_DESC *fpIntrfDesc;
+ SMARTCLASS_DESC *fpCCIDDesc = NULL;
+
+ fpDevInfo->bDeviceType = BIOS_DEV_TYPE_CCID;
+ fpDevInfo->fpPollTDPtr = 0;
+
+ fpDevInfo->bCallBackIndex = USB_InstallCallBackFunction(USBCCID_ProcessInterruptData);
+
+ //
+ // Initialize the Initlist to hold data for each Slot
+ //
+ DListInit(&(fpDevInfo->ICCDeviceList));
+ fpIntrfDesc = (INTRF_DESC*)(fpDesc + wStart);
+
+ //
+ // Calculate the end of descriptor block
+ //
+ fpDesc+=((CNFG_DESC*)fpDesc)->wTotalLength;
+ fpEndpDesc = (ENDP_DESC*)((char*)fpIntrfDesc + fpIntrfDesc->bDescLength);
+
+ do {
+ if (fpIntrfDesc->bDescType == DESC_TYPE_SMART_CARD) {
+ fpCCIDDesc = (SMARTCLASS_DESC *)fpIntrfDesc;
+ break;
+ }
+ fpIntrfDesc = (INTRF_DESC*) ((UINT8 *)fpIntrfDesc + fpIntrfDesc->bDescLength);
+ }while ((UINT8 *)fpIntrfDesc < fpDesc);
+
+ if (!fpCCIDDesc) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ fpDevInfo->pCCIDDescriptor = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(sizeof(SMARTCLASS_DESC)));
+ ASSERT(fpDevInfo->pCCIDDescriptor);
+ if (!fpDevInfo->pCCIDDescriptor) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ MemCopy((UINT8 *)fpCCIDDesc, (UINT8 *)(fpDevInfo->pCCIDDescriptor), sizeof(SMARTCLASS_DESC));
+ fpCCIDDesc = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+
+ if (fpCCIDDesc->bNumDataRatesSupported) {
+
+ fpDevInfo->DataRates = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(
+ fpCCIDDesc->bNumDataRatesSupported * sizeof(UINT32)));
+ ASSERT(fpDevInfo->DataRates);
+ if (!fpDevInfo->DataRates) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Issue GET_DATA_RATES cmd. Should interface number be zero?
+ //
+ USBCCIDIssueControlTransfer(fpDevInfo,
+ CCID_CLASS_SPECIFIC_GET_DATA_RATES,
+ 0x0, 0, (UINT8 *)fpDevInfo->DataRates,
+ fpCCIDDesc->bNumDataRatesSupported * sizeof(UINT32)
+ );
+
+ } else {
+ fpDevInfo->DataRates = 0;
+ }
+
+ if (fpCCIDDesc->bNumClockSupported) {
+
+ fpDevInfo->ClockFrequencies = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(
+ fpCCIDDesc->bNumClockSupported * sizeof(UINT32)));
+ ASSERT(fpDevInfo->ClockFrequencies);
+ if (!fpDevInfo->ClockFrequencies) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Issue GET_CLOCK_FREQUENCIES. Should interface number be zero?
+ //
+ USBCCIDIssueControlTransfer(fpDevInfo,
+ CCID_CLASS_SPECIFIC_GET_CLOCK_FREQUENCIES,
+ 0x0, 0, (UINT8 *)fpDevInfo->DataRates,
+ fpCCIDDesc->bNumClockSupported * sizeof(UINT32));
+ } else {
+ fpDevInfo->ClockFrequencies = 0;
+ }
+
+ PrintDescriptorInformation(fpDevInfo->pCCIDDescriptor);
+
+ bTemp = 0x03; // bit 1 = Bulk In, bit 0 = Bulk Out
+
+ for( ;(fpEndpDesc->bDescType != DESC_TYPE_INTERFACE) && ((UINT8*)fpEndpDesc < fpDesc);
+ fpEndpDesc = (ENDP_DESC*)((UINT8 *)fpEndpDesc + fpEndpDesc->bDescLength)){
+
+ if(!(fpEndpDesc->bDescLength)) {
+ // Br if 0 length desc (should never happen, but...)
+ break;
+ }
+
+ if( fpEndpDesc->bDescType != DESC_TYPE_ENDPOINT ) {
+ continue;
+ }
+
+ if ((fpEndpDesc->bEndpointFlags & EP_DESC_FLAG_TYPE_BITS) ==
+ EP_DESC_FLAG_TYPE_BULK) { // Bit 1-0: 10 = Endpoint does bulk transfers
+ if(!(fpEndpDesc->bEndpointAddr & EP_DESC_ADDR_DIR_BIT)) {
+ //
+ // Bit 7: Dir. of the endpoint: 1/0 = In/Out
+ // If Bulk-Out endpoint already found then skip subsequent ones
+ // on the interface.
+ //
+ if (bTemp & 1) {
+ fpDevInfo->bBulkOutEndpoint = (UINT8)(fpEndpDesc->bEndpointAddr
+ & EP_DESC_ADDR_EP_NUM);
+ fpDevInfo->wBulkOutMaxPkt = fpEndpDesc->wMaxPacketSize;
+ bTemp &= 0xFE;
+ }
+ } else {
+ //
+ // If Bulk-In endpoint already found then skip subsequent ones
+ // on the interface
+ //
+ if (bTemp & 2) {
+ fpDevInfo->bBulkInEndpoint = (UINT8)(fpEndpDesc->bEndpointAddr
+ & EP_DESC_ADDR_EP_NUM);
+ fpDevInfo->wBulkInMaxPkt = fpEndpDesc->wMaxPacketSize;
+ bTemp &= 0xFD;
+ }
+ }
+ }
+
+ //
+ // Check for and configure Interrupt endpoint if present
+ //
+ if ((fpEndpDesc->bEndpointFlags & EP_DESC_FLAG_TYPE_BITS) !=
+ EP_DESC_FLAG_TYPE_INT) { // Bit 1-0: 10 = Endpoint does interrupt transfers
+ continue;
+ }
+
+ if (fpEndpDesc->bEndpointAddr & EP_DESC_ADDR_DIR_BIT) {
+ fpDevInfo->IntInEndpoint = fpEndpDesc->bEndpointAddr;
+ fpDevInfo->IntInMaxPkt = fpEndpDesc->wMaxPacketSize;
+ fpDevInfo->bPollInterval = fpEndpDesc->bPollInterval;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: USBCCIDInitialize
+//
+// Description: This function initializes CCID device related data
+//
+// Input:
+// None
+//
+// Output:
+// None
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+USBCCIDInitialize ()
+{
+ USB_InstallCallBackFunction(USBCCID_ProcessInterruptData);
+ return;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDCheckForDevice
+//
+// Description: This routine checks for CCID type device from the
+// interface data provided
+//
+// Input:
+// DEV_INFO *fpDevInfo
+// UINT8 bBaseClass
+// UINT8 bSubClass
+// UINT8 bProtocol
+//
+// Output:
+// BIOS_DEV_TYPE_STORAGE type on success or 0FFH on error
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+USBCCIDCheckForDevice (
+ DEV_INFO *fpDevInfo,
+ UINT8 bBaseClass,
+ UINT8 bSubClass,
+ UINT8 bProtocol
+)
+{
+
+ if(bBaseClass == BASE_CLASS_CCID_STORAGE && bProtocol == PROTOCOL_CCID) {
+ return BIOS_DEV_TYPE_CCID;
+ }
+
+ return USB_ERROR;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDConfigureDevice
+//
+// Description: This function checks an interface descriptor of a device
+// to see if it describes a USB CCID device. If the device
+// is a CCID device, then it is configured
+// and initialized.
+//
+// Input:
+// pHCStruc HCStruc pointer
+// pDevInfo Device information structure pointer
+// pDesc Pointer to the descriptor structure
+// wEnd End offset of the device descriptor
+//
+// Output:
+// New device info structure, NULL on error
+//
+// Notes: DoDevInfoInitialization
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+DEV_INFO*
+USBCCIDConfigureDevice (
+ HC_STRUC *fpHCStruc,
+ DEV_INFO *fpDevInfo,
+ UINT8 *fpDesc,
+ UINT16 wStart,
+ UINT16 wEnd
+)
+{
+
+ EFI_STATUS Status;
+ INTRF_DESC *fpIntrfDesc = (INTRF_DESC*)(fpDesc + wStart);
+
+ USB_DEBUG (DEBUG_LEVEL_3, "USBCCIDConfigureDevice ....\n");
+
+ //
+ // Do some house keeping related DEV_INFO structure. No H/W access
+ //
+ Status = DoDevInfoInitialization(fpDevInfo, fpDesc, wStart, wEnd);
+
+ if (EFI_ERROR(Status)) {
+ return NULL;
+ }
+
+#if CCID_USE_INTERRUPT_INSERTION_REMOVAL
+ //
+ // if Interrupt EndPoint is supported
+ //
+ if (fpIntrfDesc->bNumEndpoints == 3) {
+ fpDevInfo->PollingLength = fpDevInfo->IntInMaxPkt;
+ (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDActivatePolling)
+ (fpHCStruc, fpDevInfo);
+ }
+
+#else
+
+ Status = ICCInsertEvent(fpDevInfo, 0);
+
+#endif
+
+ //
+ // Should we support CCID which doesn't support interrupt-IN Message.
+ // Maybe not for now.
+ //
+ return fpDevInfo;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: USBCCIDDisconnectDevice
+//
+// Description: This function disconnects the CCID device.
+//
+// Input:
+// pDevInfo Device info structure pointer
+//
+// Output:
+// None
+//
+//Notes: Free up all memory allocated to the device.
+// Remove ICC device from the device list.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+USBCCIDDisconnectDevice (
+ DEV_INFO *fpDevInfo
+)
+{
+
+ ICC_DEVICE *fpICCDevice;
+ DLINK *dlink = fpDevInfo->ICCDeviceList.pHead;
+ HC_STRUC *fpHCStruc = gUsbData->HcTable[fpDevInfo->bHCNumber - 1];
+ SMARTCLASS_DESC *CCIDDescriptor = (SMARTCLASS_DESC*)fpDevInfo->pCCIDDescriptor;
+ UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12);
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ if (((UINT8*)fpDevInfo->pCCIDDescriptor < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)fpDevInfo->pCCIDDescriptor > MemBlockEnd)) {
+ return USB_ERROR;
+ }
+
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (dlink != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)dlink,
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return USB_ERROR;
+ }
+ }
+#endif
+
+#if CCID_USE_INTERRUPT_INSERTION_REMOVAL
+ // Stop polling the endpoint
+ (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDeactivatePolling)(fpHCStruc,fpDevInfo);
+ fpDevInfo->IntInEndpoint = 0;
+
+#endif
+
+ //
+ // Free up all the memory allocated for each ICC device
+ //
+ while (dlink) {
+ fpICCDevice = OUTTER(dlink, ICCDeviceLink, ICC_DEVICE);
+ if (((UINT8*)fpICCDevice < gUsbData->fpMemBlockStart) ||
+ ((UINT8*)((UINTN)fpICCDevice + sizeof(ICC_DEVICE)) > MemBlockEnd)) {
+ return USB_ERROR;
+ }
+ USB_MemFree(fpICCDevice, (UINT8)GET_MEM_BLK_COUNT(sizeof(ICC_DEVICE)));
+#if USB_RUNTIME_DRIVER_IN_SMM
+ if (fpDevInfo->ICCDeviceList.pHead != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pHead),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return USB_ERROR;
+ }
+ }
+ if (fpDevInfo->ICCDeviceList.pTail != NULL) {
+ Status = AmiValidateMemoryBuffer((VOID*)(fpDevInfo->ICCDeviceList.pTail),
+ (UINT32)sizeof(DLINK));
+ if (EFI_ERROR(Status)) {
+ return USB_ERROR;
+ }
+ }
+#endif
+ DListDelete (&(fpDevInfo->ICCDeviceList), &(fpICCDevice->ICCDeviceLink));
+ if (!dlink->pNext) break;
+ dlink = dlink->pNext;
+ }
+
+ if (fpDevInfo->DataRates) {
+ USB_MemFree(fpDevInfo->DataRates,
+ (UINT8)GET_MEM_BLK_COUNT(CCIDDescriptor->bNumDataRatesSupported * sizeof(UINT32))
+ );
+ }
+
+ if (fpDevInfo->ClockFrequencies) {
+ USB_MemFree(fpDevInfo->ClockFrequencies,
+ (UINT8)GET_MEM_BLK_COUNT(CCIDDescriptor->bNumClockSupported * sizeof(UINT32))
+ );
+ }
+
+ //
+ // Free up all the memory allocated for CCID Descriptor
+ //
+ USB_MemFree(CCIDDescriptor,
+ (UINT8)GET_MEM_BLK_COUNT(sizeof(SMARTCLASS_DESC))
+ );
+
+ fpDevInfo->pCCIDDescriptor = 0;
+
+ return USB_SUCCESS;
+}
+
+//****************************************************************************
+//****************************************************************************
+//** **
+//** (C)Copyright 1985-2016, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Norcross, GA 30093 **
+//** **
+//** Phone (770)-246-8600 **
+//** **
+//****************************************************************************
+//****************************************************************************