diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/usb/rt | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/EM/usb/rt')
31 files changed, 55341 insertions, 0 deletions
diff --git a/Core/EM/usb/rt/UsbMass.h b/Core/EM/usb/rt/UsbMass.h new file mode 100644 index 0000000..5fb4e9f --- /dev/null +++ b/Core/EM/usb/rt/UsbMass.h @@ -0,0 +1,465 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/UsbMass.h 3 7/04/14 5:34a Wilsonlee $ +// +// $Revision: 3 $ +// +// $Date: 7/04/14 5:34a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/UsbMass.h $ +// +// 3 7/04/14 5:34a Wilsonlee +// [TAG] EIP175485 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB key can't be save during secure boot key. +// [RootCause] The usb key, MSI 8G Team, has two luns. One is CD-ROM, it +// always reports there is no media until we send "Get_Configuration" +// command to it, then it causes the other lun will report media change +// when we read/write data later. +// [Solution] Send "Get_Configuration" command for CD/DVD devices. +// [Files] usbmass.c, UsbMass.h +// +// 2 12/15/13 10:16p Wilsonlee +// [TAG] EIP136594 +// [Category] New Feature +// [Description] Support 64 bits LBA of usb mass storages. +// [Files] Bfiusb.asm, Bfiusb.equ, UsbInt13.c, UsbInt13.h, amiusb.c, +// usbdef.h, usbmass.c, UsbMass.h, efiusbmass.c, UI13.bin +// +// 1 1/22/13 3:08a Wilsonlee +// [TAG] EIP112938 +// [Category] Improvement +// [Description] Create a header file for usb mass storage driver. +// [Files] UsbMass.h, usbmass.c, usbdef.h, amiusb.c, efiusbmass.c +// +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: UsbMass.h +// +// Description: AMI USB Mass Storage support header +// +//<AMI_FHDR_END> +//********************************************************************** +#ifndef __USBMASS__H__ +#define __USBMASS__H__ +#ifdef __cplusplus +extern "C" { +#endif + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: BOT_STATUS_BLOCK +// +// Description: USB mass device boot only protocol status block structure. +// Referred as CSW - Command status wrapper. Refer Bulk-Only +// transport specification for more detail. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// dCswSignature DWORD CBS signature "USBS" +// dCswTag DWORD Tag used to link the command with status response +// dCswDataResidue DWORD Size of remaining data that is not processed in this transfer +// bmCswStatus BYTE CSW status byte +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +#pragma pack(push, 1) + +typedef struct { + UINT32 dCswSignature; // 0-3h, CSW signature = "USBS" + UINT32 dCswTag; // 4-7h, Tag + UINT32 dCswDataResidue; // 8-0Bh, Data residue + UINT8 bmCswStatus; // 0Ch, CSW status +} BOT_STATUS_BLOCK; + +#pragma pack(pop) + +// Common device specific command structures and values +//---------------------------------------------------------------------------- +#define COMMON_INQUIRY_OPCODE 0x12 +#define COMMON_READ_CAPACITY_10_OPCODE 0x25 +#define COMMON_READ_CAPACITY_16_OPCODE 0x9E +#define COMMON_READ_10_OPCODE 0x28 +#define COMMON_READ_16_OPCODE 0x88 +#define COMMON_WRITE_10_OPCODE 0x2A +#define COMMON_WRITE_16_OPCODE 0x8A +#define COMMON_MODE_SENSE_6_OPCODE 0x1A +#define COMMON_MODE_SENSE_10_OPCODE 0x5A +#define COMMON_SEND_DIAGNOSTIC_OPCODE 0x1D +#define COMMON_TEST_UNIT_READY_OPCODE 0x00 +#define COMMON_REQUEST_SENSE_OPCODE 0x03 +#define COMMON_START_STOP_UNIT_OPCODE 0x1B +#define COMMON_FORMAT_UNIT_OPCODE 0x04 +#define COMMON_VERIFY_10_OPCODE 0x2F +#define COMMON_VERIFY_16_OPCODE 0x8F +#define COMMON_READ_FORMAT_CAPACITY_OPCODE 0x23 +#define COMMON_GET_CONFIGURATION_OPCODE 0x46 + +#pragma pack(push, 1) + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 bPageCode; // 02h, Page Code + UINT8 bReserved; // 03h, Reserved + UINT8 bAllocLength; // 04h, Allocation Length + UINT8 bControl; // 05h, Control/Reserved + UINT8 aReserved[6]; // 06h-0Bh, Reserved +} COMMON_INQ_CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT32 dLba; // 02h-05h, Logical Block Address + UINT16 wbReserved; // 06h-07, Reserved + UINT8 bPMI; // 08h, PMI - bit 0 + UINT8 bControl; // 09h, Control/Reserved + UINT16 wdReserved; // 0Ah-0Bh, Reserved +} COMN_READ_CAPACITY_10_CMD; + +typedef struct { + UINT8 OpCode; // 00h, Operation Code + UINT8 ServiceAction; // 01h, Service Action - bit0..bit4 + UINT64 Lba; // 02h-09h, Logical Block Address + UINT32 AllocLength; // 10h-0Dh, Allocation Length + UINT8 PMI; // 0Eh, PMI - bit 0 + UINT8 Control; // 0Fh, Control +} COMN_READ_CAPACITY_16_CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 aReserved[5]; // 02-06h, Reserved + UINT16 wAllocLength; // 07h-08h, Allocation Length(BIG ENDIAN) + UINT8 aReserved1[3]; // 09h-0Bh, Reserved +} COMN_READ_FMT_CAPACITY; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT32 dLba; // 02h-05h, Logical Block Address + UINT8 bReserved; // 06h, Reserved + UINT16 wTransferLength;// 07h-08h, Transfer Length(BIG ENDIAN) + UINT8 bControl; // 09h, Control/Reserved + UINT16 wReserved; // 0Ah-0Bh, Reserved +} COMN_RWV_10_CMD; + +typedef struct { + UINT8 OpCode; // 00h, Operation Code + UINT8 Lun; // 01h, Logical Unit Number, etc + UINT64 Lba; // 02h-09h, Logical Block Address + UINT32 TransferLength; // 0Ah-0Dh, Transfer Length(BIG ENDIAN) + UINT8 GroupNum; // 0Eh, Group Number, etc + UINT8 Control; // 0Fh, Control +} COMN_RWV_16_CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 bPageCode; // 02h, Page Code + UINT8 bReserved; // 03h, Reserved + UINT8 bAllocLength; // 04h, Allocation Length + UINT8 bControl; // 05h, Control/Reserved +} COMN_MODE_SENSE_6CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 bPageCode; // 02h, Page Code + UINT32 dReserved; // 03-06h, Reserved + UINT16 wAllocLength; // 07h-08h, Allocation Length(BIG ENDIAN) + UINT8 bControl; // 09h, Control/Reserved + UINT16 wReserved; // 0Ah-0Bh, Reserved +} COMN_MODE_SENSE_10CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code (1D) + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 bReserved[10]; // 02h-0Bh, Reserved +} COMN_SEND_DIAG_CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number + UINT8 bReserved[10]; // 02h-0Bh, Reserved +} COMN_TEST_UNIT_READY_CMD; + +typedef struct { + UINT8 bOpCode; //00h, Operation Code + UINT8 bLun; //01h, Logical Unit Number + UINT16 wReserved; //02-03h, Reserved + UINT8 bAllocLength; //04h, Allocation Length + UINT8 aReserved[7]; //05h-0Bh, Reserved +} COMMON_REQ_SENSE_CMD; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT16 wReserved; // 02-03h, Reserved + UINT8 bStart; // 04h, LoEj, Start bits + UINT8 aReserved[7]; // 05h-0Bh, Reserved +} COMMON_START_STOP_UNIT_CMD; + +typedef struct { + UINT8 OpCode; // 00h, Operation Code + UINT8 Rt; // 01h, Logical Unit Number, etc + UINT16 StartingFeatureNumber; // 02h, StartingFeatureNumber + UINT8 Reserved[3]; // 03-06h, Reserved + UINT16 AllocLength; // 07h, Allocation Length + UINT8 Control; // 09h, Control +} COMMON_GET_CONFIGURATION; + +typedef struct { + UINT8 bOpCode; // 00h, Operation Code + UINT8 bLun; // 01h, Logical Unit Number, etc + UINT8 bTrackNumber; // 02h, Track Number + UINT16 wInterleave; // 03h-04h, Interleave (BIG ENDIAN) + UINT16 wReserved; // 05-06h, Reserved + UINT16 wParamLength; // 07h-08h, Parameter List Length(BIG ENDIAN) + UINT8 aReserved[3]; // 09h-0Bh, Reserved +} UFI_FMT_UNIT_CMD; + +typedef struct { + UINT16 wLength; + UINT8 bMediaType; + UINT8 aReserved[3]; + UINT16 wBlkDescSize; +} MODE_SENSE_10_HEADER; + +typedef struct { + UINT32 dCbwSignature; // 0-3h, CBW signature = "USBC" + UINT32 dCbwTag; // 4-7h, Tag + UINT32 dCbwDataLength; // 8-0Bh, Data transfer length + UINT8 bmCbwFlags; // 0Ch, Flags + UINT8 bCbwLun; // 0Dh, Logical unit number + UINT8 bCbwLength; // 0Eh, Command block length + UINT8 aCBWCB[16]; // 0Fh-1Eh, Command block buffer +} BOT_CMD_BLK; + +typedef struct { + UINT8 bPageCode; + UINT8 bPageSize; + UINT16 wXferRate; + UINT8 bHeads; + UINT8 bSectors; + UINT16 wBlockSize; + UINT16 wCylinders; + UINT8 aReserved[22]; +} PAGE_CODE_5; + +typedef struct { + UINT8 aReserved[3]; + UINT8 bCapListLength; // Amount of capacity format data after the header +} READ_FMT_CAP_HDR; + +typedef struct { + READ_FMT_CAP_HDR stCapHeader; + UINT32 dNumBlocks; + UINT8 bDescCode; + UINT8 bReserved; + UINT16 wBlockSize; +}READ_FMT_CAPACITY; + +#pragma pack(pop) + +#define MODE_SENSE_COMMAND_EXECUTED BIT0 +#define READ_CAPACITY_COMMAND_EXECUTED BIT1 + +//---------------------------------------------------------------------------- +// Physical Device Type Constants for BIOS internal use +//---------------------------------------------------------------------------- +#define USB_MASS_DEV_TYPE_FLOPPY 1 // USB FD drive +#define USB_MASS_DEV_TYPE_CDROM 2 // USB CDROM drive +#define USB_MASS_DEV_TYPE_ZIP 3 // USB ZIP drive +#define USB_MASS_DEV_TYPE_ZIP_FLOPPY 4 // USB ZIP drive as floppy emulated +#define USB_MASS_DEV_TYPE_SUPER_DISK 5 // USB super disk (LS120/240) +#define USB_MASS_DEV_TYPE_HARD_DISK 6 // USB HD drive +#define USB_MASS_DEV_TYPE_DISKONKEY 7 // USB Disk On Key + +//---------------------------------------------------------------------------- +// USB Mass Storage Related Data Structures and Equates +//---------------------------------------------------------------------------- +//#define MAX_SIZE_FOR_FLOPPY_EMULATION 530 // 530MB //(EIP80382-) +//#define MAX_LBA_FOR_FLOPPY_EMULATION 0x109000 // 530MB //(EIP80382-) + +// LBA to CHS conversion parameters +#define USB_FIXED_LBA_HPT_ABOVE_1GB 0xFF +#define USB_FIXED_LBA_SPT_ABOVE_1GB 0x3F +#define USB_FIXED_LBA_HPT_BELOW_1GB 0x40 +#define USB_FIXED_LBA_SPT_BELOW_1GB 0x20 + +// Parameters regarding 1.44MB FDD +#define USB_144MB_FDD_MAX_LBA 0xB40 +#define USB_144MB_FDD_MEDIA_TYPE 0x94 +#define USB_144MB_FDD_MAX_HEADS 0x02 +#define USB_144MB_FDD_MAX_SECTORS 0x12 +#define USB_144MB_FDD_MAX_CYLINDERS 0x50 +#define USB_144MB_FDD_MAX_BLOCK_SIZE 0x200 + +// Parameters regarding 720KB FDD +#define USB_720KB_FDD_MAX_LBA 0x5A0 +#define USB_720KB_FDD_MEDIA_TYPE 0x1E +#define USB_720KB_FDD_MAX_HEADS 0x02 +#define USB_720KB_FDD_MAX_SECTORS 0x09 +#define USB_720KB_FDD_MAX_CYLINDERS 0x50 +#define USB_720KB_FDD_MAX_BLOCK_SIZE 0x200 + +#define USB_UNKNOWN_MEDIA_TYPE 0x0F0 + +//----------------------------------------------- +// ATAPI ERROR CODE REPORTED TO CALLER +//----------------------------------------------- +#define USB_ATA_WRITE_PROTECT_ERR 0x003 // Write protect error +#define USB_ATA_TIME_OUT_ERR 0x080 // Command timed out error +#define USB_ATA_DRIVE_NOT_READY_ERR 0x0AA // Drive not ready error +#define USB_ATA_DATA_CORRECTED_ERR 0x011 // Data corrected error +#define USB_ATA_PARAMETER_FAILED 0x007 // Bad parameter error +#define USB_ATA_MARK_NOT_FOUND_ERR 0x002 // Address mark not found error +#define USB_ATA_NO_MEDIA_ERR 0x031 // No media in drive +#define USB_ATA_READ_ERR 0x004 // Read error +#define USB_ATA_UNCORRECTABLE_ERR 0x010 // Uncorrectable data error +#define USB_ATA_BAD_SECTOR_ERR 0x00A // Bad sector error +#define USB_ATA_GENERAL_FAILURE 0x020 // Controller general failure + +#define atapi_cntlr_not_ready_err 0x080 // ATAPI controller not ready/media not present +#define atapi_check_condition_err 0x0fd // check condition reported by ATAPI controller +#define atapi_resend_err 0x0fe // resend the command to ATAPI controller +#define atapi_media_change_err 0x006 // ATAPI media change error +#define atapi_reset_err 0x005 // ATAPI reset error +#define atapi_invalid_func 0x001 // ATAPI invalid function + +#define atapi_volume_not_locked_err 0x0B0 // volume not locked in drive +#define atapi_volume_locked_err 0x0B1 // volume locked in drive +#define atapi_volume_not_removable_err 0x0B2 // volume not removable +#define atapi_volume_in_use_err 0x0B3 // volume in use +#define atapi_lock_count_exceeded_err 0x0B4 // lock count exceeded +#define atapi_eject_request_failed_err 0x0B5 // valid eject request failed + +#define atapi_sense_failed 0x0ff // Sense key command failed + +//----------------------------------------------------------------------- +// Bulk-Only Mass Storage Reset (Class Specific Request) +//----------------------------------------------------------------------- +#define BOT_RESET_REQUEST_CODE 0x0FF // Reset Request code + +//----------------------------------------------------------------------- +// Bulk-Only Get Max Lun (Class Specific Request) +//----------------------------------------------------------------------- +#define BOT_GET_MAX_LUN_REQUEST_CODE 0x0FE // Get Max Lun Request code + +//----------------------------------------------------------------------- +// USB Command Status Wrapper Structure +//----------------------------------------------------------------------- +#define BOT_CSW_SIGNATURE 0x53425355 // 0-3h, signature = "USBS" + +//----------------------------------------------------------------------- +// USB Command Block Wrapper Structure +//----------------------------------------------------------------------- +#define BOT_CBW_SIGNATURE 0x43425355 // 0-3h, signature = "USBC" + +#pragma pack(push, 1) + +typedef struct { + UINT8 BootIndicator; + UINT8 StartHead; + UINT8 StartSector; + UINT8 StartTrack; + UINT8 OSType; + UINT8 EndHead; + UINT8 EndSector; + UINT8 EndTrack; + UINT32 StartingLba; + UINT32 SizeInLba; +} MBR_PARTITION; + +typedef struct { + UINT8 BootCode[440]; + UINT32 UniqueMbrSig; + UINT16 Unknown; + MBR_PARTITION PartRec[4]; + UINT16 Sig; +} MASTER_BOOT_RECORD; + +typedef struct { + UINT8 jmp[3]; //0x0 + CHAR8 OEMName[8]; //0x3 + UINT16 BytsPerSec; //0xB + UINT8 SecPerClus; //0xD + UINT16 RsvdSecCnt; //0xE + UINT8 NumFATs; //0x10 + UINT16 RootEntCnt; //0x11 + UINT16 TotSec16; //0x13 + UINT8 Media; //0x15 + UINT16 FATSz16; //0x16 + UINT16 SecPerTrk; //0x18 + UINT16 NumHeads; //0x1A + UINT32 HiddSec; //0x1C + UINT32 TotSec32; //0x20 + union { + struct { + UINT8 DrvNum; //0x24 + UINT8 Reserved1; //0x25 + UINT8 BootSig; //0x26 + UINT32 VolID; //0x27 + CHAR8 VolLab[11]; //0x2B + CHAR8 FilSysType[8]; //0x36 + UINT8 Padding[510 - 0x3E]; //0x3E + } Fat16; + struct { + UINT32 FATSz32; //0x24 + UINT16 ExtFlags; //0x28 + UINT16 FSVer; //0x2A + UINT32 RootClus; //0x2C + UINT16 FSInfo; //0x30 + UINT16 BkBootSec; //0x32 + UINT8 Reserved[12]; //0x34 + UINT8 DrvNum; //0x40 + UINT8 Reserved1; //0x41 + UINT8 BootSig; //0x42 + UINT32 VolID; //0x43 + CHAR8 VolLab[11]; //0x47 + CHAR8 FilSysType[8]; //0x52 + UINT8 Padding2[510 - 0x5A]; //0x5A + } Fat32; + } Fat; + UINT16 Signature; +} BOOT_SECTOR; + +#pragma pack(pop) + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif +#endif +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2013, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/usb/rt/amidef.h b/Core/EM/usb/rt/amidef.h new file mode 100644 index 0000000..a679e7b --- /dev/null +++ b/Core/EM/usb/rt/amidef.h @@ -0,0 +1,503 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/amidef.h 40 10/28/16 3:57a Wilsonlee $ +// +// $Revision: 40 $ +// +// $Date: 10/28/16 3:57a $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/rt/amidef.h $ +// +// 40 10/28/16 3:57a Wilsonlee +// [TAG] EIP300142 +// [Category] Improvement +// [Description] Remove USB Int1C module part because we use the other +// method to service xhci. +// [Files] usbport.c, amidef.h, amiusbhc.c, UsbLegacy.cif +// +// 39 10/28/16 1:29a Wilsonlee +// [TAG] EIP300142 +// [Category] Improvement +// [Description] Get vector value from memory 0x1c directly and check +// it's not zero. +// [Files] usbport.c, amidef.h +// +// 38 12/16/13 1:41a Ryanchou +// [TAG] EIP142509 +// [Category] Improvement +// [Description] Added usage 0x87 and 0x89. +// [Files] efiusbkb.c, efiusbkb.h. amidef.h +// +// 37 5/22/12 10:03a Ryanchou +// [TAG] EIP90154 +// [Category] Improvement +// [Description] Remove the USBSB_EnableSmmPeriodicSmi and +// USBSB_DisableSmmPeriodicSmi hooks. +// [Files] amidef.h, amiusb.c, usb.c, usbsb.c +// +// 36 5/04/12 5:20a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 35 11/08/11 2:01a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 34 4/06/11 3:26a Ryanchou +// [TAG] EIP55275 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] EBDA:108 conflict +// [RootCause] The EIP48064 save EFI_USB_PROTOCOL pointer in EBDA:108, +// but Keymon filter driver used the same location. +// [Solution] Use the EBDA:32 to save EFI_USB_PROTOCOL pointer and add a +// signature in EFI_USB_PROTOCOL. +// [Files] amidef.h, AmiUsbController.h, uhcd.c, usbsb.c +// +// 33 11/22/10 8:44a Ryanchou +// [TAG] EIP48064 +// [Category] Improvement +// [Description] The SB template implemented elink +// AcpiEnableCallbackList, the XHCI/EHCI hand off function should be +// invoked via the elink AcpiEnableCallbackList. +// [Files] amidef.h, amiusb.c, amiusb.dxs, amiusb.h, +// AmiUsbController.h, usb.sdl, usbrt.mak, usbsb.c +// +// 32 10/07/10 10:14a Ryanchou +// EIP41379: Move the code that install xHCI hardware SMI handler in +// XHCI_Start function. +// +// 31 3/25/10 9:47a Olegi +// +// 30 3/19/10 10:06a Olegi +// +// 29 11/30/09 6:11p Olegi +// +// 28 11/30/09 9:08a Olegi +// +// 27 10/02/09 10:50a Olegi +// Code cleanup. +// +// 26 10/03/08 3:33p Olegi +// +// 25 9/05/08 3:45p Olegi +// Definitions related to USB SMI code isolation. +// +// 24 5/16/08 12:03p Olegi +// Compliance with AMI coding standard. +// +// 23 7/13/07 11:42a Olegi +// F11 and F12 codes added. +// +// 22 3/20/07 1:26p Olegi +// +// 21 3/07/07 5:59p Olegi +// +// 20 10/25/06 10:59a Olegi +// +// 19 10/12/06 9:11p Andriyn +// +// 18 10/12/06 5:17p Olegi +// +// 17 10/12/06 5:01p Felixp +// EfiCreateEventLegacyBoot added +// +// 16 10/12/06 4:42p Olegi +// +// 15 5/31/06 6:56p Mirk +// Core 4.5 compliant - DP Length manipulation changes. +// +// 14 5/03/06 10:00a Olegi +// +// 13 4/14/06 6:43p Olegi +// Conversion to be able to use x64 compiler. +// +// 10 1/11/06 1:42p Olegi +// +// 9 11/10/05 11:11a Olegi +// +// 8 8/26/05 12:25p Andriyn +// +// 7 8/15/05 3:59p Olegi +// +// 6 8/05/05 3:38p Andriyn +// Complience with EFI EDK +// +// 5 6/03/05 6:32p Andriyn +// Redifinition of library function for source complience with Aptio +// +// 4 5/20/05 11:05a Andriyn +// reconcile Aptio changes with Alaska +// +// 3 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 2 5/10/05 4:13p Andriyn +// USBBUS implementation +// +// 1 3/29/05 10:40a Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//********************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: AmiDef.h +// +// Description: AMI USB driver definitions, framework specific +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// Avoid including multiple instance of this file + +#ifndef __AMI_H +#define __AMI_H + +#include "token.h" + +#define USB_DRIVER_VERSION (USB_DRIVER_MAJOR_VER << 4) + USB_DRIVER_MINOR_VER + +#include "Efi.h" +#include <AmiDxeLib.h> +#define _FAR_ + +// Basic type definitions of various size + +#if (__STDC_VERSION__ < 199901L ) + + /* No ANSI C 1999/2000 stdint.h integer width declarations */ + + #if _MSC_EXTENSIONS + + /* Use Microsoft C compiler integer width declarations */ +#if _64_BIT_EXTENSIONS + typedef unsigned __int64 UINT64; + typedef __int64 INT64; +typedef UINT64 QWORD; +typedef QWORD * PQWORD; +typedef QWORD _FAR_ * FPQWORD; +typedef UINT64 * PUINT64; +typedef INT64 * PINT64; +typedef UINT64 _FAR_ * FPUINT64; +typedef INT64 _FAR_ * FPINT64; +#endif +// typedef unsigned __int32 UINT32; +// typedef __int32 INT32; +// typedef unsigned __int16 UINT16; +// typedef __int16 INT16; +// typedef unsigned __int8 UINT8; +// typedef __int8 INT8; + #else +#if _64_BIT_EXTENSIONS +#endif + #endif +#endif + +// Return code definition +typedef INT16 RETCODE; + +// 64-bit extenstion definition +#if _64_BIT_EXTENSIONS +#endif + +#ifndef NULL +#define NULL 0 +#endif + +// Private and public definitions +#define PRIVATE static +#define PUBLIC + +// Function IN/OUT definitions +#define IN +#define OUT +#define IN_OUT + +// Return codes +#define SUCCESS 0 +#define FAILURE -1 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif +// Bit equates +#define BIT0 0x01 +#define BIT1 0x02 +#define BIT2 0x04 +#define BIT3 0x08 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 +#define BIT8 0x100 +#define BIT9 0x200 +/* defined in AmiDxeLib +#define BIT10 0x400 +#define BIT11 0x800 +#define BIT12 0x1000 +#define BIT13 0x2000 +#define BIT14 0x4000 +#define BIT15 0x8000 +#define BIT16 0x10000 +#define BIT17 0x20000 +#define BIT18 0x40000 +#define BIT19 0x80000 +#define BIT20 0x100000 +#define BIT21 0x200000 +#define BIT22 0x400000 +#define BIT23 0x800000 +#define BIT24 0x1000000 +#define BIT25 0x2000000 +#define BIT26 0x4000000 +#define BIT27 0x8000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 +*/ +#define SCAN_NULL EFI_SCAN_NULL +#define SCAN_ESC EFI_SCAN_ESC +#define SCAN_F1 EFI_SCAN_F1 +#define SCAN_F2 EFI_SCAN_F2 +#define SCAN_F3 EFI_SCAN_F3 +#define SCAN_F4 EFI_SCAN_F4 +#define SCAN_F5 EFI_SCAN_F5 +#define SCAN_F6 EFI_SCAN_F6 +#define SCAN_F7 EFI_SCAN_F7 +#define SCAN_F8 EFI_SCAN_F8 +#define SCAN_F9 EFI_SCAN_F9 +#define SCAN_F10 EFI_SCAN_F10 +#define SCAN_F11 EFI_SCAN_F11 +#define SCAN_F12 EFI_SCAN_F12 +#define SCAN_INSERT EFI_SCAN_INS +#define SCAN_HOME EFI_SCAN_HOME +#define SCAN_PAGE_UP EFI_SCAN_PGUP +#define SCAN_DELETE EFI_SCAN_DEL +#define SCAN_END EFI_SCAN_END +#define SCAN_PAGE_DOWN EFI_SCAN_PGDN +#define SCAN_RIGHT EFI_SCAN_RIGHT +#define SCAN_LEFT EFI_SCAN_LEFT +#define SCAN_DOWN EFI_SCAN_DN +#define SCAN_UP EFI_SCAN_UP + +#ifndef SCAN_PAUSE +#define SCAN_PAUSE 0x0048 +#define SCAN_F13 0x0068 +#define SCAN_F14 0x0069 +#define SCAN_F15 0x006A +#define SCAN_F16 0x006B +#define SCAN_F17 0x006C +#define SCAN_F18 0x006D +#define SCAN_F19 0x006E +#define SCAN_F20 0x006F +#define SCAN_F21 0x0070 +#define SCAN_F22 0x0071 +#define SCAN_F23 0x0072 +#define SCAN_F24 0x0073 +#define SCAN_MUTE 0x007F +#define SCAN_VOLUME_UP 0x0080 +#define SCAN_VOLUME_DOWN 0x0081 +#define SCAN_BRIGHTNESS_UP 0x0100 +#define SCAN_BRIGHTNESS_DOWN 0x0101 +#define SCAN_SUSPEND 0x0102 +#define SCAN_HIBERNATE 0x0103 +#define SCAN_TOGGLE_DISPLAY 0x0104 +#define SCAN_RECOVERY 0x0105 +#define SCAN_EJECT 0x0106 +#endif + +#define EFI_BLOCK_IO_PROTOCOL EFI_BLOCK_IO +#define EFI_SIMPLE_TEXT_IN_PROTOCOL SIMPLE_INPUT_INTERFACE + +//#define MESSAGING_DEVICE_PATH MESSAGING_DEVICE_PATH_TYPE +//#define MSG_USB_CLASS_DP MSG_USB_CLASS_DEVICE_PATH_SUBTYPE +#define EFI_END_ENTIRE_DEVICE_PATH END_DEVICE_PATH +#define EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE END_ENTIRE_SUBTYPE +//#define MSG_SCSI_DP MSG_SCSI_DEVICE_PATH_SUBTYPE +//#define Pun TargetId + +#define EFI_DRIVER_ENTRY_POINT(x) +//#define EFI_LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE +#define EfiInitializeSmmDriverLib(ImageHandle, SystemTable) InitAmiLib(ImageHandle, SystemTable) +#define EfiInitializeDriverLib(ImageHandle, SystemTable) InitAmiLib(ImageHandle,SystemTable) +#define gBS pBS +#define gRT pRS +#define EfiDuplicateDevicePath DPCopy + + +// Loop forever macro +#define LOOP_FOREVER while(1) + +#if defined(DEBUG_SWITCH) && (DEBUG_SWITCH == 1) +#define EfiDebugVPrint(EFI_D_ERROR, Message, ArgList) PrintDebugMessageVaList(-1, Message, ArgList) + +extern RETCODE PrintDebugMsg (int, char *, ...); +#define USB_DEBUG PrintDebugMsg +#define USB_DEBUG_LEVEL DEBUG_LEVEL_3 +void DEBUG_DELAY(); +#else +extern RETCODE PrintDebugMsg (int, char *, ...); +#define USB_DEBUG 1?0:PrintDebugMsg +#define DEBUG_DELAY +#endif + +#if GENERIC_USB_CABLE_SUPPORT +#undef USB_DEBUG +#define USB_DEBUG +#endif + +#define MAX_DEBUG_LEVEL 8 + +#define DEBUG_LEVEL_8 8 +#define DEBUG_LEVEL_7 7 +#define DEBUG_LEVEL_6 6 +#define DEBUG_LEVEL_5 5 +#define DEBUG_LEVEL_4 4 +#define DEBUG_LEVEL_3 3 +#define DEBUG_LEVEL_2 2 +#define DEBUG_LEVEL_1 1 +#define DEBUG_LEVEL_0 0 + +#define MICROSECOND 10 +#define MILLISECOND (1000 * MICROSECOND) +#define ONESECOND (1000 * MILLISECOND) + +#define USB_DATA_EBDA_OFFSET 0x104 +#define USB_PROTOCOL_EBDA_OFFSET 0x32 //(EIP55275) + +#define GET_CPUSAVESTATE_REG(x) (URP_STRUC*)(UINTN)gSmst->CpuSaveState->Ia32SaveState.x +//#define GET_FV_NAME(pImage) &((FV_FILE_PATH_DEVICE_PATH*)(pImage->FilePath))->Name +#define GET_FV_NAME(pImage) &((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH*)(pImage->FilePath))->NameGuid +#define EfiDevicePathNodeLength(a) (((a)->Length[0]) | ((a)->Length[1] << 8)) +//#define EfiNextDevicePathNode(a) ((EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *) (a)) + \ +// EfiDevicePathNodeLength(a))) +#define EfiNextDevicePathNode(a) NEXT_NODE(a) + +#define EfiDevicePathType(a) ( ((a)->Type) & 0x7f ) +#define EfiIsDevicePathEndType(a) (EfiDevicePathType(a) == 0x7f) + + +#define EfiIsDevicePathEndSubType(a) ((a)->SubType == 0xFF) +#define EfiIsDevicePathEndInstanceSubType(a) ((a)->SubType == 1) + +#define EfiIsDevicePathEnd(a) ( EfiIsDevicePathEndType(a) && \ + EfiIsDevicePathEndSubType(a) ) +#define EfiIsDevicePathEndInstance(a) ( EfiIsDevicePathEndType(a) && \ + EfiIsDevicePathEndInstanceSubType(a) ) +//#define SetDevicePathNodeLength(a,l) { (a)->Length = (l); } +#define SetDevicePathNodeLength(a,l) ( SET_NODE_LENGTH(a,l) ) +//#define DevicePathNodeLength(a) ( ((a)->Length[0]) | ((a)->Length[1] << 8) ) +#define DevicePathNodeLength(a) ( NODE_LENGTH(a) ) +//#define NextDevicePathNode(a) ( (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *) (a)) + DevicePathNodeLength(a))) +#define NextDevicePathNode(a) ( (EFI_DEVICE_PATH_PROTOCOL *) ( ((UINT8 *) (a)) + NODE_LENGTH(a))) +#define SetDevicePathEndNode(a) { \ + (a)->Type = 0x7F; \ + (a)->SubType = 0xFF; \ + (a)->Length = sizeof(EFI_DEVICE_PATH_PROTOCOL); \ + } + +#define VA_LIST va_list +#define VA_START va_start +#define VA_ARG va_arg +#define VA_END va_end + +// +// CONTAINING_RECORD - returns a pointer to the structure +// from one of it's elements. +// +#define _CR(Record, TYPE, Field) \ + ((TYPE *) ( (CHAR8 *)(Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) + + +// +// Define macros to build data structure signatures from characters. +// +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) + +#define EfiCopyMem(_Destination, _Source, _Length) gBS->CopyMem ((_Destination), (_Source), (_Length)) +#define EfiSetMem(_Destination, _Length, _Value) gBS->SetMem ((_Destination), (_Length), (_Value)) +#define EfiZeroMem(_Destination, _Length) gBS->SetMem ((_Destination), (_Length), 0) + +#define EFI_TPL_NOTIFY TPL_NOTIFY +#define EFI_TPL_CALLBACK TPL_CALLBACK +#define EFI_TPL_HIGH_LEVEL TPL_HIGH_LEVEL + +#define EFI_CHECK(x) {EFI_STATUS status = (x);if(status!=EFI_SUCCESS)return status;} +#define COUNTOF(x) (sizeof(x)/sizeof((x)[0])) + +#define EfiAppendDevicePathNode DPAddNode +// redefined in core 4.05 #define DPLENGTH(x) ((x).Length) + +void cp( UINT8 code); + +#define EfiCreateEventLegacyBoot CreateLegacyBootEvent + +VOID USB_SmiQueuePut(VOID*); + +typedef struct +{ + UINT8 Down; + UINT8 KeyCode; +} USB_KEY; + +#define MAX_KEY_ALLOWED 32 + +typedef struct +{ + USB_KEY buffer[MAX_KEY_ALLOWED + 1]; + UINT8 bHead; + UINT8 bTail; +} USB_KB_BUFFER; + +EFI_STATUS USBSB_InstallSmiEventHandlers(VOID); +EFI_STATUS USBSB_InstallXhciHwSmiHandler(VOID); +EFI_STATUS USBSB_InstallUsbIntTimerHandler(VOID); +EFI_STATUS USBSB_UninstallTimerHandlers(VOID); + +#endif // __AMI_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/amiusb.c b/Core/EM/usb/rt/amiusb.c new file mode 100644 index 0000000..89a2975 --- /dev/null +++ b/Core/EM/usb/rt/amiusb.c @@ -0,0 +1,3402 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/amiusb.c 121 10/16/16 10:11p Wilsonlee $ +// +// $Revision: 121 $ +// +// $Date: 10/16/16 10:11p $ +// +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/amiusb.c $ +// +// 121 10/16/16 10:11p 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 +// +// 120 7/29/16 3:13a Wilsonlee +// [TAG] EIP264662 +// [Category] Improvement +// [Description] Don't install usb hw smi after reconnecting usb +// controllers. +// [Files] uhcd.c, usb.c, ohci.c, amiusb.c, amiusbhc.c +// +// 119 7/29/16 3: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 +// +// 117 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 +// +// 116 10/16/15 3:34a Wilsonlee +// [TAG] EIP241977 +// [Category] Improvement +// [Description] Improve UsbKbcAccessControl api function. +// [Files] amiusb.c +// +// 115 4/10/15 3:12a 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 +// +// 114 2/10/15 12:20a Wilsonlee +// Fixed build error in non-smm projects. +// +// 113 12/03/14 9:36p Wilsonlee +// [TAG] EIP193805 +// [Category] Improvement +// [Description] Security Enhancement for SMIHandler in USB module. +// [Files] amiusb.c, uhcd.c, usbrt.mak, usbdef.h, usbsb.c +// +// 112 11/23/14 10:10p Wilsonlee +// [TAG] EIP189293 +// [Category] Improvement +// [Description] Implement XHCI key repeat function. +// [Files] usb.c, xhci.c , xhci.h, amiusb.c +// +// 111 6/05/14 9:15p Wilsonlee +// [TAG] EIP171837 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] When use afuwin update BIOS or read ROMID under pure Win8.1 +// OS, sometimes the system will blue screen. +// [RootCause] UsbData->EfiKeyboardBuffer is EfiBootServicesData. This +// memory isn't reserved in OS. We can't write data to this memory in OS. +// [Solution] We clear the buffer at USBKBDProcessKeyboardData function +// if the system is under EFI. +// [Files] amiusb.c +// +// 110 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 109 4/07/14 1:28a Wilsonlee +// [TAG] EIP157193 +// [Category] Improvement +// [Description] Stop the usb host controllers at AcpiModeEnable if they +// art extend cards or don't support HW SMI. +// [Files] amiusb.c +// +// 108 2/10/14 1:19a Ryanchou +// [TAG] EIP149929 +// [Category] Improvement +// [Description] Stop all external EHCI HCs in ACPI enable call. +// [Files] amiusb.c +// +// 107 12/15/13 10:16p Wilsonlee +// [TAG] EIP136594 +// [Category] New Feature +// [Description] Support 64 bits LBA of usb mass storages. +// [Files] Bfiusb.asm, Bfiusb.equ, UsbInt13.c, UsbInt13.h, amiusb.c, +// usbdef.h, usbmass.c, UsbMass.h, efiusbmass.c, UI13.bin +// +// 106 11/05/13 4:46a Ryanchou +// [TAG] EIP135636 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] NumLock LED cannot be on/off properly. +// [RootCause] It is the side effect of EIP #107429 changes, the +// keyboard does not generate break code when pressing NumLock. +// [Solution] Remove the EIP #107429 changes. +// [Files] amiusb.c, usbkbd.c, efiusbkb.c +// +// 105 10/19/13 7:06a Ryanchou +// [TAG] EIP138257 +// [Category] Improvement +// [Description] Correct USB HID device type. +// [Files] amiusb.c, usbdef.h, usbhid.c, efiusbhid.c, uhcd.c +// +// 104 8/06/13 4:21a Wilsonlee +// [TAG] EIP128970 +// [Category] Improvement +// [Description] UsbInstallHwSmiHandler returns EFI_UNSUPPORTED if +// HCType is invalid. +// [Files] amiusb.c +// +// 103 6/02/13 11:43p Wilsonlee +// [TAG] EIP123235 +// [Category] Improvement +// [Description] Stop the usb host controller at ExitBootService if it +// is an extend card or it doesn't support HW SMI. +// [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, +// uhcd.c +// +// 102 4/10/13 9:29p Wilsonlee +// [TAG] EIP120573 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Afuwinx64/Safuwinx64 hang up issue. +// [RootCause] EfiZeroMem is a boot service function, we can't use it +// during runtime. +// [Solution] Use MemFill function to clear the KBC buffers. +// [Files] amiusb.c +// +// 101 3/19/13 3:58a 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 +// +// 100 1/23/13 4:15a Ryanchou +// [TAG] EIP111280 +// [Category] Improvement +// [Description] Add USB APIs for external driver. +// [Files] amiusb.c, amiusb.h, usbdef.h +// +// 99 1/22/13 3:09a Wilsonlee +// [TAG] EIP112938 +// [Category] Improvement +// [Description] Create a header file for usb mass storage driver. +// [Files] UsbMass.h, usbmass.c, usbdef.h, amiusb.c, efiusbmass.c +// +// 98 12/21/12 5:02a Ryanchou +// [TAG] EIP71730 +// [Category] New Feature +// [Description] Added OHCI handoff support. +// [Files] usb.sdl, usbport.c, amiusb.c, usbdef.h, UsbPolicy.h, usb.sd, +// usb.uni +// +// 97 12/09/12 12:12a Wilsonlee +// [TAG] EIP107429 +// [Category] Improvement +// [Description] Process the make code even if there is no break code. +// [Files] efiusbkb.c, amiusb.c +// +// 96 12/02/12 10:23p Roberthsu +// [TAG] EIP102150 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Push key and unplug KB , character repeat can not. +// stop +// [RootCause] Because repeat key does not clear when usb keyboard +// unplug. +// [Solution] When keyboard disconnrct, clear keyboard device id with +// device id buffer and scancode buffer. +// [Files] amiusb.c,syskbc.c,uhcd.c,usbkbd.c +// +// 95 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 +// +// 94 8/29/12 8:10a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 93 8/07/12 9:39p Wilsonlee +// [TAG] EIP96366 +// [Category] New Feature +// [Description] Add the token "DEFAULT_USB_EMUL6064_OPTION" that +// control the default value of the I/O port 60h/64h emulation support +// option. +// [Files] usb.sd, usb.sdl, amiusb.c, amiusb.h +// +// 92 6/13/12 7:31a Lavanyap +// [TAG] EIP89825 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System get's hangs inside the SMI handler while flashing +// the Bios. +// [RootCause] Port 60/64 access SMI will not be generated immediately +// if accessed inside an SMI handler when KbcEmulation is enabled. +// [Solution] Emulation is disabled while accessing the Port 60/64. +// [Files] amiusb.c +// +// 91 5/22/12 10:03a Ryanchou +// [TAG] EIP90154 +// [Category] Improvement +// [Description] Remove the USBSB_EnableSmmPeriodicSmi and +// USBSB_DisableSmmPeriodicSmi hooks. +// [Files] amidef.h, amiusb.c, usb.c, usbsb.c +// +// 90 5/04/12 6:37a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 89 5/04/12 5:21a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 88 5/03/12 5:50a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 87 1/16/12 6:01a Ryanchou +// [TAG] EIP81132 +// [Description] Add core version check for EIP80609 solution. +// [Files] amiusb.c, usbrt.mak, usbsb.c +// +// 86 1/14/12 4:09a Ryanchou +// [TAG] EIP80609 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] If to enable debug mode and set launch CSM is "Never" in +// setup, system will hang at 0xB1 +// [RootCause] The pointer AmiUsb is invalid if CSM is not launched, +// that may cause CPU exception. +// [Solution] Added USB smm protocol, and use SmmLocateProtocol to get +// the pointer. +// [Files] amiusb.c, AmiUsbController.h, usbrt.mak, usbsb.c +// +// 85 1/13/12 4:23a Ryanchou +// [TAG] EIP47348 +// [Category] New Feature +// [Description] Support for USB Port Reset function. +// [Files] amiusb.c, amiusb.h, amiusbhc.c, uhci.c, usb.c, usbbus.c, +// usbbus.h, usbmass.c +// +// 84 12/09/11 3:09p Ryanchou +// [TAG] EIP7768 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] USB mass storage can't work after unplug and plug under DOS +// [RootCause] The SW SMI handler checks USB_FLAG_RUNNING_UNDER_EFI flag +// to get the URP from USB global data area or EBDA. Legacy boot event +// clears the flag, and UsbPrepareForLegacyOS will not be invoked. +// [Solution] Check the URP in USB global data area, if it is not empty, +// get it in USB global data area, or get it in EBDA. +// [Files] amiusb.c +// +// 83 11/08/11 8:22a Wilsonlee +// [TAG] EIP74876 +// [Category] New Feature +// [Description] Add USB API for shutdown single USB controller. +// [Files] amiusb.c, amiusb.h, usb.c, usbdef.h, uhcd.c, uhcd.h, +// AmiUsbController.h +// +// 82 11/08/11 1:41a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 81 11/05/11 3:26a Ryanchou +// [TAG] EIP70094 +// [Category] Improvement +// [Description] Microsoft CSM Opt-Out feature implementation. +// [Files] amiusb.c, uhcd.c +// +// 80 10/17/11 2:24a Ryanchou +// [TAG] EIP69136 +// [Category] Improvement +// [Description] Remove the dependency of EBDA in USB module for CSM +// disabling. +// [Files] amiusb.c, uhcd.c, usbport.c, usbsb.c +// +// 79 9/28/11 10:45a Ryanchou +// [TAG] EIP66064 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System hangs when waiting for finger swipe +// [RootCause] USB driver save the URP pointer to EBDA in function +// UsbSmiCore and UsbSmiHc, the pointer will be destroyed if someone also +// invoke the two functions. +// [Solution] Save the URP pointer before generate SW SMI and restore it +// after return from SMI. +// [Files] amiusb.c, amiusbhc.c, usbport.c +// +// 78 8/08/11 6:57a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 77 8/05/11 6:18a Ryanchou +// [TAG] EIP60706 +// [Category] Improvement +// [Description] Move gUsbBadDeviceTable into SMRAM. +// [Files] usbport.c, amiusb.c, usb.c, uhcd.c, AmiUsbController.h +// +// 76 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 75 7/12/11 8:09a 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 +// +// 74 5/03/11 8:44a Ryanchou +// [TAG] EIP57521 +// [Category] Improvement +// [Description] Enumerate root hub ports after start host controllers +// in USB_StartLegacy. +// [Files] amiusb.c +// +// 73 3/30/11 9:02a Ryanchou +// [TAG] EIP41483 +// [Category] Improvement +// [Description] Stop timer SMI after legacy shutdown. +// [Files] amiusb.c, AmiUsbController.h, ohci.c +// +// 72 3/29/11 10:07a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 71 12/24/10 5:02a Tonylo +// [TAG] EIP48323 +// [Category] Improvement +// [Description] Reflush USB keyboard data buffer to avoid junk data +// sent after enable USB keyboard data throughput. +// [Files] AMIUSB.C +// +// 70 11/22/10 8:42a Ryanchou +// [TAG] EIP48064 +// [Category] Improvement +// [Description] The SB template implemented elink +// AcpiEnableCallbackList, the XHCI/EHCI hand off function should be +// invoked via the elink AcpiEnableCallbackList. +// [Files] amidef.h, amiusb.c, amiusb.dxs, amiusb.h, +// AmiUsbController.h, usb.sdl, usbrt.mak, usbsb.c +// +// 69 10/07/10 9:32a Ryanchou +// EIP42986: Remove the retry loop in UsbHwSmiHandler. +// +// 68 8/31/10 8:57a Tonylo +// Remove user tags for coding standard. +// +// Description: Remove user tags for coding standard. +// +// 67 8/18/10 4:22p Olegi +// Klockwork related fixes; EIP37978 +// +// 66 7/27/10 9:11a Ryanchou +// EIP41216: Return correct error code when device isn't present. +// +// 65 7/15/10 4:33a Tonylo +// EIP21649 - USB mass storage device still appear in BBS menu when USB +// legacy support is disabled. +// +// 64 6/07/10 8:56a Ryanchou +// EIP38547: Fixed system halt when installing FreeBSD. +// +// 63 3/31/10 6:26p Olegi +// +// 62 3/25/10 9:45a Olegi +// +// 61 3/19/10 10:05a Olegi +// +// 60 1/27/10 5:19p Olegi +// Added chipset porting hook to initialize timers. +// +// 59 12/01/09 10:06a Olegi +// EIP31535: RWV error code corrected. +// +// 58 11/25/09 8:05a Olegi +// EIPEIP29733: Added KBC access control API +// +// 57 10/30/09 5:47p Olegi +// +// 56 10/02/09 10:49a Olegi +// Code cleanup. +// +// 54 9/15/09 10:21a Olegi +// Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. +// +// 53 8/26/09 11:41a Olegi +// Changes that prevent collision of keyboard activity and mass storage +// access. EIP#22808 +// +// 52 5/22/09 1:46p Olegi +// Added the special treatment for in-built hubs. +// +// 51 5/21/09 5:11p Olegi +// Added checking for hotplug fake drives in Read/Write/Verify functions. +// +// 50 1/29/09 2:31p Olegi +// USB API CheckDevicePresence is extended with USB_SRCH_DEVBASECLASS_NUM +// search key. +// +// 49 1/23/09 4:28p Olegi +// Added EXTRA_CHECK_DEVICE_READY condition for the fix to EIP#15037. +// +// 48 1/05/09 9:40a Olegi +// Changes for EIP#15037. Extra CheckDeviceReady call added to read/write +// functions. +// +// 46 10/06/08 3:33p Olegi +// EHCI change ownership testing in DOS fix (EIP#14855). +// +// 44 9/24/08 4:01p Olegi +// Modified USBAPI_ChangeOwner so that it allows multiple calls to +// acquiring the ownership without releasing it. +// +// 43 7/04/08 1:07p Olegi +// Device "Ultra-X, Inc.: Ultra-X QTP USB HD 1.01" is removed from +// incompatible device list. +// +// 42 6/27/08 5:52p Olegi +// Added incompatible devices. +// +// 41 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 40 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 39 12/05/07 4:36p Olegi +// Modification in USBSWSMIHandler() related to the 64/32-bit pointers. +// +// 36 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 34 6/11/07 2:53p Olegi +// Bugfix in device read/write routine: do not issue RWV command if there +// is no media present. +// +// 32 3/20/07 12:16p Olegi +// SMITHUNK removed. +// +// 28 10/18/06 9:40a Andriyn +// Fix: race condition on hot-plug in / plug-off +// +// 27 10/12/06 4:41p Olegi +// Modified the method of passing arguments into USBSWSMIHandler: it is +// done through memory location, not using CPU register. This change is +// only valid for CSM16 versions 31 and later. +// +// 26 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 24 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 23 3/06/06 6:22p Olegi +// Lun devices support modifications: supported using the index in +// DEV_INFO table, not through dedicated massLun table. +// +// 21 1/11/06 11:51a Olegi +// LegacyUsbSupport setup question functionality added. +// +// 18 10/20/05 3:08p Olegi +// ReadDevice correction (EST change). +// +// 14 8/25/05 7:19p Andriyn +// USB Keyboard and mouse to use EMUL 60/64 for passing data to KBC. +// Fall-back when EMUL 60/64 is not present +// +// 13 8/23/05 5:50p Olegi +// USBMassGetDeviceParameters function added. +// +// 12 8/11/05 9:53a Olegi +// 60/64 port emulation related fixes for EMU6064 driver. +// +// 11 8/04/05 5:58p Andriyn +// Legacy over LegacyFree +// +// 10 6/20/05 8:55a Olegi +// .NET compiler with highest warning level and warning-as-error +// modification. +// +// 9 6/15/05 1:59p Andriyn +// Comments were changed +// +// 6 6/03/05 6:06p Olegi +// UsbHwSmiHandler modified to be called individually from UHCI, OHCI and +// EHCI drivers. +// +// 5 6/03/05 9:28a Olegi +// ATA Error reporting is corrected in USBWrapGetATAErrorCode. +// +// 4 6/01/05 5:21p Olegi +// Debug message shortened. +// +// 3 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 2 5/10/05 4:11p Andriyn +// USBBUS implementation +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: AMIUSB.C +// +// Description: AMI USB API implementation. The following code will be +// copied to SMM; only RT functions can be used. gUsbData +// is obtained from AMIUHCD in the entry point and can be +// used afterwards. +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <AmiDxeLib.h> +#include "amiusb.h" +#include "amidef.h" +#include <UsbDevDriverElinks.h> //(EIP71750+) +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#include <AmiUsbSmmGlobalDataValidationLib.h> +#endif + +#if USB_DEV_KBD +#include "usbkbd.h" +#endif +#include "UsbMass.h" + + //(EIP54018+)> +#if USB_S5_WAKEUP_SUPPORT +#include <Protocol\SmmSxDispatch.h> +#include <Protocol\SmmPowerButtonDispatch.h> +#endif + //<(EIP54018+) +//#pragma warning (disable: 4152) + +extern UINT8 IsKbcAccessBlocked; //(EIP29733+) +EFI_EMUL6064MSINPUT_PROTOCOL* gMsInput = 0; +EFI_EMUL6064KBDINPUT_PROTOCOL* gKbdInput = 0; +EFI_EMUL6064TRAP_PROTOCOL* gEmulationTrap = 0; + +USB_GLOBAL_DATA *gUsbData; +//USB_BADDEV_STRUC *gUsbBadDeviceTable; //(EIP60706-) + +AMI_USB_SMM_PROTOCOL gUsbSmmProtocol = {0}; + +BOOLEAN gLockSmiHandler = FALSE; +BOOLEAN gLockHwSmiHandler = FALSE; +BOOLEAN gCheckUsbApiParameter = FALSE; + +VOID StopControllerType(UINT8); +VOID StartControllerType(UINT8); +UINT8 USB_StopDevice (HC_STRUC*, UINT8, UINT8); +UINT8 USB_EnumerateRootHubPorts(UINT8); //(EIP57521+) +VOID StopControllerBdf(UINT16); //(EIP74876+) + +VOID FillHcdEntries(); + //(EIP71750+)> +typedef VOID USB_DEV_DELAYED_DRIVER_CHECK (DEV_DRIVER*); +extern USB_DEV_DELAYED_DRIVER_CHECK USB_DEV_DELAYED_DRIVER EndOfUsbDevDelayedDriverList; +USB_DEV_DELAYED_DRIVER_CHECK* UsbDevDelayedDrivers[]= {USB_DEV_DELAYED_DRIVER NULL}; + +typedef VOID USB_DEV_DRIVER_CHECK (DEV_DRIVER*); +extern USB_DEV_DRIVER_CHECK USB_DEV_DRIVER EndOfUsbDevDriverList; +USB_DEV_DRIVER_CHECK* UsbDevDrivers[]= {USB_DEV_DRIVER NULL}; + //<(EIP71750+) + //(EIP54018+)> +#if USB_S5_WAKEUP_SUPPORT +VOID UsbSuspend(VOID); +#endif + +#if USB_S5_WAKEUP_SUPPORT +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UsbS5SmiCallback +// +// Description: +// This function enter usb s5 callback. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +UsbS5SmiCallback( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext +) +{ + EFI_STATUS Status = EFI_SUCCESS; +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + return; + } +#endif + UsbSuspend(); +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UsbPowerButtonSmiCallback +// +// Description: +// This function enter s5 callback if press power button. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +UsbPowerButtonSmiCallback( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT *DispatchContext +) +{ + EFI_STATUS Status = EFI_SUCCESS; +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + return; + } +#endif + UsbSuspend(); +} +#endif + //<(EIP54018+) + +//<AMI_THDR_START> +//---------------------------------------------------------------------------- +// Name: aUsbApiTable - USB API Function Dispatch Table +// +// Type: Function Dispatch Table +// +// Description: This is the table of functions used by USB API +// +// Notes: This functions are invoked via software SMI +// +//---------------------------------------------------------------------------- +//<AMI_THDR_END> + +API_FUNC aUsbApiTable[] = { + USBAPI_CheckPresence, + USBAPI_Start, + USBAPI_Stop, + USBAPI_DisableInterrupts, + USBAPI_EnableInterrupts, + USBAPI_MoveDataArea, + USBAPI_GetDeviceInfo, + USBAPI_CheckDevicePresence, + USBAPI_MassDeviceRequest, + USBAPI_PowerManageUSB, + USBAPI_PrepareForOS, + USBAPI_SecureInterface, + USBAPI_LightenKeyboardLEDs, + USBAPI_ChangeOwner, + USBAPI_HC_Proc, + USBAPI_Core_Proc, + USBAPI_LightenKeyboardLEDs_Compatible, + USBAPI_KbcAccessControl, + USBAPI_LegacyControl, + USBAPI_GetDeviceAddress, + USBAPI_ExtDriverRequest, + USBAPI_CCIDRequest, + USBAPI_UsbStopController, //(EIP74876+) + USBAPI_HcStartStop +}; + +//<AMI_THDR_START> +//---------------------------------------------------------------------------- +// Name: USBMassAPITable - USB Mass Storage API Function Dispatch Table +// +// Type: Function Dispatch Table +// +// Description: This is the table of functions used by USB Mass Storage API +// +//---------------------------------------------------------------------------- +//<AMI_THDR_END> + +API_FUNC aUsbMassApiTable[] = { + USBMassAPIGetDeviceInformation, // USB Mass API Sub-Func 00h + USBMassAPIGetDeviceGeometry, // USB Mass API Sub-Func 01h + USBMassAPIResetDevice, // USB Mass API Sub-Func 02h + USBMassAPIReadDevice, // USB Mass API Sub-Func 03h + USBMassAPIWriteDevice, // USB Mass API Sub-Func 04h + USBMassAPIVerifyDevice, // USB Mass API Sub-Func 05h + USBMassAPIFormatDevice, // USB Mass API Sub-Func 06h + USBMassAPICommandPassThru, // USB Mass API Sub-Func 07h + USBMassAPIAssignDriveNumber, // USB BIOS API function 08h + USBMassAPICheckDevStatus, // USB BIOS API function 09h + USBMassAPIGetDevStatus, // USB BIOS API function 0Ah + USBMassAPIGetDeviceParameters // USB BIOS API function 0Bh +}; + +EFI_DRIVER_ENTRY_POINT(USBDriverEntryPoint) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: USBDriverEntryPoint +// +// Description: USB Driver entry point +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +USBDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + + InitAmiLib(ImageHandle, SystemTable); + +#if USB_RUNTIME_DRIVER_IN_SMM + Status = InitSmmHandler(ImageHandle, SystemTable, InSmmFunction, NULL); +#else + Status = InstallUsbProtocols(); + InitializeUsbGlobalData(); +#endif + ASSERT_EFI_ERROR(Status); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: InitializeUsbGlobalData +// +// Description: This function initializes the USB global data. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +InitializeUsbGlobalData( + VOID +) +{ + EFI_STATUS Status; + UINT8 bDriverIndex; + UINT8 bDelayedIndex; + + // + // Initialize host controller drivers + // + FillHcdEntries(); // This routine is implemented in $(BUILD_DIR)\dummyusbrt.c + + // + // Initialize the device driver pointers + // + bDriverIndex = 0; + bDelayedIndex = 0; + //(EIP71750)> + while(UsbDevDelayedDrivers[bDelayedIndex]) { + UsbDevDelayedDrivers[bDelayedIndex](&gUsbData->aDelayedDrivers[bDelayedIndex]); + if (gUsbData->aDelayedDrivers[bDelayedIndex].pfnDeviceInit) { + (*gUsbData->aDelayedDrivers[bDelayedIndex].pfnDeviceInit)(); + } + if (gUsbData->aDelayedDrivers[bDelayedIndex].bDevType) { + bDelayedIndex++; + } + } + + while(UsbDevDrivers[bDriverIndex]) { + UsbDevDrivers[bDriverIndex](&gUsbData->aDevDriverTable[bDriverIndex]); + if (gUsbData->aDevDriverTable[bDriverIndex].pfnDeviceInit) { + (*gUsbData->aDevDriverTable[bDriverIndex].pfnDeviceInit)(); + } + if (gUsbData->aDevDriverTable[bDriverIndex].bDevType) { + bDriverIndex++; + } + } + + // + // Allocate a block of memory to be used as a temporary + // buffer for USB mass transfer + // + Status = pBS->AllocatePool (EfiRuntimeServicesData, MAX_CONSUME_BUFFER_SIZE, + &gUsbData->fpUSBMassConsumeBuffer); + ASSERT_EFI_ERROR(Status); + pBS->SetMem(gUsbData->fpUSBMassConsumeBuffer, MAX_CONSUME_BUFFER_SIZE, 0); + + // + // Allocate a block of memory for the temporary buffer + // + Status = gBS->AllocatePool (EfiRuntimeServicesData, MAX_TEMP_BUFFER_SIZE, + &gUsbData->fpUSBTempBuffer); + ASSERT_EFI_ERROR(Status); + pBS->SetMem(gUsbData->fpUSBTempBuffer, MAX_TEMP_BUFFER_SIZE, 0); + + // + // Allow to enumerate ports + // + gUsbData->bEnumFlag = FALSE; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbApiHandler +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UsbApiHandler(VOID* Param) +{ + URP_STRUC *fpURP = (URP_STRUC*)Param; + UINT8 bFuncIndex; + UINT8 bNumberOfFunctions; + + if (fpURP == NULL) { + return; + } + + bFuncIndex = fpURP->bFuncNumber; + bNumberOfFunctions = sizeof aUsbApiTable / sizeof (API_FUNC *); + + // + // Make sure function number is valid; if function number is not zero + // check for valid extended USB API function + // + if (bFuncIndex && ((bFuncIndex < USB_NEW_API_START_FUNC ) || + bFuncIndex > (bNumberOfFunctions + USB_NEW_API_START_FUNC))) { + //fpURP->bRetValue = USBAPI_INVALID_FUNCTION; + USB_DEBUG(3, "UsbApiHandler Invalid function#%x\n", bFuncIndex); + return; + } + + if (bFuncIndex) { + bFuncIndex = (UINT8)(bFuncIndex - USB_NEW_API_START_FUNC + 1); + } + + aUsbApiTable[bFuncIndex](fpURP); // Call the appropriate function + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: InstallUsbProtocols +// +// Description: This function initializes the USB global data. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +InstallUsbProtocols( + VOID +) +{ + EFI_STATUS Status; + EFI_USB_PROTOCOL *UsbProtocol; + + Status = pBS->LocateProtocol(&gEfiUsbProtocolGuid, NULL, &UsbProtocol); + if (EFI_ERROR(Status)) { + return Status; + } + gUsbData = UsbProtocol->USBDataPtr; + + UsbProtocol->UsbRtKbcAccessControl = UsbKbcAccessControl; + + //Hook USB legacy control function for shutdown/init USB legacy support + UsbProtocol->UsbLegacyControl = USBRT_LegacyControl; + UsbProtocol->UsbStopUnsupportedHc = USB_StopUnsupportedHc; +#if !USB_RUNTIME_DRIVER_IN_SMM + UsbProtocol->UsbInvokeApi = UsbApiHandler; +#endif + + return Status; +} + +#if USB_RUNTIME_DRIVER_IN_SMM +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: InSmmFunction +// +// Description: SMM entry point of AMIUSB driver +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +InSmmFunction( + EFI_HANDLE ImageHandle, + EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + + EFI_SMM_SW_DISPATCH_CONTEXT SwSmiContext; + EFI_HANDLE SwSmiHandle = NULL; + EFI_SMM_SW_DISPATCH_PROTOCOL *SwSmiDispatch; + + UINT32 KbcEmulFeature = 0; + VOID *ProtocolNotifyRegistration; + EFI_EVENT Emul6064Event = NULL; + + //(EIP54018+)> +#if USB_S5_WAKEUP_SUPPORT + EFI_SMM_SX_DISPATCH_CONTEXT S5DispatchContext; + EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatchProtocol; + EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PbDispatchContext; + EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL *PbDispatchProtocol; + EFI_HANDLE S5DispatchHandle; + EFI_HANDLE PbDispatchHandle; +#endif + //<(EIP54018+) +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + EFI_HANDLE UsbSmmProtocolHandle = NULL; + + Status = InitAmiSmmLib(ImageHandle, SystemTable); + if (EFI_ERROR(Status)) return Status; +#endif + + InitAmiBufferValidationLib(ImageHandle, SystemTable); + + InstallUsbProtocols(); + InitializeUsbGlobalData(); + + + Status = pBS->LocateProtocol (&gEmul6064TrapProtocolGuid, NULL, &gEmulationTrap); + if (EFI_ERROR(Status)) { + Status = RegisterProtocolCallback(&gEmul6064TrapProtocolGuid, + Emul6064TrapCallback, + NULL, + &Emul6064Event, + &ProtocolNotifyRegistration); + } + + if(!gUsbData->kbc_support) { + Status = gBS->LocateProtocol (&gEmul6064MsInputProtocolGuid, NULL, &gMsInput); + pBS->LocateProtocol (&gEmul6064KbdInputProtocolGuid, NULL, &gKbdInput); + + if (Status == EFI_SUCCESS) { + gUsbData->dUSBStateFlag |= USB_FLAG_6064EMULATION_ON; + if(gEmulationTrap) + KbcEmulFeature = gEmulationTrap->FeatureSupported(gEmulationTrap); + if(KbcEmulFeature & IRQ_SUPPORTED) { + gUsbData->dUSBStateFlag |= USB_FLAG_6064EMULATION_IRQ_SUPPORT; + } + } else { + InitSysKbc( &gKbdInput, &gMsInput ); + } + } else { + // + //Init Fake Emulation interface + // + InitSysKbc( &gKbdInput, &gMsInput ); + } + + Status = USBSB_InstallSmiEventHandlers(); + + USB_DEBUG(DEBUG_LEVEL_3,"AMIUSB global data at 0x%x\n", gUsbData); + + // + // Register the USB SW SMI handler + // + Status = pBS->LocateProtocol (&gEfiSmmSwDispatchProtocolGuid, NULL, &SwSmiDispatch); + + if (EFI_ERROR (Status)) { + USB_DEBUG(DEBUG_LEVEL_0, "SmmSwDispatch protocol: %r\n", Status); + return Status; + } + + SwSmiContext.SwSmiInputValue = USB_SWSMI; + Status = SwSmiDispatch->Register (SwSmiDispatch, USBSWSMIHandler, &SwSmiContext, &SwSmiHandle); + + USB_DEBUG(DEBUG_LEVEL_3, "AMIUSB SW SMI registration:: %r\n", Status); + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + gUsbSmmProtocol.UsbStopUnsupportedHc = USB_StopUnsupportedHc; + gUsbSmmProtocol.UsbApiTable = aUsbApiTable; + gUsbSmmProtocol.UsbMassApiTable = aUsbMassApiTable; + gUsbSmmProtocol.GlobalDataValidation.ConstantDataCrc32 = 0; + gUsbSmmProtocol.GlobalDataValidation.Crc32Hash = (UINT32)GetCpuTimer(); + + Status = pSmst->SmmInstallProtocolInterface( + &UsbSmmProtocolHandle, + &gAmiUsbSmmProtocolGuid, + EFI_NATIVE_INTERFACE, + &gUsbSmmProtocol + ); + + USB_DEBUG(DEBUG_LEVEL_3, "AMIUSB SMM protocol: %r\n", Status); +#endif + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + InitAmiUsbSmmGlobalDataValidationLib(ImageHandle, SystemTable); + UpdateAmiUsbSmmGlobalDataCrc32(gUsbData); +#endif + + //(EIP54018+)> +#if USB_S5_WAKEUP_SUPPORT + Status = pBS->LocateProtocol( + &gEfiSmmSxDispatchProtocolGuid, + NULL, + &SxDispatchProtocol + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + S5DispatchContext.Type = SxS5; + S5DispatchContext.Phase = SxEntry; + Status = SxDispatchProtocol->Register( + SxDispatchProtocol, + UsbS5SmiCallback, + &S5DispatchContext, + &S5DispatchHandle + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + // Locate Power Button Dispatch Protocol + Status = pBS->LocateProtocol( + &gEfiSmmPowerButtonDispatchProtocolGuid, + NULL, + &PbDispatchProtocol + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + // Register the handler for power button presses + PbDispatchContext.Phase = PowerButtonEntry; + Status = PbDispatchProtocol->Register( + PbDispatchProtocol, + UsbPowerButtonSmiCallback, + &PbDispatchContext, + &PbDispatchHandle + ); +#endif + //<(EIP54018+) + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBSWSMIHandler +// +// Description: Invoked on reads from SW SMI port with value USB_SWSMI. This +// function dispatches the USB Request Packets (URP) to the +// appropriate functions. +// +// Input: EBDA:USB_DATA_EBDA_OFFSET - Pointer to the URP (USB Request +// Packet structure) +// DispatchHandle - EFI Handle +// DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT +// +// Output: bRetValue Zero on successfull completion +// Non-zero on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBSWSMIHandler ( + EFI_HANDLE DispatchHandle, + EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext +) +{ + URP_STRUC *UsbUrp; + UINT16 EbdaSeg; + EFI_STATUS Status; + + if (gLockSmiHandler == TRUE) { + return; + } +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + gLockHwSmiHandler = TRUE; + gLockSmiHandler = TRUE; + return; + } +#endif + + if (gUsbData->fpURP) { // Call from AMIUSB C area + Status = AmiValidateMemoryBuffer((VOID*)gUsbData->fpURP, sizeof(URP_STRUC)); + if (EFI_ERROR(Status)) { + USB_DEBUG(3, "UsbApiHandler Invalid Pointer, the address is in SMRAM.\n"); + return; + } + UsbUrp = gUsbData->fpURP; + gUsbData->fpURP = 0; // Clear the switch + } else { + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_OS) { + return; + } + // + // Get the fpURP pointer from EBDA + // + EbdaSeg = *((UINT16*)0x40E); + UsbUrp = *(URP_STRUC**)(UINTN)(((UINT32)EbdaSeg << 4) + USB_DATA_EBDA_OFFSET); + UsbUrp = (URP_STRUC*)((UINTN)UsbUrp & 0xFFFFFFFF); + Status = AmiValidateMemoryBuffer((VOID*)UsbUrp, sizeof(URP_STRUC)); + if (EFI_ERROR(Status)) { + USB_DEBUG(3, "UsbApiHandler Invalid Pointer, the address is in SMRAM.\n"); + return; + } + } + + if (UsbUrp == NULL) { + return; + } + + gCheckUsbApiParameter = TRUE; + + UsbApiHandler(UsbUrp); + + gCheckUsbApiParameter = FALSE; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHwSmiHandler +// +// Description: USB Hardware SMI handler. +// +// Input: Host controller type. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UsbHwSmiHandler (UINT8 HcType) +{ + UINT8 Index; + HC_STRUC *HcStruc; + EFI_STATUS Status; + + if (gLockHwSmiHandler == TRUE) { + return; + } + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + gLockHwSmiHandler = TRUE; + gLockSmiHandler = TRUE; + return; + } +#endif + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + HcStruc = gUsbData->HcTable[Index]; + if (HcStruc == NULL) { + continue; + } + if (!(HcStruc->dHCFlag & HC_STATE_USED)) { + continue; + } + if (HcStruc->bHCType == HcType) { // Process appropriate interrupt + (*gUsbData->aHCDriverTable + [GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDProcessInterrupt)(HcStruc); + } + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: xhciHWSMIHandler +// +// Description: USB Hardware SMI handler. +// +// Input: DispatchHandle - EFI Handle +// DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UhciHWSMIHandler ( + EFI_HANDLE DispatchHandle, + EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ) +{ + UsbHwSmiHandler(USB_HC_UHCI); +} +VOID +OhciHWSMIHandler ( + EFI_HANDLE DispatchHandle, + EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ) +{ + UsbHwSmiHandler(USB_HC_OHCI); +} +VOID +EhciHWSMIHandler ( + EFI_HANDLE DispatchHandle, + EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ) +{ + UsbHwSmiHandler(USB_HC_EHCI); +} + +VOID +XhciHwSmiHandler ( + EFI_HANDLE DispatchHandle, + VOID *DispatchContext + ) +{ + UsbHwSmiHandler(USB_HC_XHCI); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBInstallHwSmiHandler +// +// Description: +// This function registers USB hardware SMI callback function. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +UsbInstallHwSmiHandler( + HC_STRUC *HcStruc +) +{ + EFI_STATUS Status; + EFI_SMM_USB_DISPATCH_CONTEXT UsbContext; + EFI_SMM_USB_DISPATCH_PROTOCOL *UsbDispatch; + EFI_SMM_USB_DISPATCH UsbCallback; + EFI_HANDLE Handle = NULL; + + if (HcStruc->HwSmiHandle != NULL) { + return EFI_SUCCESS; + } + + Status = gBS->LocateProtocol( + &gEfiSmmUsbDispatchProtocolGuid, + NULL, + &UsbDispatch); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return Status; + } + + switch (HcStruc->bHCType) { + case USB_HC_UHCI: + UsbCallback = UhciHWSMIHandler; + break; + + case USB_HC_OHCI: + UsbCallback = OhciHWSMIHandler; + break; + + case USB_HC_EHCI: + UsbCallback = EhciHWSMIHandler; + break; + + case USB_HC_XHCI: + UsbCallback = XhciHwSmiHandler; + break; + + default: + return EFI_UNSUPPORTED; + } + + UsbContext.Type = UsbLegacy; + UsbContext.Device = HcStruc->pHCdp; + + Status = UsbDispatch->Register( + UsbDispatch, + UsbCallback, + &UsbContext, + &Handle); + + USB_DEBUG(DEBUG_LEVEL_3, "AMIUSB HC type %x HW SMI registation status:: %r\n", HcStruc->bHCType, Status); + + if (!EFI_ERROR(Status)) { + HcStruc->HwSmiHandle = Handle; + } + + return Status; +} +#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: Emul6064TrapCallback +// +// Description: +// Update the KbcEmul feature when the Emul6064Trap Protocol becomes available. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +Emul6064TrapCallback ( + EFI_EVENT Event, + VOID *Context +) +{ + EFI_STATUS Status; + UINT32 KbcEmulFeature = 0; + + Status = gBS->LocateProtocol( + &gEmul6064TrapProtocolGuid, + NULL, + &gEmulationTrap); + + if(!gUsbData->kbc_support) { + Status = gBS->LocateProtocol( + &gEmul6064MsInputProtocolGuid, + NULL, + &gMsInput); + + gBS->LocateProtocol( + &gEmul6064KbdInputProtocolGuid, + NULL, + &gKbdInput); + + if (Status == EFI_SUCCESS) { + gUsbData->dUSBStateFlag |= USB_FLAG_6064EMULATION_ON; + if(gEmulationTrap) + KbcEmulFeature = gEmulationTrap->FeatureSupported(gEmulationTrap); + if(KbcEmulFeature & IRQ_SUPPORTED) { + gUsbData->dUSBStateFlag |= USB_FLAG_6064EMULATION_IRQ_SUPPORT; + } + } else { + InitSysKbc( &gKbdInput, &gMsInput ); + } + } else { + // + //Init Fake Emulation interface + // + InitSysKbc( &gKbdInput, &gMsInput ); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// USB API Functions +// +////////////////////////////////////////////////////////////////////////////// + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_MassDeviceRequest +// +// Description: This routine services the USB API function number 27h. It +// handles all the mass storage 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 +// 00 Get Device Information +// 01 Get Device Parameter +// 02 Reset Device +// 03 Read Device +// 04 Write Device +// 05 Verify Device +// 06 Format Device +// 07 Request Sense +// 08 Test Unit Ready +// 09 Start Stop Unit +// 0A Read Capacity +// 0B Mode Sense +// 0C Device Inquiry +// 0D Send Command +// 0E Assign drive number +// +// Output: URP structure is updated with the relevant information +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBAPI_MassDeviceRequest (URP_STRUC *fpURP) +{ + UINT8 bMassFuncIndex = fpURP->bSubFunc; + UINT8 bNumberOfMassFunctions = sizeof aUsbMassApiTable / sizeof (API_FUNC *); + + // + // Make sure function number is valid + // + if (bMassFuncIndex >= bNumberOfMassFunctions) { + //fpURP->bRetValue = USBAPI_INVALID_FUNCTION; + USB_DEBUG(3, "UsbApi MassDeviceRequet Invalid function#%x\n", bMassFuncIndex); + return; + } + gUsbData->bUSBKBC_MassStorage = 01; + // + // Function number is valid - call it + // + aUsbMassApiTable[bMassFuncIndex](fpURP); + gUsbData->bUSBKBC_MassStorage = 00; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_CheckPresence +// +// Description: This routine services the USB API function number 0. It +// reports the USB BIOS presence, its version number and +// its current status information +// +// Input: fpURPPointer - Pointer to the URP structure +// +// Output: URP structure is updated with the following information +// CkPresence.wBiosRev USB BIOS revision (0210h means r2.10) +// CkPresence.bBiosActive 0 - if USB BIOS is not running +// CkPresence.bNumBootDev Number of USB boot devices found +// CkPresence.bNumHC Number of host controller present +// CkPresence.bNumPorts Number of root hub ports +// CkPresence.dUsbDataArea Current USB data area +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBAPI_CheckPresence (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_SUCCESS; + fpURP->ApiData.CkPresence.bBiosActive = 0; + + fpURP->ApiData.CkPresence.bNumBootDev = 0; // Number of USB boot devices found + fpURP->ApiData.CkPresence.bNumKeyboards = 0; // Number of USB keyboards present + fpURP->ApiData.CkPresence.bNumMice = 0; // Number of USB mice present + fpURP->ApiData.CkPresence.bNumPoint = 0; // Number of USB Point present //(EIP38434+) + fpURP->ApiData.CkPresence.bNumHubs = 0; // Number of USB hubs present + fpURP->ApiData.CkPresence.bNumStorage = 0; // Number of USB storage devices present + + fpURP->ApiData.CkPresence.wBiosRev = (USB_DRIVER_MAJOR_VER << 4) + USB_DRIVER_MINOR_VER; + fpURP->ApiData.CkPresence.bBiosActive = USB_ACTIVE; // Set USB BIOS as active + if (!(gUsbData->dUSBStateFlag & USB_FLAG_DISABLE_LEGACY_SUPPORT)) { + fpURP->ApiData.CkPresence.bBiosActive |= USB_LEGACY_ENABLE; + } + if (gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_ON) { + fpURP->ApiData.CkPresence.bBiosActive |= USB_6064_ENABLE; + } + USBWrap_GetDeviceCount(fpURP); // Get active USB devices +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_Start +// +// Description: This API routine configures the USB host controllers and +// enumerate the devices +// +// Input: fpURPPointer URP structure with input parameters +// StartHc.wDataAreaFlag Indicates which data area to use +// +// Output: StartHc.wDataAreaFlag Returns current data area pointer +// bRetValue - USB_SUCCESS on success, USB_ERROR on error. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_Start (URP_STRUC *fpURP) +{ + USB_DEBUG(DEBUG_LEVEL_3, "USBSMI: Start\n"); + USB_DEBUG(DEBUG_LEVEL_3, "\tUSBAPI_HC_Proc:%x\n", &USBAPI_HC_Proc); + USB_DEBUG(DEBUG_LEVEL_3, "\tUSBAPI_Core_Proc:%x\n", &USBAPI_Core_Proc); + USB_DEBUG(DEBUG_LEVEL_3, "\tUSB_ReConfigDevice:%x\n", &USB_ReConfigDevice); + fpURP->bRetValue = USB_StartHostControllers (gUsbData); + USB_DEBUG(DEBUG_LEVEL_3, "USB_StartHostControllers returns %d\n", fpURP->bRetValue); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_Stop +// +// Description: This routine stops the USB host controllers +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue USB_SUCCESS on success +// USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_Stop (URP_STRUC *fpURP) +{ + gCheckUsbApiParameter = FALSE; + fpURP->bRetValue = USB_StopHostControllers (gUsbData); + USB_DEBUG(DEBUG_LEVEL_3, "USB_StopHostControllers returns %d\n", fpURP->bRetValue); + gUsbData->dUSBStateFlag &= ~(USB_FLAG_DRIVER_STARTED); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_PowerManageUSB +// +// Description: This routine suspends the USB host controllers +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_PowerManageUSB (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_PrepareForOS +// +// Description: This routine updates data structures to reflect that +// POST is completed +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_PrepareForOS (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_SecureInterface +// +// Description: This routine handles the calls related to security device +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_SecureInterface (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_DisableInterrupts +// +// Description: This routine stops the USB host controllers interrupts +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue USB_SUCCESS on success +// USB_ERROR on error (Like data area not found) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_DisableInterrupts (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_EnableInterrupts +// +// Description: This routine re-enable the USB host controller interrupts +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue USB_SUCCESS on success +// USB_ERROR on error (Like data area not found) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_EnableInterrupts (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_MoveDataArea +// +// Description: This routine stops the USB host controllers and moves +// the data area used by host controllers to a new area. +// The host controller is started from the new place. +// +// Input: fpURPPointer URP structure with input parameters +// StartHc.wDataAreaFlag Indicates which data area to use +// +// Output: bRetValue USB_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_MoveDataArea(URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_NOT_SUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_GetDeviceInfo +// +// Description: This routine returns the information regarding +// a USB device like keyboard, mouse, floppy drive etc +// +// Input: fpURPPointer URP structure with input parameters +// GetDevInfo.bDevNumber Device number (1-based) whose +// information is requested +// +// Output: URP structure is updated with the following information +// GetDevInfo.bHCNumber - HC number in which the device is found +// GetDevInfo.bDevType - Type of the device +// bRetValue will be one of the following value +// USB_SUCCESS on successfull completion +// USB_PARAMETER_ERROR if bDevNumber is invalid +// USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID USBAPI_GetDeviceInfo (URP_STRUC *fpURP) +{ + DEV_INFO* fpDevInfo; + + // + // Initialize the return values + // + fpURP->ApiData.GetDevInfo.bHCNumber = 0; + fpURP->ApiData.GetDevInfo.bDevType = 0; + fpURP->bRetValue = USB_ERROR; + + // + // Check for parameter validity + // + if ( !fpURP->ApiData.GetDevInfo.bDevNumber ) return; + + fpURP->bRetValue = USB_PARAMETER_ERROR; + + // + // Get the device information structure for the 'n'th device + // + fpDevInfo = USBWrap_GetnthDeviceInfoStructure(fpURP->ApiData.GetDevInfo.bDevNumber); +// if (!wRetCode) return; // USB_PARAMETER_ERROR + + // + // Return value + // + fpURP->ApiData.GetDevInfo.bDevType = fpDevInfo->bDeviceType; + fpURP->ApiData.GetDevInfo.bHCNumber = fpDevInfo->bHCNumber; + fpURP->bRetValue = USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_CheckDevicePresence +// +// Description: This routine checks whether a particular type of USB device +// is installed in the system or not. +// +// Input: fpURPPointer URP structure with input parameters +// ChkDevPrsnc.bDevType Device type to find +// ChkDevPrsnc.fpHCStruc Pointer to HC being checked for device +// connection; if NULL then the total number of devices +// connected to ANY controller is returned. +// ChkDevPrsnc.bNumber Number of devices connected +// +// Output: bRetValue will be one of the following value +// USB_SUCCESS if device type present, ChkDevPrsnc.bNumber <> 0 +// USB_ERROR if device type absent, ChkDevPrsnc.bNumber returns 0 +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBAPI_CheckDevicePresence (URP_STRUC *fpURP) +{ + UINT8 bSearchFlag; + UINTN dData; + + bSearchFlag = USB_SRCH_DEV_NUM; + if (fpURP->bSubFunc == 1) + { + bSearchFlag = USB_SRCH_DEVBASECLASS_NUM; + } + // + // The total number of devices connected to ANY controller has been requested + // + dData = (UINTN) USB_GetDeviceInfoStruc( bSearchFlag, + 0, fpURP->ApiData.ChkDevPrsnc.bDevType, fpURP->ApiData.ChkDevPrsnc.fpHCStruc); + + fpURP->ApiData.ChkDevPrsnc.bNumber = (UINT8)dData; + fpURP->bRetValue = (UINT8)((fpURP->ApiData.ChkDevPrsnc.bNumber)? + USB_SUCCESS : USB_ERROR); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIGetDeviceInformation +// +// Description: This function is part of the USB BIOS MASS API. This function +// returns the device information of the mass storage device +// +// Input: fpURPPointer Pointer to the URP structure +// bDevAddr USB device address of the device +// +// Output: bRetValue Return value +// fpURPPointer Pointer to the URP structure +// dSenseData Sense data of the last command +// bDevType Device type byte (HDD, CD, Removable) +// bEmuType Emulation type used +// fpDevId Far pointer to the device ID +// dInt13Entry INT 13h entry point +// +// Notes: Initially the bDevAddr should be set to 0 as input. This +// function returns the information regarding the first mass +// storage device (if no device found it returns bDevAddr as +// 0FFh) and also updates bDevAddr to the device address of +// the current mass storage device. If no other mass storage +// device is found then the routine sets the bit7 to 1 +// indicating current information is valid but no more mass +// device found in the system. The caller can get the next +// device info if bDevAddr is not 0FFh and bit7 is not set +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIGetDeviceInformation (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USBMassGetDeviceInfo (&fpURP->ApiData.MassGetDevInfo); +} + +VOID +USBMassAPIGetDeviceParameters (URP_STRUC *fpURP) +{ + DEV_INFO *DevInfo; + EFI_STATUS Status; + + DevInfo = fpURP->ApiData.MassGetDevParms.fpDevInfo; + + Status = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(Status)) { + return; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + Status = AmiValidateMemoryBuffer((VOID*)fpURP->ApiData.MassGetDevParms.fpInqData, sizeof(MASS_INQUIRY)); + if (EFI_ERROR(Status)) { + return; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + fpURP->ApiData.MassGetDevParms.fpInqData = USBMassGetDeviceParameters(DevInfo); + fpURP->bRetValue = (fpURP->ApiData.MassGetDevParms.fpInqData == NULL)? USB_ERROR : USB_SUCCESS; +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBMassAPIGetDevStatus +// +// Description: This function returns the drive status and media presence +// status +// +// Input: fpURPPointer Pointer to the URP structure +// fpURP->ApiData.fpDevInfo - pointer to USB device that is +// requested to be checked +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBMassAPIGetDevStatus(URP_STRUC *fpURP) +{ +#if USB_DEV_MASS + fpURP->bRetValue = USBMassGetDeviceStatus (&fpURP->ApiData.MassGetDevSts); +// USB_DEBUG(DEBUG_LEVEL_3, "USBMassAPIGetDevStatus ... check function call correct?\n"); +#endif +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIGetDeviceGeometry +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure +// bDevAddr USB device address of the device +// +// Output: bRetValue Return value +// fpURPPointer Pointer to the URP structure +// dSenseData Sense data of the last command +// bNumHeads Number of heads +// wNumCylinders Number of cylinders +// bNumSectors Number of sectors +// wBytesPerSector Number of bytes per sector +// bMediaType Media type +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIGetDeviceGeometry(URP_STRUC *fpURP) +{ + fpURP->bRetValue = USBMassGetDeviceGeometry (&fpURP->ApiData.MassGetDevGeo); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIResetDevice +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue Return value +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIResetDevice (URP_STRUC *fpURP) +{ + UINT8 bDevAddr; + DEV_INFO *fpDevInfo; + UINT16 wResult; + + bDevAddr = fpURP->ApiData.MassReset.bDevAddr; + + // + // Get the device info structure for the matching device address + // + fpDevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, bDevAddr, 0); + if((fpDevInfo == NULL)|| (!(fpDevInfo->Flag & DEV_INFO_DEV_PRESENT))) { + fpURP->bRetValue = USB_ATA_TIME_OUT_ERR; + return; + } + // + // Send Start/Stop Unit command to UFI class device only + // + fpURP->bRetValue = USB_SUCCESS; + if(fpDevInfo->bSubClass == SUB_CLASS_UFI) { + wResult = USBMassStartUnitCommand (fpDevInfo); + if (wResult) { + fpURP->bRetValue = USBWrapGetATAErrorCode(fpURP->ApiData.MassReset.dSenseData); + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIReadDevice +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure, it contains the following: +// bDevAddr USB device address of the device +// dStartLBA Starting LBA address +// wNumBlks Number of blocks to read +// wPreSkipSize Number of bytes to skip before +// wPostSkipSize Number of bytes to skip after +// fpBufferPtr Far buffer pointer +// +// Output: fpURPPointer Pointer to the URP structure +// bRetValue Return value +// dSenseData Sense data of the last command +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIReadDevice ( + URP_STRUC *Urp +) +{ + DEV_INFO *DevInfo; + UINT8 DevAddr; + UINT16 Result; + UINT32 Data = 0; + UINT8 OpCode; + + DevAddr = Urp->ApiData.MassRead.DevAddr; + + if (((DevAddr == USB_HOTPLUG_FDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_FDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_HDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_HDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_CDROM_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_CDROM_ENABLED) == FALSE))) { + Urp->bRetValue = USB_ATA_DRIVE_NOT_READY_ERR; + return; + } + + // + // Get the device info structure for the matching device address + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + if ((DevInfo == NULL)|| (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT))) { + Urp->bRetValue = USB_ATA_TIME_OUT_ERR; + return; + } + + //(EIP15037+)> +#if EXTRA_CHECK_DEVICE_READY + // + // Check device ready + // + Data = USBMassCheckDeviceReady(DevInfo); + if (Data) { + Urp->ApiData.MassRead.dSenseData = Data; + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassRead.dSenseData); //(EIP31535) + return; + } +#endif + //<(EIP15037+) + + // + // Issue read command + // + if (Shr64(DevInfo->MaxLba, 32)) { + OpCode = COMMON_READ_16_OPCODE; + } else { + OpCode = COMMON_READ_10_OPCODE; + } + Result = USBMassRWVCommand(DevInfo, OpCode, &Urp->ApiData.MassRead); + //USB_DEBUG(DEBUG_LEVEL_3, " wr(%x):%x %x", DevAddr, Result, Urp->ApiData.MassRead.dSenseData); + if (Result) { + Urp->bRetValue = USB_SUCCESS; + return; + } + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassRead.SenseData); + //USB_DEBUG(DEBUG_LEVEL_3, " er(%x):%x", DevAddr, Urp->bRetValue); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIWriteDevice +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure +// bDevAddr USB device address of the device +// dStartLBA Starting LBA address +// wNumBlks Number of blocks to write +// wPreSkipSize Number of bytes to skip before +// wPostSkipSize Number of bytes to skip after +// fpBufferPtr Far buffer pointer +// +// Output: fpURPPointer Pointer to the URP structure +// bRetValue Return value +// dSenseData Sense data of the last command +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIWriteDevice( + URP_STRUC *Urp +) +{ + DEV_INFO *DevInfo; + UINT8 DevAddr; + UINT16 Result; + UINT32 Data = 0; + UINT8 OpCode; + + DevAddr = Urp->ApiData.MassWrite.DevAddr; + + if (((DevAddr == USB_HOTPLUG_FDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_FDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_HDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_HDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_CDROM_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_CDROM_ENABLED) == FALSE))) { + Urp->bRetValue = USB_ATA_DRIVE_NOT_READY_ERR; + return; + } + + // + // Get the device info structure for the matching device address + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + if((DevInfo == NULL)|| (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT))) { + Urp->bRetValue = USB_ATA_TIME_OUT_ERR; + return; + } +/* + if (!(DevInfo->bLastStatus & USB_MASS_MEDIA_PRESENT)) { + Urp->bRetValue = USB_ATA_NO_MEDIA_ERR; + return; + } +*/ + //(EIP15037+)> +#if EXTRA_CHECK_DEVICE_READY + // + // Check device ready + // + Data = USBMassCheckDeviceReady(DevInfo); + if (Data) { + Urp->ApiData.MassRead.dSenseData = Data; + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassWrite.dSenseData); //(EIP31535) + return; + } +#endif + //<(EIP15037+) + + // + // Issue write command + // + if (Shr64(DevInfo->MaxLba, 32)) { + OpCode = COMMON_WRITE_16_OPCODE; + } else { + OpCode = COMMON_WRITE_10_OPCODE; + } + Result = USBMassRWVCommand(DevInfo, OpCode, &Urp->ApiData.MassWrite); + if (Result) { + Urp->bRetValue = USB_SUCCESS; + return; + } + + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassWrite.SenseData); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIVerifyDevice +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure +// bDevAddr USB device address of the device +// dStartLBA Starting LBA address +// wNumBlks Number of blocks to write +// wPreSkipSize Number of bytes to skip before +// wPostSkipSize Number of bytes to skip after +// fpBufferPtr Far buffer pointer +// +// Output: fpURPPointer Pointer to the URP structure +// bRetValue Return value +// dSenseData Sense data of the last command +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIVerifyDevice( + URP_STRUC *Urp +) +{ + DEV_INFO *DevInfo; + UINT8 DevAddr; + UINT16 Result; + UINT32 Data = 0; + UINT8 OpCode; + + DevAddr = Urp->ApiData.MassVerify.DevAddr; + + if (((DevAddr == USB_HOTPLUG_FDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_FDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_HDD_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_HDD_ENABLED) == FALSE)) || + ((DevAddr == USB_HOTPLUG_CDROM_ADDRESS) && + ((gUsbData->dUSBStateFlag & USB_HOTPLUG_CDROM_ENABLED) == FALSE))) { + Urp->bRetValue = USB_ATA_DRIVE_NOT_READY_ERR; + return; + } + + // + // Get the device info structure for the matching device address + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + if ((DevInfo == NULL)|| (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT))) { + Urp->bRetValue = USB_ATA_TIME_OUT_ERR; + return; + } + //(EIP15037+)> +#if EXTRA_CHECK_DEVICE_READY + // + // Check device ready + // + Data = USBMassCheckDeviceReady(DevInfo); + if (Data) { + Urp->ApiData.MassRead.dSenseData = Data; + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassVerify.dSenseData); //(EIP31535) + return; + } +#endif + //<(EIP15037+) + + // + // Issue write command + // + if (Shr64(DevInfo->MaxLba, 32)) { + OpCode = COMMON_VERIFY_16_OPCODE; + } else { + OpCode = COMMON_VERIFY_10_OPCODE; + } + Result = USBMassRWVCommand(DevInfo, OpCode, &Urp->ApiData.MassVerify); + if (Result) { + Urp->bRetValue = USB_SUCCESS; + return; + } + + Urp->bRetValue = USBWrapGetATAErrorCode(Urp->ApiData.MassVerify.SenseData); + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPIFormatDevice +// +// Description: This function is part of the USB BIOS MASS API. +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue Return value +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPIFormatDevice(URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassAPICommandPassThru +// +// Description: This function is part of the USB BIOS MASS API. This +// function can be used to pass raw command/data sequence to +// the USB mass storage device +// +// Input: fpURPPointer Pointer to the URP structure +// +// Output: bRetValue Return value +// +// Modified: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassAPICommandPassThru (URP_STRUC *fpURP) +{ + UINT8 Result; + MASS_CMD_PASS_THRU *MassCmdPassThru; + EFI_STATUS Status = EFI_SUCCESS; + + MassCmdPassThru = &fpURP->ApiData.MassCmdPassThru; + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + Status = AmiValidateMemoryBuffer((VOID*)MassCmdPassThru->fpCmdBuffer, MassCmdPassThru->wCmdLength); + if (EFI_ERROR(Status)) { + return; + } + Status = AmiValidateMemoryBuffer((VOID*)MassCmdPassThru->fpDataBuffer, MassCmdPassThru->wDataLength); + if (EFI_ERROR(Status)) { + return; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + Result = USBMassCmdPassThru(MassCmdPassThru); + + fpURP->bRetValue = Result; +} + + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBMassAPIAssignDriveNumber +// +// Description: This function is part of the USB BIOS MASS API. This function +// assigns the logical drive device according to the information of the +// mass storage device +// +// Input: fpURPPointer Pointer to the URP structure +// bDevAddr USB device address of the device +// bLogDevNum Logical Drive Number to assign to the device +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBMassAPIAssignDriveNumber (URP_STRUC *fpURP) +{ + fpURP->bRetValue = USB_SUCCESS; // No errors expected after this point +} + + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBMassAPICheckDevStatus +// +// Description: This function is part of the USB BIOS MASS API. This function +// invokes USB Mass Storage API handler to check whether device +// is ready. If called for the first time, this function retrieves +// the mass storage device geometry and fills the corresponding +// fpDevInfo fields. +// +// Input: fpURPPointer Pointer to the URP structure +// fpURP->ApiData.fpDevInfo - pointer to USB device that is +// requested to be checked +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBMassAPICheckDevStatus(URP_STRUC *fpURP) +{ +#if USB_DEV_MASS + UINT32 Result; + DEV_INFO *DevInfo; + EFI_STATUS Status; + + DevInfo = fpURP->ApiData.MassChkDevReady.fpDevInfo; + + Status = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(Status)) { + return; + } + + gCheckUsbApiParameter = FALSE; + + Result = USBMassCheckDeviceReady(fpURP->ApiData.MassChkDevReady.fpDevInfo); + fpURP->bRetValue = (UINT8)Result; +#endif +} + + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_LightenKeyboardLEDs +// +// Description: This function is part of the USB BIOS API. This function +// controls LED state on the connected USB keyboards +// +// Input: fpURP Pointer to the URP structure +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBAPI_LightenKeyboardLEDs(URP_STRUC *fpURP) +{ +#if USB_DEV_KBD + + gCheckUsbApiParameter = FALSE; + + if(fpURP->ApiData.KbLedsData.fpLedMap) { + gUsbData->bUSBKBShiftKeyStatus = 0; + if(((LED_MAP*)fpURP->ApiData.KbLedsData.fpLedMap)->NumLock) { + gUsbData->bUSBKBShiftKeyStatus |= KB_NUM_LOCK_BIT_MASK; + } + if(((LED_MAP*)fpURP->ApiData.KbLedsData.fpLedMap)->CapsLock) { + gUsbData->bUSBKBShiftKeyStatus |= KB_CAPS_LOCK_BIT_MASK; + } + if(((LED_MAP*)fpURP->ApiData.KbLedsData.fpLedMap)->ScrLock) { + gUsbData->bUSBKBShiftKeyStatus |= KB_SCROLL_LOCK_BIT_MASK; + } + } + //USB_DEBUG(DEBUG_LEVEL_3," LEDs: %d\n", gUsbData->bUSBKBShiftKeyStatus); + USBKB_LEDOn(); + + fpURP->bRetValue = USB_SUCCESS; + return; +#else + fpURP->bRetValue = USB_NOT_SUPPORTED; +#endif + +} + +VOID +USBAPI_LightenKeyboardLEDs_Compatible(URP_STRUC *fpURP) +{ + USBAPI_LightenKeyboardLEDs(fpURP); +} + + //(EIP29733+)> +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_KbcAccessControl +// +// Description: This function is part of the USB BIOS API. This function +// is used to control whether KBC access in USB module +// should be blocked or not. +// +// Input: fpURP Pointer to the URP structure +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + + +VOID +UsbKbcAccessControl( + UINT8 ControlSwitch +) +{ + UINT8 Index; + HC_STRUC *HcStruc; +#if USB_RUNTIME_DRIVER_IN_SMM + EFI_STATUS Status = EFI_SUCCESS; + + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + gLockHwSmiHandler = TRUE; + gLockSmiHandler = TRUE; + return; + } +#endif + + gCheckUsbApiParameter = FALSE; + + IsKbcAccessBlocked = (ControlSwitch != 0)? TRUE : FALSE; + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + HcStruc = gUsbData->HcTable[Index]; + if (HcStruc == NULL) { + continue; + } + if (HcStruc->dHCFlag & HC_STATE_RUNNING) { + break; + } + } + + if (Index == gUsbData->HcTableCount) { + return; + } +/* + // + // Check if the USB access in Legacy mode. If it's legacy mode enable/disable + // the Kbcemulation based on the ControlSwitch + // + if(!(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI)) { + + if(IsKbcAccessBlocked) { + if(gEmulationTrap) { + // + // Keyboard access blocked. Disable the Emulation + // + gEmulationTrap->TrapDisable(gEmulationTrap); + } + } else { + if(gEmulationTrap) { + // + // Keyboard access enabled. Enable the KbcEmulation + // + gEmulationTrap->TrapEnable(gEmulationTrap); + } + } + } +*/ + //(EIP48323+)> + //Reflush USB data buffer if intend to disable usb keyboard data throughput. + if (IsKbcAccessBlocked) { + USBKeyRepeat(NULL, 1); // Disable Key repeat + gUsbData->RepeatKey = 0; + + // Clear Legacy USB keyboard buffer + MemFill(gUsbData->aKBCCharacterBufferStart, sizeof(gUsbData->aKBCCharacterBufferStart), 0); + gUsbData->fpKBCCharacterBufferHead = gUsbData->aKBCCharacterBufferStart; + gUsbData->fpKBCCharacterBufferTail = gUsbData->aKBCCharacterBufferStart; + + MemFill(gUsbData->aKBCScanCodeBufferStart, sizeof(gUsbData->aKBCScanCodeBufferStart), 0); + gUsbData->fpKBCScanCodeBufferPtr = gUsbData->aKBCScanCodeBufferStart; + + MemFill(gUsbData->aKBCDeviceIDBufferStart, sizeof(gUsbData->aKBCDeviceIDBufferStart), 0); + MemFill(gUsbData->aKBCShiftKeyStatusBufferStart, sizeof(gUsbData->aKBCShiftKeyStatusBufferStart), 0); + + MemFill(gUsbData->aKBInputBuffer, sizeof(gUsbData->aKBInputBuffer), 0); + } + //<(EIP48323+) +} + + +VOID +USBAPI_KbcAccessControl(URP_STRUC *fpURP) +{ + UsbKbcAccessControl(fpURP->ApiData.KbcControlCode); +} + //<(EIP29733+) +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USB_StopLegacy +// +// Description: This function is part of the USB BIOS API. This function init USB +// legacy support. +// +// Input: fpURP Pointer to the URP structure +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> +VOID +USB_StopLegacy(URP_STRUC *fpURP) +{ + //shutdown device first + UINT8 bIndex; + DEV_INFO *fpDevInfo; + HC_STRUC *fpHCStruc; + + for (bIndex = 1; bIndex < MAX_DEVICES; bIndex ++){ + fpDevInfo = gUsbData->aDevInfoTable +bIndex; + if ((fpDevInfo->Flag & + (DEV_INFO_VALID_STRUC |DEV_INFO_DEV_PRESENT) ) == + (DEV_INFO_VALID_STRUC |DEV_INFO_DEV_PRESENT) ){ + // + fpHCStruc = gUsbData->HcTable[fpDevInfo->bHCNumber - 1]; + // + USB_StopDevice (fpHCStruc, fpDevInfo->bHubDeviceNumber, fpDevInfo->bHubPortNumber); + } + } + + StopControllerType(USB_HC_XHCI); //(EIP57521+) + StopControllerType(USB_HC_EHCI); + StopControllerType(USB_HC_UHCI); + StopControllerType(USB_HC_OHCI); + + //return as success + fpURP->bRetValue = USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USB_StartLegacy +// +// Description: This function is part of the USB BIOS API. This function init USB +// legacy support. +// +// Input: fpURP Pointer to the URP structure +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> +VOID +USB_StartLegacy(URP_STRUC *fpURP) +{ + //(EIP57521)> + gUsbData->bHandOverInProgress = FALSE; + //Start XHCI + StartControllerType(USB_HC_XHCI); + USB_EnumerateRootHubPorts(USB_HC_XHCI); + //Start EHCI + StartControllerType(USB_HC_EHCI); + USB_EnumerateRootHubPorts(USB_HC_EHCI); + //Start UHCI + StartControllerType(USB_HC_UHCI); + USB_EnumerateRootHubPorts(USB_HC_UHCI); + //Start OHCI + StartControllerType(USB_HC_OHCI); + USB_EnumerateRootHubPorts(USB_HC_OHCI); + //<(EIP57521) + //return as success + fpURP->bRetValue = USB_SUCCESS; +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_LegacyControl +// +// Description: This function is part of the USB BIOS API. This function +// is used to shutdown/init USB legacy support. +// +// Input: fpURP Pointer to the URP structure +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> +VOID USBAPI_LegacyControl (URP_STRUC *fpURP) +{ + UINT8 bSubLegacyFunc = fpURP->bSubFunc,i; //(EIP102150+) + UINT8 Count = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); //(EIP102150+) + + gCheckUsbApiParameter = FALSE; + + USB_DEBUG(DEBUG_LEVEL_3, "USBAPI_LegacyControl %d\n", fpURP->bSubFunc); + if(bSubLegacyFunc==STOP_USB_CONTROLLER){ //(EIP43475+)> + USB_StopLegacy (fpURP); + //(EIP102150+)> + for(i = Count; i > 0; i--) + USBKB_DiscardCharacter(&gUsbData->aKBCShiftKeyStatusBufferStart[i-1]); + //<(EIP102150+) + if(gEmulationTrap) + gEmulationTrap->TrapDisable(gEmulationTrap); + } + + if(bSubLegacyFunc==START_USB_CONTROLLER){ + USB_StartLegacy (fpURP); + if(gEmulationTrap) + gEmulationTrap->TrapEnable(gEmulationTrap); + } //<(EIP43475+) + USB_DEBUG(DEBUG_LEVEL_3, "Result %d\n", fpURP->bRetValue); +} + //(EIP74876+)> +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_UsbStopController +// +// Description: This function is part of the USB BIOS API. This function stops +// the USB host controller. +// +// Input: fpURP Pointer to the URP structure +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> +VOID USBAPI_UsbStopController (URP_STRUC *fpURP) +{ + gCheckUsbApiParameter = FALSE; + StopControllerBdf(fpURP->ApiData.HcBusDevFuncNum); +} + //<(EIP74876+) +//----------------------------------------------------- +// +//----------------------------------------------------- +EFI_STATUS USBRT_LegacyControl (VOID *fpURP) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + EFI_STATUS Status = EFI_SUCCESS; + + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + gLockHwSmiHandler = TRUE; + gLockSmiHandler = TRUE; + return EFI_SUCCESS; + } +#endif + // + USBAPI_LegacyControl ((URP_STRUC *)fpURP); + // + return((EFI_STATUS)(((URP_STRUC *)fpURP)->bRetValue)); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_GetDeviceAddress +// +// Description: +// +// Input: +// +// Output: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBAPI_GetDeviceAddress( + URP_STRUC *Urp +) +{ + UINT8 i; + DEV_INFO *DevInfo = NULL; + + for (i = 1; i < MAX_DEVICES; i++) { + if (!(gUsbData->aDevInfoTable[i].Flag & DEV_INFO_VALID_STRUC)) { + continue; + } + if ((gUsbData->aDevInfoTable[i].wVendorId == Urp->ApiData.GetDevAddr.Vid) && + (gUsbData->aDevInfoTable[i].wDeviceId == Urp->ApiData.GetDevAddr.Did)) { + DevInfo = &gUsbData->aDevInfoTable[i]; + } + } + if (DevInfo == NULL) { + Urp->bRetValue = USB_ERROR; + return; + } + + Urp->ApiData.GetDevAddr.DevAddr = DevInfo->bDeviceAddress; + Urp->bRetValue = USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAPI_ExtDriverRequest +// +// Description: +// +// Input: +// +// Output: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBAPI_ExtDriverRequest ( + URP_STRUC *Urp +) +{ + DEV_INFO *DevInfo = NULL; + DEV_DRIVER *DevDriver; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, 0, Urp->ApiData.DevAddr, 0); + if (DevInfo == NULL) { + Urp->bRetValue = USB_ERROR; + return; + } + + DevDriver = UsbFindDeviceDriverEntry(DevInfo->fpDeviceDriver); + + if (DevDriver != NULL) { + DevDriver->pfnDriverRequest(DevInfo, Urp); + } +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USB_StopUnsupportedHc +// +// Description: This routine is called, from host controllers that supports +// OS handover functionality, when OS wants the BIOS to hand-over +// the host controllers to the OS. This routine will stop HC that +// does not support this functionality. +// +// Input: None +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USB_StopUnsupportedHc() +{ + +#if USB_RUNTIME_DRIVER_IN_SMM + UINT8 Index; + HC_STRUC* HcStruc; + EFI_STATUS Status; + + Status = AmiUsbSmmGlobalDataValidation(gUsbData); + + ASSERT_EFI_ERROR(Status); + + if (EFI_ERROR(Status)) { + gLockHwSmiHandler = TRUE; + gLockSmiHandler = TRUE; + return; + } + + USBSB_UninstallTimerHandlers(); + + USB_DEBUG(DEBUG_LEVEL_3, "Stopping all external HCs"); + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + HcStruc = gUsbData->HcTable[Index]; + if (HcStruc == NULL) { + continue; + } + if (HcStruc->HwSmiHandle != NULL) { + continue; + } + if (HcStruc->dHCFlag & HC_STATE_RUNNING) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDStop)(HcStruc); + USB_DEBUG(DEBUG_LEVEL_3, "."); + } + } + + USB_DEBUG(DEBUG_LEVEL_3, "\n"); + +#endif + + if(gUsbData->UsbXhciHandoff) { + StopControllerType(USB_HC_XHCI); + } + if(gUsbData->UsbEhciHandoff) { + gUsbData->bHandOverInProgress = TRUE; + StopControllerType(USB_HC_EHCI); + } + if(gUsbData->UsbOhciHandoff) { + StopControllerType(USB_HC_OHCI); + } +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_ChangeOwner +// +// Description: This function is part of the USB BIOS API. This function +// updates the global variables according to the new owner +// +// Input: fpURP Pointer to the URP structure +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +// Notes: It is a caller responsibility to release the keyboard only if it +// was previously acquired. +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBAPI_ChangeOwner(URP_STRUC *fpURP) +{ +//USB_DEBUG(DEBUG_LEVEL_3, "USBAPI_ChangeOwner.."); + + if(fpURP->ApiData.Owner) { // Changing to Efi driver +//USB_DEBUG(DEBUG_LEVEL_3, "fpURP->ApiData.Owner=%d\n", fpURP->ApiData.Owner); + if(gEmulationTrap) { + gEmulationTrap->TrapDisable(gEmulationTrap); + } + gUsbData->dUSBStateFlag |= USB_FLAG_RUNNING_UNDER_EFI; + } else { // Acquiring - check the current condition first +//USB_DEBUG(DEBUG_LEVEL_3, "fpURP->ApiData.Owner=%d...", fpURP->ApiData.Owner); + if(gEmulationTrap) { + gEmulationTrap->TrapEnable(gEmulationTrap); + } + + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { +//USB_DEBUG(DEBUG_LEVEL_3, "USB_FLAG_RUNNING_UNDER_EFI\n"); + gUsbData->dUSBStateFlag &= ~USB_FLAG_RUNNING_UNDER_EFI; + } else { +//USB_DEBUG(DEBUG_LEVEL_3, "not USB_FLAG_RUNNING_UNDER_EFI\n"); + } + } + fpURP->bRetValue = USB_SUCCESS; +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_HcStartStop +// +// Description: This function is part of the USB BIOS API. This function +// starts/stops the USB host controller. +// +// Input: fpURP Pointer to the URP structure +// +// Output: None +// +// Notes: +// +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID +USBAPI_HcStartStop(URP_STRUC *Urp) +{ + HC_STRUC* HcStruc; + EFI_STATUS Status; + + HcStruc = Urp->ApiData.HcStartStop.HcStruc; + + Status = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(Status)) { + return; + } + + if ((HcStruc->bHCType != USB_HC_UHCI) && (HcStruc->bHCType != USB_HC_OHCI) && + (HcStruc->bHCType != USB_HC_EHCI) && (HcStruc->bHCType != USB_HC_XHCI)) { + return; + } + + gCheckUsbApiParameter = FALSE; + + if (Urp->ApiData.HcStartStop.Start) { + Urp->bRetValue = UsbHcStart(HcStruc); + } else { + Urp->bRetValue = UsbHcStop(HcStruc); + } +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_invoke_in_frame +// +// Description: Invokes procedure passing parameters supplied in the buffer +// It replicates the stack frame so that target procedure can +// see the parameters passed to the stub. +// +// Output: Returns result of invoked proc +// +//------------------------------------------------------------------------------ +//<AMI_PHDR_END> + +// +// The following typedef corresponds to the min width type that can be passed +// into function call as a parameter without padding +// +typedef UINTN STACKWORD; + +UINTN +USBAPI_invoke_in_frame( + VOID* pProc, + VOID* buffer, + UINT32 paramSize ) +{ + STACKWORD* params = (STACKWORD*)buffer; + + switch(paramSize/sizeof(STACKWORD)){ + case 0: return ((STACKWORD (*)())pProc)(); + case 1: return ((STACKWORD (*)(STACKWORD))pProc)(params[0]); + case 2: return ((STACKWORD (*)(STACKWORD,STACKWORD))pProc)(params[0], + params[1]); + case 3: return ((STACKWORD (*)(STACKWORD,STACKWORD,STACKWORD))pProc)( + params[0],params[1],params[2]); + case 4: return ((STACKWORD (*)(STACKWORD,STACKWORD,STACKWORD, + STACKWORD))pProc)( + params[0],params[1],params[2],params[3]); + case 5: return ((STACKWORD (*)(STACKWORD,STACKWORD,STACKWORD,STACKWORD, + STACKWORD))pProc)( + params[0],params[1],params[2],params[3],params[4]); + case 6: return ((STACKWORD (*)(STACKWORD,STACKWORD,STACKWORD,STACKWORD, + STACKWORD,STACKWORD))pProc)( + params[0],params[1],params[2],params[3],params[4],params[5]); + case 7: return ((STACKWORD (*)(STACKWORD,STACKWORD,STACKWORD,STACKWORD, + STACKWORD,STACKWORD,STACKWORD))pProc)( + params[0],params[1],params[2],params[3],params[4],params[5], + params[6]); + default: + ASSERT(paramSize/sizeof(STACKWORD) < 4); + return 0; + } +/* kept for reference + __asm { + push ecx + push esi + pushf + //Copy stak frame + std + mov esi, buffer + mov ecx, paramSize + add esi, ecx + sub esi, 4 + shr ecx, 2 +loop1: + lodsd //DWORD PTR ds:edi + push eax + loop loop1 + //Call proc + mov eax, pProc + cld + call eax + //Read return value + mov retVal, eax + + //Restore stack and registers + add esp, paramSize + popf + pop esi + pop ecx + } + return retVal;*/ +} + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_HC_Proc +// +// Description: Bridge to a number of procedures supplied by HC driver +// +// +// Input: fpURP Pointer to the URP structure +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success) +// +// Notes: +// Assumes that buffer has a correct image of the stack that +// corresponding function reads argument from +// Size of the buffer can be biger than actually used. +// +// Following code copies the buffer (some stack frame) into new +// stack frame such that invoked dirver proc can read parametes +// supplied by buffer +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + +VOID USBAPI_HC_Proc(URP_STRUC *fpURP) +{ + VOID* buffer = fpURP->ApiData.HcProc.paramBuffer; + UINT32 paramSize = // align size on DWORD + (fpURP->ApiData.HcProc.paramSize + 3) & ~0x3; + UN_HCD_HEADER* pHdr; + + ASSERT( GET_HCD_INDEX(fpURP->ApiData.HcProc.bHCType) < + sizeof(gUsbData->aHCDriverTable)/sizeof(HCD_HEADER)); + ASSERT( fpURP->bSubFunc < sizeof(pHdr->asArray.proc)/sizeof(VOID*)); + + pHdr = (UN_HCD_HEADER*)(gUsbData->aHCDriverTable + + GET_HCD_INDEX(fpURP->ApiData.HcProc.bHCType)); + fpURP->ApiData.HcProc.retVal = USBAPI_invoke_in_frame( + pHdr->asArray.proc[fpURP->bSubFunc],buffer,paramSize); + fpURP->bRetValue = USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//----------------------------------------------------------------------------- +// Procedure: USBAPI_Core_Proc +// +// Description: Bridge to a number of procedures supplied by Core proc table +// +// Input: fpURP Pointer to the URP structure +// +// Output: Return code USB_ERROR - Failure, USB_SUCCESS - Success +// +// Notes: +// Assumes that buffer has a correct image of the stack that +// corresponding function reads argument from +// Size of the buffer can be biger than actually used. +// +// Following code copies the buffer (some stack frame) into new +// stack frame such that invoked proc can read parametes +// supplied by buffer +//------------------------------------------------------------------------------; +//<AMI_PHDR_END> + + +VOID* core_proc_table[] = { + USB_GetDescriptor, + USB_ReConfigDevice, + USB_ReConfigDevice2, + UsbAllocDevInfo, + prepareForLegacyOS, + USB_ResetAndReconfigDev, + USB_DevDriverDisconnect, +// USB_GetDataPtr, +// MemCopy, + }; + +VOID USBAPI_Core_Proc(URP_STRUC *fpURP) +{ + VOID* buffer = fpURP->ApiData.CoreProc.paramBuffer; + UINT32 paramSize = // align size on DWORD + (fpURP->ApiData.CoreProc.paramSize + 3) & ~0x3; + + ASSERT( fpURP->bSubFunc < COUNTOF(core_proc_table)); + + fpURP->ApiData.CoreProc.retVal = USBAPI_invoke_in_frame( + core_proc_table[fpURP->bSubFunc],buffer,paramSize); + + fpURP->bRetValue = USB_SUCCESS; +} + + +//---------------------------------------------------------------------------- +// USB API Procedures Ends +//---------------------------------------------------------------------------- + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBWrapGetATAError +// +// Description: This routine converts the sense data information into +// ATAPI error code +// +// Input: dSenseData Sense data obtained from the device +// +// Output: BYTE - ATAPI error code +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 USBWrapGetATAErrorCode (UINT32 dSenseData) +{ + UINT8 sc = (UINT8)dSenseData; // Sense code + UINT8 asc = (UINT8)(dSenseData >> 16); // Additional Sense Code (ASC) + UINT8 ascq = (UINT8)(dSenseData >> 8); // Additional Sense Code Qualifier (ASCQ) + + if (ascq == 0x28) return USB_ATA_DRIVE_NOT_READY_ERR; + if (sc == 7) return USB_ATA_WRITE_PROTECT_ERR; + if ((asc == 0x80) && (ascq == 0x80)) return USB_ATA_TIME_OUT_ERR; + if (ascq == 0x18) return USB_ATA_DATA_CORRECTED_ERR; + if ((ascq==6) && (asc == 0)) return USB_ATA_MARK_NOT_FOUND_ERR; + if ((ascq==0x3a) && (asc == 0)) return USB_ATA_NO_MEDIA_ERR; + if ((ascq==0x11) && (asc == 0)) return USB_ATA_READ_ERR; + if ((ascq==0x11) && (asc == 6)) return USB_ATA_UNCORRECTABLE_ERR; + if (ascq==0x30) return USB_ATA_BAD_SECTOR_ERR; + if ((ascq<0x20) || (ascq>0x26)) return USB_ATA_GENERAL_FAILURE; + + return USB_ATA_PARAMETER_FAILED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBWrap_GetnthDeviceInfoStructure +// +// Description: This routine finds the 'n'th device's DeviceInfo entry. +// +// Input: bDevNumber Device number (1-based) +// +// Output: DeviceInfo structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBWrap_GetnthDeviceInfoStructure(UINT8 bDevNumber) +{ + return &gUsbData->aDevInfoTable[bDevNumber]; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBWrap_GetDeviceCount +// +// Description: This routine searches through the device entry table +// and returns number of active USB devices configured +// by the BIOS. +// +// Input: fpURPPointer Pointer to the URP +// +// Output: Following fields in the URP are modified +// CkPresence.bNumBootDev Number of USB boot devices found +// CkPresence.bNumKeyboards Number of USB keyboards present +// CkPresence.bNumMice Number of USB mice present +// CkPresence.bNumHubs Number of USB hubs present +// CkPresence.bNumStorage Number of USB storage devices present +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBWrap_GetDeviceCount(URP_STRUC *fpURP) +{ + DEV_INFO *fpDevInfo; + UINT8 i; + + for (i=1; i<MAX_DEVICES; i++) { + fpDevInfo = &gUsbData->aDevInfoTable[i]; + + if ( (fpDevInfo->Flag & DEV_INFO_VALID_STRUC) && + (fpDevInfo->Flag & DEV_INFO_DEV_PRESENT)) { + fpURP->ApiData.CkPresence.bNumBootDev++; + + switch (fpDevInfo->bDeviceType) { + case BIOS_DEV_TYPE_HID: + if (fpDevInfo->HidDevType & HID_DEV_TYPE_KEYBOARD) { + fpURP->ApiData.CkPresence.bNumKeyboards++; + } + if (fpDevInfo->HidDevType & HID_DEV_TYPE_MOUSE) { + fpURP->ApiData.CkPresence.bNumMice++; + } + if (fpDevInfo->HidDevType & HID_DEV_TYPE_POINT) { + fpURP->ApiData.CkPresence.bNumPoint++; + } + break; + //<(EIP84455+) + case BIOS_DEV_TYPE_HUB: + fpURP->ApiData.CkPresence.bNumHubs++; + break; + case BIOS_DEV_TYPE_STORAGE: + fpURP->ApiData.CkPresence.bNumStorage++; + break; + case BIOS_DEV_TYPE_SECURITY: + break; + } + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: MemFill +// +// Description: This routine fills the given memory range with the given value. +// +// Input: +// fpPtr - Pointer to the memory region to fill. +// wSize - Size in bytes of the area to be filled. +// Value - Byte value to fill the given range with. +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +MemFill ( + UINT8* fpPtr, + UINT32 dSize, + UINT8 Value) +{ + UINT32 dCount; + + if (fpPtr) { // Check for pointer validity + for(dCount = 0; dCount < dSize; dCount++) { + fpPtr[dCount] = Value; + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: MemCopy +// +// Description: This routine copies data from source to destination. +// +// Input: +// fpSrc - Pointer to the source. +// fpDest - Pointer to the destination. +// wSize - Number of bytes to copy. +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +MemCopy ( + UINT8* fpSrc, + UINT8* fpDest, + UINT32 dSize) +{ + UINT32 dCount; + + // + // Check for pointer validity + // + if ((fpSrc) && (fpDest)) { + for(dCount = 0; dCount < dSize; dCount++) { + fpDest[dCount] = fpSrc[dCount]; + } + } +} + + +UINTN DevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!EfiIsDevicePathEnd (DevicePath)) { + DevicePath = EfiNextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL); +} + + +EFI_DEVICE_PATH_PROTOCOL * +AppendDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *Src1, + IN EFI_DEVICE_PATH_PROTOCOL *Src2 + ) +{ + EFI_STATUS Status; + UINTN Size; + UINTN Size1; + UINTN Size2; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; + EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; + + // + // Allocate space for the combined device path. It only has one end node of + // length EFI_DEVICE_PATH_PROTOCOL + // + Size1 = DevicePathSize (Src1); + Size2 = DevicePathSize (Src2); + Size = Size1 + Size2; + + if (Size1 != 0 && Size2 != 0) { + Size -= sizeof(EFI_DEVICE_PATH_PROTOCOL); + } + + Status = gBS->AllocatePool (EfiBootServicesData, Size, (VOID **)&NewDevicePath); + + if (EFI_ERROR(Status)) { + return NULL; + } + + gBS->CopyMem (NewDevicePath, Src1, Size1); + + // + // Over write Src1 EndNode and do the copy + // + if (Size1 != 0) { + SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath + (Size1 - sizeof(EFI_DEVICE_PATH_PROTOCOL))); + } + else { + SecondDevicePath = NewDevicePath; + } + gBS->CopyMem (SecondDevicePath, Src2, Size2); + return NewDevicePath; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/amiusb.dxs b/Core/EM/usb/rt/amiusb.dxs new file mode 100644 index 0000000..170a6ef --- /dev/null +++ b/Core/EM/usb/rt/amiusb.dxs @@ -0,0 +1,44 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +#include <token.h> +#if USB_RUNTIME_DRIVER_IN_SMM +#include <Protocol/SmmBase.h> +#include <Protocol/SmmSwDispatch.h> +#endif +#include <Protocol/PciRootBridgeIo.h> +#include <Protocol/AmiUsbController.h> + +DEPENDENCY_START + EFI_USB_PROTOCOL_GUID AND +#if USB_RUNTIME_DRIVER_IN_SMM + EFI_SMM_BASE_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH_PROTOCOL_GUID AND +#endif + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID +DEPENDENCY_END + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/amiusb.h b/Core/EM/usb/rt/amiusb.h new file mode 100644 index 0000000..accb29f --- /dev/null +++ b/Core/EM/usb/rt/amiusb.h @@ -0,0 +1,437 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/amiusb.h 40 10/16/16 10:15p Wilsonlee $ +// +// $Revision: 40 $ +// +// $Date: 10/16/16 10:15p $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/rt/amiusb.h $ +// +// 40 10/16/16 10:15p 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 +// +// 39 3/02/16 9:44p 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 +// +// 38 9/01/15 10:18p Wilsonlee +// [TAG] EIP235482 +// [Category] Improvement +// [Description] Select this alternate setting for multiple TTs hubs. +// [Files] usbhub.c, usb.c, amiusb.h, usbdef.h +// +// 37 4/10/15 3:09a 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 +// +// 36 3/08/15 10:51p Wilsonlee +// [TAG] EIP207774 +// [Category] Improvement +// [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and +// clear it if we don't start any HC. +// [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h +// +// 35 4/29/14 8:14p Wilsonlee +// [TAG] EIP163828 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The mouses stop more than 4 seconds during TP 0xB4 when +// power on several times. +// [RootCause] The device sometime doesn't respond the set report +// command. +// [Solution] Change the timeout of set report command to 100 ms. +// [Files] syskbc.c, sysnokbc.c, usbhid.c, amiusb.h +// +// 34 1/23/13 5:14a Ryanchou +// [TAG] EIP111280 +// [Category] Improvement +// [Description] Add USB APIs for external driver. +// [Files] amiusb.c, amiusb.h, usbdef.h +// +// 33 11/10/12 6:43a 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 +// +// 32 9/28/12 2:36a 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 +// +// 31 8/29/12 8:40a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 30 8/07/12 9:40p Wilsonlee +// [TAG] EIP96366 +// [Category] New Feature +// [Description] Add the token "DEFAULT_USB_EMUL6064_OPTION" that +// control the default value of the I/O port 60h/64h emulation support +// option. +// [Files] usb.sd, usb.sdl, amiusb.c, amiusb.h +// +// 29 5/04/12 6:44a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 28 1/13/12 4:29a Ryanchou +// [TAG] EIP47348 +// [Category] New Feature +// [Description] Support for USB Port Reset function. +// [Files] amiusb.c, amiusb.h, amiusbhc.c, uhci.c, usb.c, usbbus.c, +// usbbus.h, usbmass.c +// +// 27 11/08/11 8:25a Wilsonlee +// [TAG] EIP74876 +// [Category] New Feature +// [Description] Add USB API for shutdown single USB controller. +// [Files] amiusb.c, amiusb.h, usb.c, usbdef.h, uhcd.c, uhcd.h, +// AmiUsbController.h +// +// 26 7/12/11 8:16a 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 +// +// 25 4/06/11 3:30a Tonylo +// [TAG] EIP57354 +// [Category] Improvement +// [Description] Core 4.6.5.0 compliant. UEFI 2.3 and PI 1.x support. +// +// 24 3/29/11 10:21a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 23 11/22/10 8:45a Ryanchou +// [TAG] EIP48064 +// [Category] Improvement +// [Description] The SB template implemented elink +// AcpiEnableCallbackList, the XHCI/EHCI hand off function should be +// invoked via the elink AcpiEnableCallbackList. +// [Files] amidef.h, amiusb.c, amiusb.dxs, amiusb.h, +// AmiUsbController.h, usb.sdl, usbrt.mak, usbsb.c +// +// 22 7/15/10 4:43a Tonylo +// EIP15489 - Add USB HandOff function for shurdown/init USB legacy +// through USB API function. +// +// 21 4/02/10 9:00a Olegi +// +// 20 3/19/10 10:06a Olegi +// +// 19 3/11/10 9:17a Olegi +// +// 18 2/27/10 12:01p Olegi +// +// 17 1/27/10 4:38p Olegi +// +// 16 12/23/09 11:59a Olegi +// +// 15 12/22/09 9:02a Olegi +// +// 14 11/24/09 11:34a Olegi +// EIP#29733 - BIOS adds an USB API (Block KBC Access) +// +// 13 11/13/09 9:14a Olegi +// +// 12 10/30/09 5:48p Olegi +// +// 11 10/02/09 10:50a Olegi +// Code cleanup. +// +// 10 5/16/08 12:03p Olegi +// Compliance with AMI coding standard. +// +// 9 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 7 3/20/06 3:38p Olegi +// Version 8.5 - x64 compatible. +// +// 3 8/05/05 3:38p Andriyn +// Complience with EFI EDK +// +// 2 6/03/05 6:34p Andriyn +// EFI_SMM_USB_DISPATCH_CONTEXT param was added to SMI handlers to comply +// with Aptio framework +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//********************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: AmiUsb.h +// +// Description: AMI UsbRt driver definitions +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#ifndef _EFI_USB_H +#define _EFI_USB_H + +#include "token.h" + +#include <Protocol\DevicePath.h> +#if USB_RUNTIME_DRIVER_IN_SMM +#include <Protocol\SmmBase.h> + //(EIP57354)> +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A) +#include <Protocol\SmmControl2.h> +#else +#include <Protocol\SmmControl.h> +#endif + //<(EIP57354) +#include <Protocol\SmmSwDispatch.h> +#include <Protocol\SmmUSBDispatch.h> +#endif + +#include <Protocol\PciRootBridgeIo.h> +#include <Protocol\AmiUsbController.h> +#include <Protocol\LoadedImage.h> +#include <Protocol\BlockIo.h> +#include <Protocol\PciIo.h> +#include <Protocol\SimplePointer.h> +#include <Protocol\SimpleTextIn.h> +#include <Protocol\ComponentName.h> +#include <Protocol\DriverBinding.h> +#include <Protocol\FirmwareVolume.h > +#include <Protocol\UsbPolicy.h> +#include <Protocol\Emul6064Kbdinput.h> +#include <Protocol\Emul6064MsInput.h> +#include <Protocol\Emul6064Trap.h> +#include "usbdef.h" + +EFI_STATUS +USBDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + + +#if USB_RUNTIME_DRIVER_IN_SMM +VOID +USBSWSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +UhciHWSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +OhciHWSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +EhciHWSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_USB_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +XhciHwSmiHandler ( + IN EFI_HANDLE DispatchHandle, + IN VOID *DispatchContext + ); +#endif + +VOID UsbApiHandler(VOID*); +EFI_STATUS InstallUsbProtocols(VOID); + +VOID +Emul6064TrapCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS UsbInstallHwSmiHandler(HC_STRUC*); + +UINT8 ByteReadIO (UINT16); +VOID ByteWriteIO (UINT16, UINT8); +UINT32 ReadPCIConfig(UINT16, UINT8); +VOID WordWritePCIConfig(UINT16, UINT8, UINT16); +UINT32 DwordReadMem(UINT32, UINT16); +VOID USBAPI_CheckPresence(URP_STRUC*); // API 00h +VOID USBAPI_Start(URP_STRUC*); // API 20h +VOID USBAPI_Stop(URP_STRUC*); // API 21h +VOID USBAPI_DisableInterrupts(URP_STRUC*); // API 22h +VOID USBAPI_EnableInterrupts(URP_STRUC*); // API 23h +VOID USBAPI_MoveDataArea(URP_STRUC*); // API 24h +VOID USBAPI_GetDeviceInfo(URP_STRUC*); // API 25h +VOID USBAPI_CheckDevicePresence(URP_STRUC*); // API 26h +VOID USBAPI_MassDeviceRequest(URP_STRUC*); // API 27h +VOID USBAPI_PowerManageUSB(URP_STRUC*); // API 28h +VOID USBAPI_PrepareForOS(URP_STRUC*); // API 29h +VOID USBAPI_SecureInterface(URP_STRUC*); // API 2Ah +VOID USBAPI_LightenKeyboardLEDs(URP_STRUC*); // API 2Bh +VOID USBAPI_ChangeOwner(URP_STRUC*); // API 2Ch +VOID USBAPI_HC_Proc(URP_STRUC*); // API 2Dh +VOID USBAPI_Core_Proc(URP_STRUC*); // API 2eh +VOID USBAPI_LightenKeyboardLEDs_Compatible(URP_STRUC*); // API 2Fh +VOID USBAPI_KbcAccessControl(URP_STRUC*); // API 30h //(EIP29733+) +VOID USBAPI_LegacyControl(URP_STRUC*); // API 31h // +VOID USBAPI_GetDeviceAddress(URP_STRUC*); // API 32h +VOID USBAPI_ExtDriverRequest(URP_STRUC*); // API 33h +VOID USBAPI_CCIDRequest(URP_STRUC*); // API 34h +VOID USBAPI_UsbStopController(URP_STRUC*); // API 35h //(EIP74876+) +VOID USBAPI_HcStartStop(URP_STRUC *Urp); // API 36h + +VOID USBMassAPIGetDeviceInformation(URP_STRUC*); // USB Mass API Sub-Func 00h +VOID USBMassAPIGetDeviceGeometry(URP_STRUC*); // USB Mass API Sub-Func 01h +VOID USBMassAPIResetDevice(URP_STRUC*); // USB Mass API Sub-Func 02h +VOID USBMassAPIReadDevice(URP_STRUC*); // USB Mass API Sub-Func 03h +VOID USBMassAPIWriteDevice(URP_STRUC*); // USB Mass API Sub-Func 04h +VOID USBMassAPIVerifyDevice(URP_STRUC*); // USB Mass API Sub-Func 05h +VOID USBMassAPIFormatDevice(URP_STRUC*); // USB Mass API Sub-Func 06h +VOID USBMassAPICommandPassThru(URP_STRUC*); // USB Mass API Sub-Func 07h +VOID USBMassAPIAssignDriveNumber(URP_STRUC*); // USB BIOS API function 08h +VOID USBMassAPICheckDevStatus(URP_STRUC*); // USB BIOS API function 09h +VOID USBMassAPIGetDevStatus(URP_STRUC*); // USB BIOS API function 0Ah +VOID USBMassAPIGetDeviceParameters(URP_STRUC*); // USB BIOS API function 0Bh + +DEV_INFO* USBWrap_GetnthDeviceInfoStructure(UINT8); +VOID USBWrap_GetDeviceCount(URP_STRUC*); +UINT8 USBWrapGetATAErrorCode(UINT32); +UINT16 USBMassRWVCommand(DEV_INFO*, UINT8, VOID*); +UINT8* USB_GetDescriptor(HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT8, UINT8); +UINT8 UsbSetInterface(HC_STRUC*, DEV_INFO*, UINT8); + +UINT32 USB_ReConfigDevice(HC_STRUC*, DEV_INFO*); +UINT32 USB_ReConfigDevice2(HC_STRUC*, DEV_INFO*, CNFG_DESC*, INTRF_DESC*); +DEV_INFO* UsbAllocDevInfo(); +VOID prepareForLegacyOS(); +UINT32 USB_ResetAndReconfigDev(HC_STRUC*, DEV_INFO*); +UINT32 USB_DevDriverDisconnect(HC_STRUC*, DEV_INFO*); +VOID USBKB_LEDOn(); + + +EFI_DEVICE_PATH_PROTOCOL *AppendDevicePath (EFI_DEVICE_PATH_PROTOCOL*, EFI_DEVICE_PATH_PROTOCOL*); + +UINT8 USB_StartHostControllers(USB_GLOBAL_DATA*); +UINT8 USB_StopHostControllers(USB_GLOBAL_DATA*); +EFI_STATUS InitializeUsbGlobalData(VOID); +UINT8 UsbHcStart(HC_STRUC*); +UINT8 UsbHcStop(HC_STRUC*); +VOID FixedDelay(UINTN); +DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +UINT8 USBMassGetDeviceInfo(MASS_GET_DEV_INFO*); +UINT8 USBMassGetDeviceGeometry(MASS_GET_DEV_GEO*); + +UINT16 USBMassStartUnitCommand (DEV_INFO*); +UINT8 USBMassCmdPassThru (MASS_CMD_PASS_THRU*); +UINT8 USBMassGetDeviceStatus (MASS_GET_DEV_STATUS*); +UINT32 USBMassCheckDeviceReady(DEV_INFO*); +MASS_INQUIRY *USBMassGetDeviceParameters(DEV_INFO*); +VOID InitSysKbc(EFI_EMUL6064KBDINPUT_PROTOCOL**, EFI_EMUL6064MSINPUT_PROTOCOL**); +EFI_STATUS InSmmFunction(EFI_HANDLE, EFI_SYSTEM_TABLE*); +VOID UsbPeriodicEvent(); +DEV_INFO* USB_DetectNewDevice(HC_STRUC*, UINT8, UINT8, UINT8); +UINT8 USB_EnableEndpointsDummy (HC_STRUC*, DEV_INFO*, UINT8*); +UINT8 USB_InitDeviceDataDummy (HC_STRUC*,DEV_INFO*,UINT8,UINT8**); +UINT8 USB_DeinitDeviceDataDummy (HC_STRUC*,DEV_INFO*); +VOID* USB_MemAlloc(UINT16); +UINT8 USB_MemFree(VOID*, UINT16); +UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +VOID UsbKbcAccessControl(UINT8); +EFI_STATUS USBRT_LegacyControl (VOID *fpURP); +VOID USB_StopUnsupportedHc(); +UINT8 UsbControlTransfer(HC_STRUC*, DEV_INFO*, DEV_REQ, UINT16, VOID*); +UINT8 UsbInterruptTransfer(HC_STRUC*, DEV_INFO*, UINT8, UINT16, VOID*, UINT16, UINT16); +VOID CheckBiosOwnedHc(VOID); +DEV_DRIVER* UsbFindDeviceDriverEntry(DEV_DRIVER*); + +#endif + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/amiusbrtCCID.h b/Core/EM/usb/rt/amiusbrtCCID.h new file mode 100644 index 0000000..1a70891 --- /dev/null +++ b/Core/EM/usb/rt/amiusbrtCCID.h @@ -0,0 +1,836 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/rt/amiusbrtCCID.h 3 4/10/15 3:08a Wilsonlee $ +// +// $Revision: 3 $ +// +// $Date: 4/10/15 3:08a $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/rt/amiusbrtCCID.h $ +// +// 3 4/10/15 3:08a 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 +// +// 2 5/02/12 1:59a 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 +// +// 1 7/12/11 8:17a 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: AmiUsbrtCCID.h +// +// Description: AMI Usb CCID driver definitions +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#ifndef _EFI_CCID_RT_H +#define _EFI_CCID_RT_H + +#include "efi.h" +#include "token.h" +#include <AmiDxeLib.h> + +//CCID APIs +#define USB_CCID_SMARTCLASSDESCRIPTOR 0x000 +#define USB_CCID_ATR 0x001 +#define USB_CCID_POWERUP_SLOT 0x002 +#define USB_CCID_POWERDOWN_SLOT 0x003 +#define USB_CCID_GET_SLOT_STATUS 0x004 +#define USB_CCID_XFRBLOCK 0x005 +#define USB_CCID_GET_PARAMETERS 0x006 + +typedef struct _ICC_DEVICE ICC_DEVICE; +typedef struct _SMARTCLASS_DESC SMARTCLASS_DESC; +typedef struct _ATR_DATA ATR_DATA; +typedef struct _DEV_INFO DEV_INFO; +typedef struct _HC_STRUC HC_STRUC; +typedef struct _URP_STRUC URP_STRUC; + +#pragma pack(push, 1) + +#define BASE_CLASS_CCID_STORAGE 0x0B // SMART device class +#define SUB_CLASS_CCID 0x00 // SubClass +#define PROTOCOL_CCID 0x00 // Interface Protocol +#define DESC_TYPE_SMART_CARD 0x21 // Smart Card Descriptor (Type 21h) + + +#define MAX_ATR_LENGTH 32 +// ATR data dequence is T0, TA1, TB1, TC1, TD1, TA2, TB2, TC2, TD2, TA3... etcs + +// +// equates for bVoltageSupport +// +#define AUTO_VOLT 0x00 +#define VOLT_5 0x01 +#define VOLT_3 0x02 +#define VOLT_18 0x04 + + +// +// equates for dwFeatures +// +#define AUTO_PARAMETER_CONFIG 0x02 +#define AUTO_ACTIVATION_OF_ICC 0x04 +#define AUTO_ACTIVATION_VOLT_SELECTION 0x08 +#define AUTO_ICC_CLOCK_FREQ 0x10 +#define AUTO_BAUD_RATE_SELECTION 0x20 +#define AUTO_PPS_NEGOTIATION_CCID 0x40 +#define AUTO_PPS_NEGOTIATION_ACTIVE 0x80 +#define STOP_CLOCK_MODE 0x100 +#define NAD_OTHER_THAN_00 0x200 +#define AUTO_IFSD_EXCHANGE 0x400 +#define CHARACTER_LEVEL_EXCHANGE 0x00000 +#define TDPU_LEVEL_EXCHANGE 0x10000 +#define SHORT_ADPU_LEVEL_EXCHANGE 0x20000 +#define EXT_ADPU_LEVEL_EXCHANGE 0x40000 + +#define PC_TO_RDR_ICCPOWERON 0x62 +#define PC_TO_RDR_ICCPOWEROFF 0x63 +#define PC_TO_RDR_GETSLOTSTATUS 0x65 +#define PC_TO_RDR_XFRBLOCK 0x6F +#define PC_TO_RDR_GETPARAMETERS 0x6C +#define PC_TO_RDR_RESETPARAMETERS 0x6D +#define PC_TO_RDR_SETPARAMETERS 0x61 +#define PC_TO_RDR_ESCAPE 0x6B +#define PC_TO_RDR_ICCCLOCK 0x6E +#define PC_TO_RDR_T0APDU 0x6A +#define PC_TO_RDR_SECURE 0x69 +#define PC_TO_RDR_MECHANICAL 0x71 +#define PC_TO_RDR_ABORT 0x72 +#define PC_TO_RDR_SETDATARATEANDCLOCK 0x73 + + +#define RDR_TO_PC_DATABLOCK 0x80 +#define RDR_TO_PC_SLOTSTATUS 0x81 +#define RDR_TO_PC_PARAMETERS 0x82 +#define RDR_TO_PC_ESCAPE 0x83 +#define RDR_TO_PC_DATARATEANDCLOCK 0x84 + +#define RDR_TO_PC_NOTIFYSLOTCHANGE 0x50 +#define RDR_TO_PC_HARDWAREERROR 0x51 +// +// BIT definition for ConfiguredStatus +// +#define ICCPRESENT 0x01 +#define VOLTAGEAPPLIED 0x02 +#define BAUDRATEPROGRAMMED 0x04 +#define ATRDATAPRESENT 0x08 +#define CONFIGFAILED 0x80 + +#define IBLOCK 0x00 +#define RBLOCK 0x80 +#define SBLOCK 0xC0 + + + +//CCID Class specific request +#define CCID_CLASS_SPECIFIC_ABORT (0x01 << 8) | USB_REQ_TYPE_DEVICE | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE +#define CCID_CLASS_SPECIFIC_GET_CLOCK_FREQUENCIES (0x02 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE +#define CCID_CLASS_SPECIFIC_GET_DATA_RATES (0x03 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE + +typedef enum { + T0_PROTOCOL, + T1_PROTOCOL +} TRANSMISSION_PROTOCOL; + +//I-Block information +#define NSBIT 0x40 +#define MBIT 0x20 + +// S-Block Information +#define RESYNCH_REQUEST 0xC0 +#define IFS_REQUEST 0xC1 +#define ABORT_REQUEST 0xC2 +#define WTX_REQUEST 0xC3 + +#define WTX_RESPONSE 0xE3 +#define ABORT_RESPONSE 0xE2 +#define IFS_RESPONSE 0xE1 +#define RESYNCH_RESPONSE 0xE0 + + +#define I_BLOCK_MATCH 0x01 +#define I_BLOCK_RESEND 0x02 + +#define SEND_R_BLOCK_0 0x03 +#define SEND_R_BLOCK_1 0x04 + +#define GET_DATA_T1_CHAR 0x05 + +#define T1_CHAR_CMD_PHASE 0x06 +#define T1_CHAR_DATA_PHASE 0x07 +#define RESEND_BLOCK 0x08 + + + +#define BLOCK_TRANSMISSION_TERMINATE 0xFF +#define BLOCK_TRANSMISION_SUCCESS 0x00 + + +// Time extension Calculation (worst case scenario assumed) + +//1ETU = F/D * 1/f = 2048/1*1/4Mhz = 0.000512sec + +// Use Maximum value for BWI which is 9 and minimum Freq 4Mhz for calculation +//BWT = 11 ETU + (2BWI * 960 * 372/Clock Frequency) = 11ETU + ( 2* 9 * 960* 372/4000000) = 11+1.607040 = 12ETU = 0.00614sec = 6msec + +//WWT = 960 * WI * F / Clock Frequency +// Character Level +//The "waiting time" (see 7.2) shall be: WT =WI x960x Fi/f = 255 * 960 * 2048/4000000 = 125ETU = 0.064sec = 64msec + +#define INITWAITTIME 64 // 64msec worst case assuming T0 + +struct _ATR_DATA { + UINT8 TS; + UINT8 T0; + BOOLEAN TA1Present; + UINT8 TA1; + BOOLEAN TB1Present; + UINT8 TB1; + BOOLEAN TC1Present; + UINT8 TC1; + BOOLEAN TD1Present; + UINT8 TD1; + + BOOLEAN TA2Present; + UINT8 TA2; + BOOLEAN TB2Present; + UINT8 TB2; + BOOLEAN TC2Present; + UINT8 TC2; + BOOLEAN TD2Present; + UINT8 TD2; + + BOOLEAN TD15Present; + UINT8 TD15; + BOOLEAN TA15Present; + UINT8 TA15; + + UINT8 NumberofHystoricalBytes; + +}; + +struct _ICC_DEVICE { + + EFI_HANDLE ChildHandle; + UINT8 Slot; // slot number + UINT8 RawATRData[32]; + ATR_DATA AtrData; // Processed ATR data + UINT8 TransmissionProtocolSupported; // BitMap + UINT8 NumofTransmissionProtocolSupported; // Count 1 based + UINT8 Current; + UINT8 bStatus; // Holds the status of the last cmd + UINT8 bError; // Holds the Slot error value of the last cmd + UINT8 ConfiguredStatus; // See the bit defenitions above ICCPresent etc + + UINT16 etu; // 1etu = F/D * 1/f (Elementary time unit) This will hold the timing in Micro sec + UINT16 GlobalFi; // Clock Rate Conversion Integer + UINT8 GlobalDi; // Baude rate Adjustment + UINT8 GlobalFmax; // Max Frequency + UINT8 TransmissionProtocol; // Higher nibble what is supported, Lower nibble what is selected + + UINT8 ExtraGuardTime; // N = TC1 + UINT8 BWI; // From TB of T=1 + UINT8 CWI; // From TB of T=1 + UINT8 BWT; // Max. Block width time + UINT8 IFSC; // Default Information Filed Size (IFSC) + UINT8 IFSD; // + UINT8 NAD; + + UINT8 EpilogueFields; // First TC for T=1 + + BOOLEAN SpecificMode; // BIT7 set in TA2 + + UINT8 ClassABC; // Updated from T15->TA + UINT8 StopClockSupport; // Updated from T15->TA 00: Not supported, 1 : State L, 2 : State H, 3 : No preference + + UINT8 bClockStatus; // PlaceHolder for Clockstatus from the last RDR_to_PC_SlotStatus cmd + UINT8 bChainParameter; // PlaceHolder for ChainParameter from the last RDR_to_PC_DataBlock + + // This structure should be same as RDR_TO_PC_PARAMETERS_T1_STRUC. Don't add or remove the next 8 bytes + UINT8 bProtocolNum; // PlaceHolder for bProtocolNum from RDR_to_PC_Parameters + UINT8 bmFindIndex; + UINT8 bmTCCKST; + UINT8 bGuardTime; + UINT8 bWaitingInteger; + UINT8 bClockStop; + UINT8 bIFSC; + UINT8 nNadValue; + //End + + // From GetDataRateAndClockFrequency + UINT32 dwClockFrequency; + UINT32 dwDataRate; + + UINT32 WTwaittime; // (in ETU units) Based on T0 BWT/WWT time will be updated once ATR data is available + UINT32 WaitTime; // Final Wait time used in msec + + // Information stored for TDPU transmission + UINT8 NaSInterface; // This holds the last N(S) value transmitted. + UINT8 NaSCard; // This holds the last N(S) received from card + UINT8 RBlockCounter; + UINT8 bIFSD; // Max. size of the information field of blocks that can be received by the interface device. + BOOLEAN Chaining; // Indicates M bit is set or not + + BOOLEAN T1CharCmdDataPhase; // TRUE for Cmd Phase/False for Data Phase + + DLINK ICCDeviceLink; // Linked to ICCDeviceList + +}; + +struct _SMARTCLASS_DESC{ + UINT8 bDescLength; + UINT8 bDescType; + UINT16 bcdCCID; + UINT8 bMaxSlotIndex; + UINT8 bVoltageSupport; + UINT32 dwProtocols; + UINT32 dwDefaultClock; + UINT32 dwMaximumClock; + UINT8 bNumClockSupported; + UINT32 dwDataRate; + UINT32 dwMaxDataRate; + UINT8 bNumDataRatesSupported; + UINT32 dwMaxIFSD; + UINT32 dwSynchProtocols; + UINT32 dwMechanical; + UINT32 dwFeatures; + UINT32 dwMaxCCIDMessageLength; + UINT8 bClassGetResponse; + UINT8 bClassEnvelope; + UINT16 wLcdLayout; + UINT8 bPINSupport; + UINT8 bMaxCCIDBusySlots; +}; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bPowerSlot; + UINT16 abRFU; +} PC_TO_RDR_ICCPOWERON_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_ICCPOWEROFF_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_GETSLOT_STATUS_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bBWI; + UINT16 wLevelParameter; +} PC_TO_RDR_XFRBLOCK_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_GETPARAMETERS_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_RESETPARAMETERS_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bProtocolNum; + UINT8 abRFU[2]; + UINT8 bmFindDindex; + UINT8 bmTCCKST0; + UINT8 bGuardTimeT0; + UINT8 bWaitingIntergerT0; + UINT8 bClockStop; +} PC_TO_RDR_SETPARAMETERS_T0_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bProtocolNum; + UINT8 abRFU[2]; + UINT8 bmFindDindex; + UINT8 bmTCCKST1; + UINT8 bGuardTimeT1; + UINT8 bWaitingIntergersT1; + UINT8 bClockStop; + UINT8 bIFSC; + UINT8 bNadValue; +} PC_TO_RDR_SETPARAMETERS_T1_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_ESCAPE_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bClockCommand; + UINT8 abRFU[2]; +} PC_TO_RDR_ICCCLOCK_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bmChanges; + UINT8 bClassGetResponse; + UINT8 bClassEnvelope; +} PC_TO_RDR_T0APDU_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bBWI; + UINT16 wLevelParameter; +} PC_TO_RDR_SECURE_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bFunction; + UINT8 abRFU[2]; +} PC_TO_RDR_MECHANICAL_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; +} PC_TO_RDR_ABORT_STRUC; + + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 abRFU[3]; + UINT32 dwCloclFrequency; + UINT32 dwDataRate; +} PC_TO_RDR_SETDATARATEANDCLOCKFREQUENCY_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; // Size of abData + UINT8 bSlot; + UINT8 bSeq; + UINT8 bStatus; + UINT8 bError; + UINT8 Data; // Usage depends on diffeent Message type +} RDR_HEADER; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; // Size of abData + UINT8 bSlot; + UINT8 bSeq; + UINT8 bStatus; + UINT8 bError; + UINT8 bChainParameter; +} RDR_TO_PC_DATABLOCK_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; + UINT8 bSlot; + UINT8 bSeq; + UINT8 bStatus; + UINT8 bError; + UINT8 bClockStatus; +} RDR_TO_PC_SLOTSTATUS_STRUC; + +typedef struct { + UINT8 bmFindDindex; + UINT8 bmTCCKST0; + UINT8 bGuardTimeT0; + UINT8 bWaitingIntergerT0; + UINT8 bClockStop; +} PROTOCOL_DATA_T0; + +typedef struct { + UINT8 bmFindDindex; + UINT8 bmTCCKST1; + UINT8 bGuardTimeT1; + UINT8 bWaitingIntergersT1; + UINT8 bClockStop; + UINT8 bIFSC; + UINT8 bNadValue; +} PROTOCOL_DATA_T1; + +typedef struct { + RDR_HEADER Header; + PROTOCOL_DATA_T0 ProtocolData; +} RDR_TO_PC_PARAMETERS_T0_STRUC; + +typedef struct { + RDR_HEADER Header; + PROTOCOL_DATA_T1 ProtocolData; +} RDR_TO_PC_PARAMETERS_T1_STRUC; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; // Size of abData + UINT8 bSlot; + UINT8 bSeq; + UINT8 bStatus; + UINT8 bError; + UINT8 bRFU; +} RDR_TO_PC_ESCAPE_STATUS; + +typedef struct { + UINT8 bMessageType; + UINT32 dwLength; // Should be 8 + UINT8 bSlot; + UINT8 bSeq; + UINT8 bStatus; + UINT8 bError; + UINT8 bRFU; + UINT32 dwClockFrequency; + UINT32 dwDataRate; +} RDR_TO_PC_DATARATEANDCLOCKFREQUENCY_STRUC; + +#pragma pack(pop) + +VOID +USBCCIDInitialize( + VOID +); + +UINT8 +USBCCIDCheckForDevice ( + DEV_INFO *fpDevInfo, + UINT8 bBaseClass, + UINT8 bSubClass, + UINT8 bProtocol +); + +UINT8 +USBCCIDDisconnectDevice ( + DEV_INFO *fpDevInfo +); + +DEV_INFO* +USBCCIDConfigureDevice ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 *fpDesc, + UINT16 wStart, + UINT16 wEnd +); + +UINT32 +USBCCIDIssueBulkTransfer ( + DEV_INFO* fpDevInfo, + UINT8 bXferDir, + UINT8* fpCmdBuffer, + UINT32 dSize +); + +UINT32 +USBCCIDIssueControlTransfer( + DEV_INFO* fpDevInfo, + UINT16 wRequest, + UINT16 wIndex, + UINT16 wValue, + UINT8 *fpBuffer, + UINT16 wLength +); + +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 +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 +); + +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 +); + +EFI_STATUS +TxRxT1TDPUChar ( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice, + IN UINT32 CmdLength, + IN UINT8 *CmdBuffer, + IN UINT8 ISBlock, + OUT UINT32 *ResponseLength, + OUT UINT8 *ResponseBuffer +); + +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 +PCToRDRGetSlotStatus( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice +); + +EFI_STATUS +RDRToPCSlotStatus( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice +); + +EFI_STATUS +PCToRDRGetParameters( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice +); + +EFI_STATUS +RDRToPCParameters( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice +); + +EFI_STATUS +RDRToPCDataBlock( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice, + IN OUT UINT32 *dwLength, + OUT UINT8 *Buffer + +); + +EFI_STATUS +ICCInsertEvent( + DEV_INFO *fpDevInfo, + UINT8 Slot +); + +EFI_STATUS +ICCRemovalEvent( + IN DEV_INFO *fpDevInfo, + IN UINT8 Slot +); + +VOID +ICC_SmiQueuePut( + IN VOID *d +); + +VOID +PrintPCParameters( + IN UINT8 *Data +); + +TRANSMISSION_PROTOCOL GetDefaultProtocol ( + IN ICC_DEVICE *fpICCDevice +); + +VOID +CalculateLRCChecksum ( + IN UINT8 *BlockFrame, + IN UINT32 BlockFrameLength +); + +EFI_STATUS +PCtoRDRIccPowerOff( + IN DEV_INFO *fpDevInfo, + IN ICC_DEVICE *fpICCDevice +); + +VOID +PrintDescriptorInformation ( + SMARTCLASS_DESC *fpCCIDDesc +); + +VOID +USBCCIDAPISmartClassDescriptorSMM ( + IN OUT URP_STRUC *fpURP +); + +VOID +USBCCIDAPIAtrSMM ( + IN OUT URP_STRUC *fpURP +); + +VOID +USBCCIDAPIPowerupSlotSMM ( + IN OUT URP_STRUC *fpURP + +); + +VOID +USBCCIDAPIPowerDownSlotSMM ( + IN OUT URP_STRUC *fpURP + +); + +VOID +USBCCIDAPIGetSlotStatusSMM ( + IN OUT URP_STRUC *fpURP +); + +VOID +USBCCIDAPIXfrBlockSMM ( + IN OUT URP_STRUC *fpURP +); + +VOID +USBCCIDAPIGetParametersSMM ( + IN OUT URP_STRUC *fpURP + +); + +ICC_DEVICE* +GetICCDevice( + DEV_INFO *fpDevInfo, + UINT8 Slot +); + +VOID +PrintTimingInfo( + ICC_DEVICE *fpICCDevice +); + +VOID +PrintATRData( + UINT8 *ATRData +); + +UINT8 +FindNumberOfTs( + UINT8 Data +); + +VOID +MemFill ( + UINT8* fpPtr, + UINT32 dSize, + UINT8 Value +); + + +VOID +MemCopy ( + UINT8* fpSrc, + UINT8* fpDest, + UINT32 dSize +); + +#endif + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/debug.c b/Core/EM/usb/rt/debug.c new file mode 100644 index 0000000..32e6798 --- /dev/null +++ b/Core/EM/usb/rt/debug.c @@ -0,0 +1,110 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/debug.c 7 5/16/08 12:01p Olegi $ +// +// $Revision: 7 $ +// +// $Date: 5/16/08 12:01p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/debug.c $ +// +// 7 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 6 3/20/07 12:18p Olegi +// +// 4 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 8/26/05 12:25p Andriyn +// Simulate Mouse Sampling rate by disabling Mouse Polling (reduce USB +// SMI# generation) +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Debug.c +// +// Description: AMI USB Debug output implementation routnes +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: PrintDebugMessage (variable param) +// +// Description: This routine prints the debug message +// +// Parameters: Variable +// +// Output: Status: SUCCESS = Success +// FAILURE = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +RETCODE +PrintDebugMsg( + int MsgLevel, + char * Message, ...) +{ + VA_LIST ArgList; + + VA_START(ArgList, Message); + + if ((MsgLevel == 0) || + ((MsgLevel <= TopDebugLevel) && + (MsgLevel >= BottomDebugLevel))) + { +#if DEBUG_SWITCH == 1 + EfiDebugVPrint(EFI_D_ERROR, Message, ArgList); +#endif + } + + VA_END(ArgList); + + return SUCCESS; +} +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/ehci.c b/Core/EM/usb/rt/ehci.c new file mode 100644 index 0000000..faeb5fa --- /dev/null +++ b/Core/EM/usb/rt/ehci.c @@ -0,0 +1,5916 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/ehci.c 152 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 152 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ehci.c $ +// +// 152 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 +// +// 151 7/22/16 3:50a 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 +// +// 150 7/07/16 2:08a Wilsonlee +// [TAG] EIP268836 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The system will loop in USB runtime module during IPMI are +// resetting USB controller. +// [RootCause] Qh->dLinkPointer is invalid after device is disconnected. +// [Solution] Check if Qh is changed after we process it. +// [Files] ehci.c +// +// 149 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 +// +// 148 3/14/16 10:21p Wilsonlee +// [TAG] EIP257506 +// [Category] Improvement +// [Description] Add USB_KEYREPEAT_INTERVAL token to change the key +// repeat interval. +// [Files] usb.sdl, xhci.h, usbkbd.h, uhci.c, ohci.c, ehci.c +// +// 147 3/02/16 9:42p 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 +// +// 146 9/06/15 10:05p Wilsonlee +// +// 145 7/24/15 4:41a Wilsonlee +// [TAG] EIP226493 +// [Category] Improvement +// [Description] Block to process periodic list to prevent that we might +// send the wrong command sequences to the same device. +// [Files] usbmass.c, ehci.c, xhci.h, xhci.c, usbdef.h, uhcd.c +// +// 144 5/26/15 10:48p Wilsonlee +// [TAG] EIP219177 +// [Category] Improvement +// [Description] Fixed static code analysis issues in Usb module. +// [Files] UsbInt13.c, ehci.c, usbbus.c +// +// 143 4/10/15 3:11a 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 +// +// 142 4/07/15 4:36a Wilsonlee +// [TAG] EIP212211 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB transfer speed is slower than before in EHCI. +// [RootCause] If we parse through the all periodic list, the +// performance is low in AMD platforms. +// [Solution] Only parse the first entry through +// MAX_SPLIT_PERIODIC_NUMBER. +// [Files] ehci.c +// +// 141 3/22/15 11:12p Wilsonlee +// [TAG] EIP206118 +// [Category] Improvement +// [Description] Remove dead loop in EHCIStartAsyncSchedule and +// EHCIStopAsyncSchedule functions. +// [Files] ehci.c +// +// 140 3/08/15 10:50p Wilsonlee +// [TAG] EIP207774 +// [Category] Improvement +// [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and +// clear it if we don't start any HC. +// [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h +// +// 139 2/24/15 9:53p Wilsonlee +// [TAG] EIP205784 +// [Category] Improvement +// [Description] Don't read Periodic Frame List Base Address Register if +// the controller doesn't support periodic schedule. +// [Files] ehci.c +// +// 138 2/24/15 9:35p Wilsonlee +// [TAG] EIP206118 +// [Category] Improvement +// [Description] Remove dead loop in EHCIStartAsyncSchedule and +// EHCIStopAsyncSchedule functions. +// [Files] ehci.c +// +// 137 1/22/15 10:19p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 136 12/21/14 9:30p Wilsonlee +// [TAG] EIP194553 +// [Category] Improvement +// [Description] Realtek 8111EP EHCI controller workaround, this +// controller doesn't work if the buffer address isn't DWORD alignment +// (current offset of qTD). Provide the workaround to locate DWORD +// alignment buffer. +// [Files] ehci.c +// +// 135 11/24/14 12:50a Wilsonlee +// [TAG] EIP185972 +// [Category] Improvement +// [Description] To acquire more bandwidth, a dynamically transfer queue +// allocation mechanism is required. +// [Files] ehci.c, usbdef.h +// +// 134 5/01/14 3:56a Ryanchou +// [TAG] EIP162589 +// [Category] Improvement +// [Description] Do not register external controller as key repeat +// controller. +// [Files] ehci.c, ohci.c, uhci.c +// +// 133 4/30/14 6:12a 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 +// +// 132 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 131 2/26/14 1:56a 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 +// +// 130 11/26/13 4:15a Ryanchou +// [TAG] EIP142940 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB keyboard cannot work if token USB_RUNTIME_DRIVER_IN_SMM +// is disabled. +// [RootCause] The variable Qh in EhciAddPeriodicQh() does not have +// initialize value. +// [Solution] Check if the value of variable Qh is valid first. +// [Files] ehci.c +// +// 129 9/05/13 12:14a Wilsonlee +// [TAG] EIP135237 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB can't work when turn on AMIDEBUG_RX_SUPPORT. +// [RootCause] EHCI_PORT_CHANGE_DETECT bit isn't set when turn on +// AMIDEBUG_RX_SUPPORT. +// [Solution] Ignore the EHCI_PORT_CHANGE_DETECT bit to check the root +// hub ports at first time. +// [Files] ehci.c +// +// 128 7/26/13 2:33a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 127 7/22/13 10:31p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 126 6/26/13 2:18a Roberthsu +// [TAG] EIP122174 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Usb keyboard can not work.When special usb key insert +// [RootCause] This keyboard detect connect status signal during this +// key initial. So port detect not service. +// [Solution] Clear port detect status before check port change. +// [Files] ehci.c +// +// 125 6/02/13 11:41p Wilsonlee +// [TAG] EIP123235 +// [Category] Improvement +// [Description] Stop the usb host controller at ExitBootService if it +// is an extend card or it doesn't support HW SMI. +// [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, +// uhcd.c +// +// 124 5/12/13 11:52p Wilsonlee +// Set the data toggle to QH at EHCI_ActivatePolling and +// EHCI_InterruptTransfer. +// +// 123 5/02/13 2:35a Wilsonlee +// [TAG] EIP121790 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The usb keyboard doesn't work fine behind usb 2.0 hub. +// [RootCause] Teradici ehci controlle doesn't preserves DT bit in the +// qTD. +// [Solution] Don't set "Data toggle control" bit and check DT bit in +// the queue head. +// [Files] ehci.c +// +// 122 5/01/13 9:54p Wilsonlee +// [TAG] EIP121643 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Cannot detect the usb floppy. +// [RootCause] This device doesn't return data when we sned +// get-config-descriptor command. +// [Solution] We retry to send get-config-descriptor command if there is +// no data. +// [Files] usb.c, ehci.c +// +// 121 4/18/13 1:02p Ryanchou +// Add Teradici USB controller support. +// +// 120 4/16/13 6:44a Ryanchou +// [TAG] EIP118912 +// [Category] Improvement +// [Description] Add VIA VT6212 EHCI controller support. +// [Files] ehci.c, uhci.c, usbdef.h, uhcd.c +// +// 119 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 +// +// 118 3/18/13 4:47a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 117 2/24/13 8:59p Wilsonlee +// [TAG] EIP113541 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] System hangs at checkpoint 0xA2 when Win8 resume from S4. +// [RootCause] The "HCHalted" bit and "Port Change Detect" bit are set +// when the system S4 resume to Win8 OS. +// [Solution] We need to clear the interrupt status even if the +// "HCHalted" bit is set. +// [Files] ehci.c, ohci.c, uhci.c +// +// 116 1/24/13 3:20a Roberthsu +// [TAG] EIP111010 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Touch panel button not work. +// [RootCause] Device write wrong buffer. +// [Solution] Clear bufferptr in pollingtdcallback. +// [Files] ehci.c +// +// 115 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 114 12/24/12 5:06a Ryanchou +// [TAG] EIP103031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hans when loading QNX 6.5.0 +// [RootCause] The EHCI port detect change SMI is generated after +// ownership change to OS. +// [Solution] Clear the SMI enable bits and status bits even the +// controller is OS owned. +// [Files] ehci.c, ohci.c +// +// 113 12/06/12 12:38a Wilsonlee +// [TAG] EIP103186 +// [Category] Improvement +// [Description] Handle the error case "MEMIO was disabled" in USB +// driver. +// [Files] uhci.c, ohci.c, ehci.c, xhci.c +// +// 112 11/24/12 9:00p Wilsonlee +// [TAG] EIP107513 +// [Category] Improvement +// [Description] Stop periodic schedule before removing QH. +// [Files] ehci.c +// +// 111 11/13/12 7:11a Wilsonlee +// [TAG] EIP82553 +// [Category] New Feature +// [Description] Support usb S5 wake up function for XHCI. +// [Files] usb.c, ehci.c, ohci.c, xhci.c, xhci.h +// +// 110 11/10/12 6:40a 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 +// +// 109 10/26/12 8:58a Roberthsu +// [TAG] EIP102781 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] After update usb module, DebugRx hang at UHCD.Start(). +// [RootCause] dHCSParams vaule not vaild. +// [Solution] Function EhciIsolateDebugPort move after variable +// dHCSParams fill. +// [Files] ehci.c +// +// 108 10/25/12 4:28a Wilsonlee +// [TAG] EIP103051 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] With USB3.0 flash on USB3.0 port and set to USB mode2, +// system will hang at post code 0x92 during the first cold boot after +// connecting AC power. +// [RootCause] This device connects to ehci first and it was +// disconnected after we reset the port. +// [Solution] We need to check the connect status after resetting the +// port. +// [Files] ehci.c +// +// 107 10/25/12 4:15a Wilsonlee +// [TAG] EIP82354 +// [Category] New Feature +// [Description] Support usb S5 wake up function for OHCI. +// [Files] usb.c, ehci.c, ohci.c +// +// 106 9/28/12 2:37a 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 +// +// 105 8/29/12 9:32a Ryanchou +// [TAG] EIP88307 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Key repeat cannot be stopped if the keyboard is connected +// to xHCI. +// [RootCause] Periodic timer SMI stop generating when USB SMI and +// periodic timer SMI is generated frequently. +// [Solution] Reduces the key repeat rate to avoid this issue. +// [Files] ehci.c, usb.c, usb.sdl +// +// 104 8/29/12 8:16a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 103 5/04/12 6:38a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 102 5/03/12 5:59a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 101 5/03/12 5:17a Ryanchou +// [TAG] EIP88085 +// [Category] Improvement +// [Description] Added 1 ms delay after port reset completed. +// [Files] ehci.c +// +// 100 5/03/12 5:08a Ryanchou +// [TAG] EIP83361 +// [Category] New Feature +// [Description] Added "USB 2.0 Controller Mode" setup item. +// [Files] ehci.c, usb.sd, usb.sdl, usb.uni, usbdef.h, UsbPolicy.h, +// usbport.c +// +// 99 4/10/12 10:12p Wilsonlee +// [TAG] EIP84790 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB IO PROTOCOL under XHCI issue +// [RootCause] The DevMiscInfo is NULL. +// [Solution] Fill the DevMiscInfo for the xhci controller. +// [Files] ehci.c, xhci.c, amiusbhc.c +// +// 98 4/05/12 7:42a Wilsonlee +// [TAG] EIP86001 +// [Category] Improvement +// [Description] Free the chunk of memory allocated using the +// USBMem_Alloc call when we didn't use it. +// [Files] usbhid.c, ehci.c +// +// 97 3/20/12 10:34p Wilsonlee +// [TAG] EIP83295 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System will hang at B2 when do S3/S4 long run test or DOS +// reboot test. +// [RootCause] It causes the stack problem when we call +// IsUSBKeyboardBufferEmpty function. +// [Solution] Change to use pointer as parameter to +// IsUSBKeyboardBufferEmpty function. +// [Files] efiusbkb.c, efisubkb.h, usbmass.c, ehci.c +// +// 96 2/16/12 9:04p Wilsonlee +// [TAG] EIP82307 +// [Category] Improvement +// [Description] Port routing route to EHCI when EHCI initialization. +// [Files] ehci.c +// +// 95 1/16/12 1:05a Wilsonlee +// [TAG] EIP81030 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] System hangs randomly at POST. +// [RootCause] This is EIP71067 side effect. It uses error memory +// address. +// [Solution] The change used the correct memory address. +// [Files] ehci.c +// +// 94 12/23/11 8:39p Wilsonlee +// [TAG] EIP71067 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] SMI Timeout with USB FD and USB Flash Memory +// [RootCause] It uses the same area to bulk transfer on EHCI/ +// [Solution] It uses local QH and QTD for each control and bulk +// transfer on EHCI +// [Files] ehci.c +// +// 93 11/09/11 3:30a Ryanchou +// [TAG] EIP73692 +// [Category] Improvement +// [Description] Implement the ownership change mechanism for PCH. +// [Files] ehci.c, usbdef.h, usbsrc.sdl +// +// 92 11/08/11 1:57a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 91 9/09/11 5:06a Roberthsu +// [TAG] EIP68865 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] VIA plug in USB KB/MS cause system hang +// [RootCause] After release port.Ehci_line_status still exist. +// [Solution] Release port owner when connect status change. +// [Files] ehci.c +// +// 90 8/08/11 6:58a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 89 8/08/11 5:14a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 88 7/19/11 5:16a Ryanchou +// [TAG] EIP64498 +// [Category] New Feature +// [Description] Implement EHCI key repeat function. +// [Files] ehci.c, ehci.h, usb.c, usbdef.h +// +// 87 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 86 7/12/11 8:09a 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 +// +// 85 7/01/11 3:18a Ryanchou +// [TAG] EIP61385 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] USB devices can't detected. +// [RootCause] This is the side effect of EIP59663, the port status +// doesn't reflect connect status and connect status change. +// [Solution] Add 100 us delay. +// [Files] ehci.c, uhci.c +// +// 84 6/21/11 10:26a Ryanchou +// [TAG] EIP60632 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Generic Usb Redirection caused system hung at checkpoint A2 +// [RootCause] The timeout value is zero, and the bulk transfer never +// completed. +// [Solution] UEFI spec defines "If Timeout is 0, then the +// caller must wait for the function to be completed until +// EFI_SUCCESS or EFI_DEVICE_ERROR is returned". +// [Files] ehci.c +// +// 83 6/21/11 10:00a Ryanchou +// [TAG] EIP62708 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Unexpected USB SMI after USB Owner Ship Change +// [RootCause] Unexpected USB SMI causes an expection after USB onwer +// ship change +// executed. +// [Solution] Check if HC is still under BIOS control before service USB +// interrupts. +// [Files] ehci.c +// +// 82 6/21/11 9:55a Ryanchou +// [TAG] EIP59663 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Plug USB WLAN device may causes OHCI malfunction. +// [RootCause] The devices have to connect to OHCI first, or it can't be +// configured. +// [Solution] Port routing route to EHCI after OHCI initialization. +// [Files] ehci.c, ohci.c +// +// 81 5/30/11 8:41a Ryanchou +// [TAG] EIP61030 +// [Category] Improvement +// [Description] PORTSC register should be read before write the +// register, and set the USB_PORT_STAT_DEV_CONNECT_CHANGED flag if +// bIgnoreConnectStsChng is set and connect status change bit is not set. +// [Files] ehci.c +// +// 80 5/03/11 10:10a Ryanchou +// [TAG] EIP54283 +// [Category] Improvement +// [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery +// endpoint halt. +// [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c +// +// 79 5/03/11 8:54a Ryanchou +// [TAG] EIP58108 +// [Category] Improvement +// [Description] Disable port only if this port is enabled and remove +// the delay after port disable. +// [Files] ehci.c +// +// 78 4/06/11 3:52a Ryanchou +// [TAG] EIP55960 +// [Category] Improvement +// [Description] The Host Controller must halt within 16 micro-frames +// after software clears the Run bit. +// [Files] ehci.c, elib.c +// +// 77 4/06/11 1:32a Ryanchou +// [TAG] EIP54782 +// [Category] Improvement +// [Description] Change polling data size of HID devices to max packet +// size of interrupt endpoint. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c +// +// 76 3/29/11 10:47p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 75 3/29/11 10:10a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 74 2/17/11 8:03a Ryanchou +// [TAG] EIP48592 +// [Category] Improvement +// [Description] Add timeout check in EHCIStartPeriodicSchedule and +// EHCIStopPeriodicSchedule to avoid the endless loop. +// [Files] ehci.c +// +// 73 11/11/10 11:32p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 72 10/20/10 1:02a Ryanchou +// EIP45689: Uncomment code in EHCI_GetRootHubStatus that wait 20ms for +// host controller could report accurate port status properly. +// +// 71 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 70 8/09/10 1:29a Ryanchou +// EIP41187: Set CERR field as 3 in a qTD, and service all interrupts +// after transfer complete. +// +// 69 7/13/10 7:16a Ryanchou +// EIP38356: Implement shutdown USB legacy support in ACPI enable call. +// +// 68 6/10/10 3:07a Ryanchou +// EIP38648: Enable USB Error SMI. +// +// 67 3/11/10 9:42a Olegi +// +// 66 3/02/10 4:51p Olegi +// Undone changes in EHCI_ControlTransfer for EIP32956. +// +// 65 2/27/10 11:59a Olegi +// +// 64 2/26/10 5:14p Olegi +// +// 63 2/08/10 9:59a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 62 1/26/10 10:21a Olegi +// EIP32624: fix Change in InterruptTransfer. +// +// 61 1/04/10 9:20a Olegi +// EIP32956: Polling rate for the keyboards has been changed from 8 ms to +// 32 ms. +// +// 60 12/23/09 11:59a Olegi +// +// 59 12/09/09 1:07p Davidd +// Corrected the USBkeyboard can't hotplug in DOS issue. (EIP 26477) +// +// 58 12/09/09 12:33p Olegi +// Code cleanup. +// +// 57 11/30/09 6:13p Olegi +// +// 56 11/25/09 1:48p Olegi +// +// 55 11/18/09 7:10p Olegi +// Restored EHCIResetHC call in Start function that was removed for +// EIP23479. This EIP is resolved differently. +// +// 54 10/30/09 5:47p Olegi +// +// 52 10/15/09 3:12p Olegi +// EIP24437: Change EHCI_ProcessInterrupt to handle the HC error bit in +// the periodic TDs. +// +// 51 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 50 9/17/09 11:13a Olegi +// Change in ProcessInterrupt: +// There may be a condition in which OS changes the base address before +// owning the semaphore and SMI may occur on USB complete or port change +// detect. This may cause SMI storm. Disabling SMI will not affect +// anything since we dont have any control over it. +// +// 49 9/15/09 10:28a Olegi +// EIP26685: uncommented code in EHCI_Stop that disconnects all devices. +// +// 48 9/15/09 10:21a Olegi +// Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. +// +// 47 8/28/09 11:49a Olegi +// EIP#25760: change the sequence of periodic schedule and async schedule +// execution. +// +// 46 7/02/09 10:06a Olegi +// Fix for EIP#23479: while processing EHCI change ownership request, we +// will not reset the HC. This change will preserve the state of +// EHCI_CONFIGURE register (MMIO reg 60h, bit0) so the controller +// switching will not occur. +// +// 45 6/24/09 2:35p Olegi +// Correction in EHCIInitializePeriodicSchedule(); fix for the EIP#23498. +// +// 44 6/02/09 2:47p Olegi +// +// 43 5/22/09 1:48p Olegi +// Bugfix in EHCI_GetRootHubStatus. +// +// 42 5/15/09 6:16p Olegi +// Skip enabling PortPower for the ports that already have it enabled. +// Saves ~100ms per controller. +// +// 41 3/19/09 4:56p Olegi +// +// 40 3/09/09 8:49a Olegi +// Modified EHCIProgramLegacyRegisters, EIP#20084. +// +// 39 2/20/09 2:30p Olegi +// Modifications in ProcessOwnerShipChangeSMI function, EIP#19525 +// +// 38 2/18/09 10:10a Olegi +// Fast unplug/insert fix, EIP#19206. +// +// 37 2/17/09 4:01p Olegi +// +// 36 1/16/09 4:11p Olegi +// Added dependency on MAX_BULK_DATA in EHCI_BulkTransfer. +// +// 35 11/06/08 1:59p Olegi +// Change in EHCI_EnumeratePorts that will avoid unnecessary delays during +// enabling the port power. +// +// 34 10/06/08 3:33p Olegi +// EHCI change ownership testing in DOS fix (EIP#14855). +// +// 33 9/02/08 10:28a Olegi +// EIP14855 bugfix: change ownership request is not processed properly in +// case of multiple controllers of the same type. +// +// 32 8/08/08 2:37p Olegi +// Fix in EHCI_GetRootHubStatus that did not report connection properly in +// some cases. +// +// 31 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 30 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 29 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 28 3/20/07 12:21p Olegi +// +// 27 1/25/07 10:19a Olegi +// +// 26 12/28/06 5:27p Olegi +// +// 25 12/26/06 10:23a Olegi +// +// 24 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 23 12/20/06 2:30p Olegi +// +// 22 11/21/06 5:35p Olegi +// +// 21 11/16/06 6:10p Olegi +// DebugPort support initial changes. +// +// 19 10/19/06 5:16p Andriyn +// +// 18 10/12/06 9:37p Andriyn +// Fix: unexpected plug-off hangs with endless TIMEOUTs +// +// 17 10/12/06 9:07p Andriyn +// +// 16 7/21/06 6:34p Olegi +// +// 15 7/19/06 3:53p Olegi +// Bugfix in EHCIRemoveQH routine. +// +// 14 6/09/06 10:29a Olegi +// USB_FLAG_ENABLE_BEEP_MESSAGE flag is reset while handling change of the +// controller ownership. +// +// 13 5/22/06 9:08a Olegi +// ASYNC_BELL_SUPPORT modifications +// +// 12 5/16/06 11:23a Olegi +// +// 11 5/16/06 11:19a Olegi +// Removed DisconnectDevice call from EHCI_Stop +// +// 10 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 9 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 8 3/16/06 2:34p Olegi +// +// 7 3/06/06 6:25p Olegi +// +// 6 1/11/06 11:52a Olegi +// +// 5 11/29/05 12:33p Andriyn +// +// 4 6/03/05 6:09p Olegi +// HW SMI registration change. +// +// 3 5/19/05 8:07p Olegi +// Aptio changes in driver 8.1 implementation. +// +// 2 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Ehci.h +// +// Description: AMI USB EHCI support +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +UINT8 EHCI_Start (HC_STRUC*); +UINT8 EHCI_Stop (HC_STRUC*); +UINT8 EHCI_EnumeratePorts (HC_STRUC*); +UINT8 EHCI_DisableInterrupts (HC_STRUC*); +UINT8 EHCI_EnableInterrupts (HC_STRUC*); +UINT8 EHCI_ProcessInterrupt(HC_STRUC*); +UINT8 EHCI_GetRootHubStatus (HC_STRUC*,UINT8, BOOLEAN); +UINT8 EHCI_DisableRootHub (HC_STRUC*,UINT8); +UINT8 EHCI_EnableRootHub (HC_STRUC*,UINT8); +UINT16 EHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); +UINT32 EHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); +UINT16 EHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); +UINT8 EHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 EHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 EHCI_DisableKeyRepeat (HC_STRUC*); +UINT8 EHCI_EnableKeyRepeat (HC_STRUC*); +UINT8 EHCI_ResetRootHub (HC_STRUC*,UINT8); +UINT8 EHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) + +UINT8 EHCIResetHC(HC_STRUC*); +UINT8 EHCIInitializePeriodicSchedule(HC_STRUC*, UINT32); +UINT8 EHCIProgramLegacyRegisters(HC_STRUC*, UINT8); +UINT8 EHCIStartAsyncSchedule(HC_STRUC*); +UINT8 EHCIStopAsyncSchedule(HC_STRUC*); +UINT8 EHCIStartPeriodicSchedule(HC_STRUC*); +UINT8 EHCIStopPeriodicSchedule(HC_STRUC*); +UINT8 EHCIProcessQH(HC_STRUC*, EHCI_QH*); +VOID EHCIProcessPeriodicList(HC_STRUC*); +VOID EHCIInitializeQueueHead (EHCI_QH*); +VOID EHCISetQTDBufferPointers(EHCI_QTD*, UINT8*, UINT32); +UINT16 EHCIWaitForTransferComplete(HC_STRUC*, EHCI_QH*,DEV_INFO* ); +UINT8 EhciAddPeriodicQh(HC_STRUC*,EHCI_QH*); +UINT8 EhciRemovePeriodicQh(HC_STRUC*,EHCI_QH*); +VOID ProcessOwnerShipChangeSMI(HC_STRUC*); +VOID ProcessSmiChangeToEHCD(HC_STRUC*); +VOID ProcessSmiChangeToBIOS(HC_STRUC*); +UINT8 EHCIGetLegacySupportOffset(HC_STRUC*, UINT16); +VOID EHCIRemoveQHFromAsyncList(HC_STRUC*, EHCI_QH*); +UINT8 EhciPollingTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 EhciRepeatTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); + +UINT32 ReadPCIConfig(UINT16, UINT8); +VOID WordWritePCIConfig(UINT16, UINT8, UINT16); +VOID DwordWritePCIConfig(UINT16, UINT8, UINT32); + +UINT32 DwordReadMem(UINT32, UINT16); +VOID DwordWriteMem(UINT32, UINT16, UINT32); +VOID DwordResetMem(UINT32, UINT16, UINT32); +VOID DwordSetMem(UINT32, UINT16, UINT32); + +UINT32 EhciReadPciReg(HC_STRUC*, UINT32); +VOID EhciWritePciReg(HC_STRUC*, UINT32, UINT32); +UINT32 EhciReadHcMem(HC_STRUC*, UINT32); +VOID EhciWriteHcMem(HC_STRUC*, UINT32, UINT32); +UINT32 EhciReadOpReg(HC_STRUC*, UINT32); +VOID EhciWriteOpReg(HC_STRUC*, UINT32, UINT32); +VOID EhciClearOpReg(HC_STRUC*, UINT32, UINT32); +VOID EhciSetOpReg(HC_STRUC*, UINT32, UINT32); +UINT32 EhciReadDebugReg(HC_STRUC*, UINT8, UINT32); +VOID* EhciMemAlloc(HC_STRUC*, UINT16); +VOID EhciMemFree(HC_STRUC*, VOID*, UINT16); +UINT8 EhciDmaMap(HC_STRUC*, UINT8, UINT8*, UINT32, UINT8**, VOID**); +UINT8 EhciDmaUnmap(HC_STRUC*, VOID*); +BOOLEAN EhciIsHalted(HC_STRUC*); +UINT16 EhciTranslateInterval(UINT8, UINT8); + +UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +UINT8 USBLogError(UINT16); +UINT8 UsbGetDataToggle(DEV_INFO*,UINT8); +VOID UsbUpdateDataToggle(DEV_INFO*, UINT8, UINT8); + +VOID USB_InitFrameList (HC_STRUC*, UINT32); +VOID FixedDelay(UINTN); + +VOID* USB_MemAlloc (UINT16); +UINT8 USB_MemFree (VOID _FAR_ *, UINT16); +UINT8 USB_DisconnectDevice (HC_STRUC*, UINT8, UINT8); +DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +UINT8 USB_StopDevice (HC_STRUC*, UINT8, UINT8); +UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); +VOID USBKeyRepeat(HC_STRUC*, UINT8); + +#if USB_DEV_KBD +VOID USBKBDPeriodicInterruptHandler(HC_STRUC*); +#endif + + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_FillHCDEntries (HCD_HEADER *fpHCDHeader) +// +// Description: This function fills the host controller driver +// routine pointers +// +// Parameters: fpHCDHeader Ptr to the host controller header structure +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_FillHCDEntries (HCD_HEADER *fpHCDHeader) +{ + fpHCDHeader->pfnHCDStart = EHCI_Start; + fpHCDHeader->pfnHCDStop = EHCI_Stop; + fpHCDHeader->pfnHCDEnumeratePorts = EHCI_EnumeratePorts; + fpHCDHeader->pfnHCDDisableInterrupts = EHCI_DisableInterrupts; + fpHCDHeader->pfnHCDEnableInterrupts = EHCI_EnableInterrupts; + fpHCDHeader->pfnHCDProcessInterrupt = EHCI_ProcessInterrupt; + fpHCDHeader->pfnHCDGetRootHubStatus = EHCI_GetRootHubStatus; + fpHCDHeader->pfnHCDDisableRootHub = EHCI_DisableRootHub; + fpHCDHeader->pfnHCDEnableRootHub = EHCI_EnableRootHub; + fpHCDHeader->pfnHCDControlTransfer = EHCI_ControlTransfer; + fpHCDHeader->pfnHCDBulkTransfer = EHCI_BulkTransfer; + fpHCDHeader->pfnHCDInterruptTransfer = EHCI_InterruptTransfer; + fpHCDHeader->pfnHCDDeactivatePolling = EHCI_DeactivatePolling; + fpHCDHeader->pfnHCDActivatePolling = EHCI_ActivatePolling; + fpHCDHeader->pfnHCDDisableKeyRepeat = EHCI_DisableKeyRepeat; + fpHCDHeader->pfnHCDEnableKeyRepeat = EHCI_EnableKeyRepeat; + fpHCDHeader->pfnHCDEnableEndpoints = USB_EnableEndpointsDummy; + fpHCDHeader->pfnHCDInitDeviceData = USB_InitDeviceDataDummy; + fpHCDHeader->pfnHCDDeinitDeviceData = USB_DeinitDeviceDataDummy; + fpHCDHeader->pfnHCDResetRootHub = EHCI_ResetRootHub; + fpHCDHeader->pfnHCDClearEndpointState = 0; //(EIP54283+) + fpHCDHeader->pfnHCDGlobalSuspend = EHCI_GlobalSuspend; //(EIP54018+) + + USB_InstallCallBackFunction(EhciRepeatTDCallback); + USB_InstallCallBackFunction(EhciPollingTDCallback); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EhciIsolateDebugPort +// +// Description: This routine locates EHCI debug port and determines whether +// or not the debug port is initialized and being used by other +// agents. If so, the global flag will be set to instruct the +// EHCI runtime routines about debug port presence and prevent +// any unwanted reset/reconfiguration of this port. +// +// Parameters: fpHCStruc Ptr to the host controller structure +// +// Output: fpHCStruc->DebugPort is updated if Debug Port is active on +// this controller; otherwise it will remain 0. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID EhciIsolateDebugPort(HC_STRUC *fpHCStruc) +{ + UINT32 HcSParams = fpHCStruc->dHCSParams; // Host Controller Structural Parameters + UINT8 DebugPortNo; + UINT32 NextCap; + UINT8 DebugPortBarIndex; + UINT16 DebugPortOffset; + + // + // Locate debug port by looking at the PCI capabilities + // + DebugPortNo = (UINT8)((HcSParams & (EHCI_DEBUG_N)) >> 20); + + //ASSERT(DebugPortNo); // No debug port implemented + fpHCStruc->DebugPort = 0; + if (DebugPortNo == 0) return; + + ASSERT(DebugPortNo <= (UINT8)(HcSParams & (EHCI_N_PORTS))); // Invalid debug port number + if (DebugPortNo > (UINT8)(HcSParams & (EHCI_N_PORTS))) return; + + // + // Check whether device implements Capability list that starts at register 0x34 + // + if (!(EhciReadPciReg(fpHCStruc, 4) & BIT20)) { + //ASSERT(FALSE); // Capabilities list is not implemented + return; + } + + // + // Find the beginning of Debug Port registers block + // + for (NextCap = EhciReadPciReg(fpHCStruc, 0x34); + (UINT8)NextCap > 0; + ) + { + NextCap = EhciReadPciReg(fpHCStruc, (UINT8)NextCap); + if ((UINT8)NextCap == 0xA) break; // Debug port capability found + NextCap >>= 8; + } + if ((UINT8)NextCap == 0) { + //ASSERT(FALSE); // Debug capabilities not found + return; + } + DebugPortBarIndex = (UINT8)((NextCap >> 29) - 1); + DebugPortOffset = (UINT16)((NextCap >> 16) & 0x1FFF); + ASSERT(DebugPortBarIndex >= 0 && DebugPortBarIndex <= 5); // Wrong BAR + if (!(DebugPortBarIndex >= 0 && DebugPortBarIndex <= 5)) return; + // + // See whether Debug Port is acquired by other software + // + if (EhciReadDebugReg(fpHCStruc, DebugPortBarIndex, DebugPortOffset) & BIT28) { + fpHCStruc->DebugPort = DebugPortNo; + USB_DEBUG(DEBUG_LEVEL_3, "EHCI HC Debug Port #%d enabled.\n", DebugPortNo); + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_Start +// +// Description: This API function is called to start a EHCI host controller. +// The input to the routine is the pointer to the HC structure +// that defines this host controller +// +// Parameters: fpHCStruc Ptr to the host controller structure +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_Start (HC_STRUC* fpHCStruc) +{ + UINT32 dTemp; +//#if EHCI_ASYNC_BELL_SUPPORT +// EHCI_QH *fpQHAsyncXfer; +//#endif + EHCI_QH *fpQHRepeat = NULL; + EHCI_QTD *fpqTDRepeat = NULL; + UINT32 i; //(EIP55960+) + BOOLEAN SetPortPower = FALSE; + UINT16 PortReg; + EHCI_DESC_PTRS *DescPtr = NULL; + EFI_STATUS EfiStatus = EFI_SUCCESS; + +/* +USB_DEBUG(DEBUG_LEVEL_3, "Enabling MEM/BM for EHCI HC %02X\n", fpHCStruc->wBusDevFuncNum); + + // + // Enable IO access and Bus Mastering + // + WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, 4, BIT1 + BIT2); +*/ + // + // Get memory base address of the HC and store it in the HCStruc + // + fpHCStruc->BaseAddress = EhciReadPciReg(fpHCStruc, USB_MEM_BASE_ADDRESS) & 0xFFFFFFF0; + + USB_DEBUG(DEBUG_LEVEL_3, "EHCI HC Mem Addr: %X\n", fpHCStruc->BaseAddress); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)fpHCStruc->BaseAddress, fpHCStruc->BaseAddressSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Usb Mmio address is invalid, it is in SMRAM\n"); + return USB_ERROR; + } +#endif + // + // Get the number of ports supported by the host controller (Offset 4) + // and store it in HCStruc + // + fpHCStruc->dHCSParams = EhciReadHcMem(fpHCStruc, EHCI_HCSPARAMS); + fpHCStruc->bNumPorts = (UINT8)(fpHCStruc->dHCSParams & EHCI_N_PORTS); + USB_DEBUG(DEBUG_LEVEL_3, "EHCI HC Number of ports: %d\n", fpHCStruc->bNumPorts); + + EhciIsolateDebugPort(fpHCStruc); //(EIP102781) + + // + // Read the Capability Registers Length to find the Offset address for the + // beginning of the operational registers + // + fpHCStruc->bOpRegOffset = (UINT8)EhciReadHcMem(fpHCStruc, EHCI_VERCAPLENGTH); + USB_DEBUG(DEBUG_LEVEL_3, "EHCI HC Operational Registers Offset: %d\n", fpHCStruc->bOpRegOffset); + + // + // Read and store the HCCPARAMS value + // + fpHCStruc->dHCCParams = EhciReadHcMem(fpHCStruc, EHCI_HCCPARAMS); + //USB_DEBUG(DEBUG_LEVEL_3, "EHCI HC HCPARAMS: %x\n", gUsbData->dHCCParams); + + // + // Get PCI register offset for the legacy support in EHCI controller + // and store it in HC_STRUC + // + fpHCStruc->bExtCapPtr = EHCIGetLegacySupportOffset( + fpHCStruc, + fpHCStruc->wBusDevFuncNum); + +#if EHCI_64BIT_DATA_STRUCTURE == 0 + // + // 64bit data structures are not enabled. So check whether this host controller + // needs 64bit data structure or not. + // + if (fpHCStruc->dHCCParams & EHCI_64BIT_CAP) + { + // + // Engineer has to enable the 64bit capability. Post an error message + // + USBLogError(ERRUSB_EHCI_64BIT_DATA_STRUC); + ASSERT(FALSE); + + // + // Connect all ports to the classic host controller + // + EhciClearOpReg(fpHCStruc, EHCI_CONFIGFLAG, BIT0); + return USB_ERROR; + } +#endif + +#if HIDE_USB_HISPEED_SUPPORT_SETUP_QUESTION == 0 + if ((gUsbData->UsbHiSpeedSupport == 0) && ((fpHCStruc->dHCSParams & EHCI_N_CC) != 0)) { + EhciClearOpReg(fpHCStruc, EHCI_CONFIGFLAG, BIT0); + return USB_ERROR; + } +#endif + +//---------------------------------------------------------------------------- +// Note: after this point any access to the operational registers is through +// the macros EHCI_DWORD_READ_MEM and EHCI_DWORD_WRITE_MEM; access to the +// capability registers is through the macro USBPORT_DWORD_READ_MEM and +// there is no macro to write to the registers +//---------------------------------------------------------------------------- + //(EIP55960)> + if ((EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED) == 0) { + // Turn HC off and wait for the Halted bit to get set + EhciClearOpReg(fpHCStruc, EHCI_USBCMD, EHCI_RUNSTOP); + + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if (EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + //while ((DwordReadMem(dMemAddr, EHCI_USBSTS) & EHCI_HCHALTED) == 0) {}; + } + //<(EIP55960) +// /* EIP#23479 + // + // Reset the host controller (HC must be halted) + // + if (EHCIResetHC(fpHCStruc) == USB_ERROR) + { + return USB_ERROR; // HC reset error, error log is updated + } +//*/ + // + // Get the frame list size from the EHCI command register + // + dTemp = EhciReadOpReg(fpHCStruc, EHCI_USBCMD); + dTemp = (dTemp & (BIT2 + BIT3)) >> 2; + + // + // Calculate number of elements in the asynchronous list + // and store the value in the HCStruc + // + switch (dTemp) + { + case 0: fpHCStruc->wAsyncListSize = 1024; + break; + case 1: fpHCStruc->wAsyncListSize = 512; + break; + case 2: fpHCStruc->wAsyncListSize = 256; + break; + case 3: return USB_ERROR; + + } + + USB_DEBUG(DEBUG_LEVEL_3, "EHCI AsyncListSize: %d\n", fpHCStruc->wAsyncListSize); + + // + // Set the max bulk data size + // + fpHCStruc->dMaxBulkDataSize = MAX_EHCI_DATA_SIZE; + + // + // Initialize the frame list pointers + // + USB_InitFrameList (fpHCStruc, EHCI_TERMINATE); + + // + // Write the base address of the Periodic Frame List to the PERIODIC BASE + // register + // + EhciWriteOpReg(fpHCStruc, EHCI_PERIODICLISTBASE, (UINT32)(UINTN)fpHCStruc->fpFrameList); + + // + // Initialize the periodic schedule + // + EHCIInitializePeriodicSchedule(fpHCStruc, (UINT32)fpHCStruc->BaseAddress); +/* +#if EHCI_ASYNC_BELL_SUPPORT + // + // Allocate and initialize an queue head for Async transfer + // Set the QHDummy as Async list head + // + fpQHAsyncXfer = EhciMemAlloc (fpHCStruc, GET_MEM_BLK_COUNT_STRUC(EHCI_QH)); + + if (!fpQHAsyncXfer) { + return USB_ERROR; + } + + gUsbData->fpQHAsyncXfer = fpQHAsyncXfer; + + fpQHAsyncXfer->dEndPntCap = QH_ONE_XFER; + fpQHAsyncXfer->fpFirstqTD = 0; + fpQHAsyncXfer->dAltNextqTDPtr = EHCI_TERMINATE; + fpQHAsyncXfer->dNextqTDPtr = EHCI_TERMINATE; + + // + // Assume as a high speed device + // + dTemp = QH_HIGH_SPEED; // 10b - High speed + + // + // Use data toggle from qTD and this QH is the head of the queue + // + dTemp |= (QH_USE_QTD_DT | QH_HEAD_OF_LIST | DUMMY_DEVICE_ADDR); // Endpoint is 0 + + // + // dTemp[6:0] = Dev. Addr, dTemp[7] = I bit(0) & dTemp[11:8] = Endpoint (0) + // + fpQHAsyncXfer->dEndPntCharac = dTemp; + + // + // Set the ASYNCLISTADDR register to point to the QHDummy + // + EhciWriteOpReg(fpHCStruc, EHCI_ASYNCLISTADDR, (UINT32)(UINTN)fpQHAsyncXfer); + + // + // Set next QH pointer to itself (circular link) + // + fpQHAsyncXfer->dLinkPointer = (UINT32)(UINTN)fpQHAsyncXfer | EHCI_QUEUE_HEAD; + fpQHAsyncXfer->bActive = TRUE; +#endif // EHCI_ASYNC_BELL_SUPPORT +*/ + +#if USB_RUNTIME_DRIVER_IN_SMM + // Check whether no companion host controllers + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL) && + (fpHCStruc->dHCSParams & EHCI_N_CC) == 0) { + // + // Allocate a QH/qTD for QHRepeat/qTDRepeat + // + fpQHRepeat = EhciMemAlloc(fpHCStruc, + GET_MEM_BLK_COUNT(sizeof(EHCI_QH)+sizeof(EHCI_QTD))); + + if (!fpQHRepeat) { + return USB_ERROR; // Memory allocation error + } + DescPtr = fpHCStruc->stDescPtrs.fpEHCIDescPtrs; + DescPtr->fpQHRepeat = fpQHRepeat; + fpqTDRepeat = (EHCI_QTD*)((UINT32)fpQHRepeat + sizeof(EHCI_QH)); + DescPtr->fpqTDRepeat = fpqTDRepeat; +// +// Setup QHRepeat and qTDRepeat. It will run a interrupt transaction to a +// nonexistant dummy device. This will have the effect of generating +// a periodic interrupt used to generate keyboard repeat. This QH/qTD +// is normally inactive, and is only activated when a key is pressed. +// + // + // Set the first qTD pointer + // + fpQHRepeat->fpFirstqTD = fpqTDRepeat; + + //fpQHRepeat->fpDevInfoPtr = (UINT8*)fpDevInfo; + fpQHRepeat->dNextqTDPtr = (UINT32)fpqTDRepeat; + + // + // Intialize the queue head + // + fpQHRepeat->dAltNextqTDPtr = EHCI_TERMINATE; + fpQHRepeat->dLinkPointer = EHCI_TERMINATE; + + // + // Set max packet size, address, endpoint and high speed + // Update the AH's endpoint characteristcs field with the data formed + // + fpQHRepeat->dEndPntCharac |= ((0x40 << 16) | DUMMY_DEVICE_ADDR | + QH_HIGH_SPEED); + + // + // Set a bit in interrupt mask + // + fpQHRepeat->dEndPntCap = (BIT0 | QH_ONE_XFER); + fpQHRepeat->Interval = REPEAT_INTERVAL; + +// +// Fill the repeat qTD with relevant information +// The token field will be set so +// Direction PID = QTD_IN_TOKEN, +// Size = size of the data, +// Data Toggle = QTD_DATA0_TOGGLE, +// Error Count = QTD_NO_ERRORS, +// Status code = QTD_ACTIVE +// The buffer pointers field will point to the fpBuffer buffer +// which was before initialized to contain a DeviceRequest struc. +// The dNextqTDPtr field will point to the qTDControlSetup +// The dAltNextqTDPtr field will be set to EHCI_TERMINATE +// + fpQHRepeat->dTokenReload = ((UINT32)8 << 16) | QTD_IN_TOKEN | QTD_ONE_ERROR; + fpqTDRepeat->dToken = ((UINT32)8 << 16) | QTD_IN_TOKEN | QTD_ONE_ERROR; + + EHCISetQTDBufferPointers(fpqTDRepeat, + &fpQHRepeat->aDataBuffer[0], 8); + + // + // Update next & alternate next qTD pointers + // + fpqTDRepeat->dNextqTDPtr = EHCI_TERMINATE; + fpqTDRepeat->dAltNextqTDPtr = EHCI_TERMINATE; + + // + // Schedule the QHRepeat to 8ms schedule + // + EhciAddPeriodicQh(fpHCStruc,fpQHRepeat); + + fpQHRepeat->bCallBackIndex = USB_InstallCallBackFunction(EhciRepeatTDCallback); + fpQHRepeat->bActive = FALSE; + + USBKeyRepeat(fpHCStruc, 0); + } +#endif + + // + // Clear status register - all R/WC bits + // + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, + EHCI_USB_INTERRUPT | // Interrupt + EHCI_USB_ERROR_INTERRUPT | // Error interrupt + EHCI_PORT_CHANGE_DETECT | // Port Change Detect + EHCI_FRAME_LIST_ROLLOVER | // Frame List Rollover + EHCI_HOST_SYSTEM_ERROR | // Host System Error + EHCI_INT_ASYNC_ADVANCE); // Interrupt on Async Advance + // + // Program the HC BIOS owned bit and return the legacy support register offset + // + if (fpHCStruc->bExtCapPtr) { + EHCIProgramLegacyRegisters(fpHCStruc, 1); // Set HC BIOS owned semaphore + + // + // Enable USB SMI, SMI on port change and SMI on ownership change + // + dTemp = EHCI_SMI + EHCI_PORT_CHANGE_SMI + EHCI_OWNERSHIP_CHANGE_SMI; + + EhciWritePciReg(fpHCStruc, fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG, dTemp); + } + + // + // Turn HC on + // + EhciSetOpReg(fpHCStruc, EHCI_USBCMD, \ + (EHCI_RUNSTOP | EHCI_PER_SCHED_ENABLE)); + + // Wait for halt bit get cleared + for (i = 0; i < 20; i++) { + if (!(EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED)) { + break; + } + FixedDelay(100); // 100 us delay + } + + // + // If the port has the power switch then enable the port. Otherwise + // Power for the port is already present. So don't need to enable the power. + // ( Refer EHCI Spec 2.2.3 HCSPARAMS Structural Parameters Bit 4 (PPC) ) + if (fpHCStruc->dHCSParams & EHCI_PPC) { + // + // Enable port power + // + for (i = 1, PortReg = EHCI_PORTSC; i <= fpHCStruc->bNumPorts; i++, PortReg += 4) { + // + // Skip enabling DebugPort + // + if (fpHCStruc->DebugPort && fpHCStruc->DebugPort == i) continue; + + if (EhciReadOpReg(fpHCStruc, PortReg) & EHCI_PORTPOWER) { + continue; + } + + EhciSetOpReg(fpHCStruc, PortReg, EHCI_PORTPOWER); + SetPortPower = TRUE; + } + // + // Delay till the ports power is stabilised + // + if (SetPortPower) { + FixedDelay(20 * 1000); // 20 msec delay + } + } + + // Set HC flag as running + fpHCStruc->dHCFlag |= HC_STATE_RUNNING; + + // Set USB_FLAG_DRIVER_STARTED flag when HC is running. + if (!(gUsbData->dUSBStateFlag & USB_FLAG_DRIVER_STARTED)) { + gUsbData->dUSBStateFlag |= USB_FLAG_DRIVER_STARTED; + } + + // + // Disconnect all ports from companion HC (if any) and route them to EHCI + // + EhciSetOpReg(fpHCStruc, EHCI_CONFIGFLAG, BIT0); //(EIP59663-) //(EIP80307+) + + if (fpHCStruc->dHCFlag & HC_STATE_CONTROLLER_WITH_RMH) { + // Wait for port change detect bit set + for (i = 0; i < 50; i++) { + if (EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_PORT_CHANGE_DETECT) { + break; + } + FixedDelay(100); // 100 us delay + } + } else { + FixedDelay(100); // 100 us delay + } + +#if USB_RUNTIME_DRIVER_IN_SMM + // + // Register the USB HW SMI handler + // + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + UsbInstallHwSmiHandler(fpHCStruc); + } else { + USBSB_InstallUsbIntTimerHandler(); + } +#endif + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIGetLegacySupportOffset +// +// Description: This function returns the PCI register offset for the legacy +// support in EHCI controller +// +// Input: fpHCStruc - HCStruc pointer +// wPciAddr - PCI address of the EHCI host controller +// +// Output: 0 If the feature is not present +// <>0 Legacy support capability offset +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIGetLegacySupportOffset( + HC_STRUC* fpHCStruc, + UINT16 wPciAddr) +{ + UINT8 bData = 0; + UINT32 dData = 0; + +#if USB_RUNTIME_DRIVER_IN_SMM + + if (fpHCStruc->dHCFlag & HC_STATE_EXTERNAL) { + return 0; + } + + // + // Get EHCI Extended Capabilities Pointer + // + bData = (UINT8)((fpHCStruc->dHCCParams >> 8) & 0xFF); + + if (!bData) + { + return 0; // No extended capabilities are implemented. + } + + dData = EhciReadPciReg(fpHCStruc, bData); + if (!((UINT8)dData & 1)) { + return 0; + } +#endif + return bData; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIProgramLegacyRegisters +// +// Description: This function programs the EHCI legacy registers as per the +// input. Also this routine returns the PCI register offset +// for the legacy support in EHCI controller +// +// Input: fpHCStruc HCStruc pointer +// bSetReset: +// 0 Reset HC BIOS owned bit +// 1 Set HC BIOS owned bit +// +// Output: 0 If the feature is not present +// <>0 Legacy support capability offset +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIProgramLegacyRegisters( + HC_STRUC* fpHCStruc, + UINT8 bSetReset) +{ + UINT32 dTemp; + + // + // Check whether EHCI extended capabilities pointer is present + // + if (!fpHCStruc->bExtCapPtr) + { + return 0; // No extended capabilities are implemented. + } + + // + // Program 'HC BIOS owned semaphore bit' + // + dTemp = EhciReadPciReg(fpHCStruc, fpHCStruc->bExtCapPtr); + dTemp &= ~BIT16; + + if (bSetReset) + { + dTemp |= BIT16; + } + + // (USB_S4_RESUME_ISSUE, EIP#20084)> + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) + dTemp &= ~BIT24; + // <(USB_S4_RESUME_ISSUE, EIP#20084) + + EhciWritePciReg(fpHCStruc, fpHCStruc->bExtCapPtr, dTemp); + + // + // Reset all enable bits and clear the status + // + dTemp = 0xE0000000 | EHCI_OWNERSHIP_CHANGE_SMI; + + EhciWritePciReg(fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG, + dTemp); + + return fpHCStruc->bExtCapPtr; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ClearEECPstatus +// +// Description: This procedure clear EHCI legacy support status. +// +// Input: fpHCStruc - HCStruc pointer +// wSTatus - Legacy status to clear +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +ClearEECPstatus( + HC_STRUC* fpHCStruc, + UINT16 wStatus) +{ + UINT32 dTemp; + + if (!fpHCStruc->bExtCapPtr) + { + return; // No extended capabilities are implemented. + } + + // + // Read control and status register + // + dTemp = EhciReadPciReg(fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG); + + // + // Keep enable bits and set clear status bit + // + dTemp = (dTemp & 0xFFFF) | ((UINT32)wStatus << 16); + EhciWritePciReg( + fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG, + dTemp); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: GetEhciUSBLEGSUP +// +// Description: This routine return USBLEGSUP register content. It could be +// used to check EHCI semaphore owened by BIOS or OS. +// +// Input: fpHCStruc HCStruc pointer +// +// Output: UINT32 Legacy support extended capability register content. +// -1 if no extended capabilities are implemented. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +GetEhciUSBLEGSUP(HC_STRUC* fpHCStruc) +{ + UINT32 dTemp; + + // + // Check whether EHCI extended capabilities pointer is present + // + if (!fpHCStruc->bExtCapPtr) + { + return 0xFFFFFFFF; // No extended capabilities are implemented. + } + + // + // Read Legacy support register + // + dTemp = EhciReadPciReg( + fpHCStruc, + fpHCStruc->bExtCapPtr); + + return dTemp; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_EnumeratePorts +// +// Description: This function enumerates the HC ports for devices +// +// Input: fpHCStruc Host controller's HCStruc structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_EnumeratePorts(HC_STRUC* fpHCStruc) +{ + UINT16 wPortCtl = EHCI_PORTSC; // Port Status and Control Register (44h) + UINT8 bHCNumber; + UINT8 bPortNum; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (EhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + bHCNumber = (UINT8)(fpHCStruc->bHCNumber | BIT7); + + + // + // Enable port power so that new devices can be detected. + // + // Check whether enumeration flag is set by us or by somebody else by checking + // local enum flag. + // + if (gUsbData->bEnumFlag == FALSE) + { + gUsbData->bIgnoreConnectStsChng = TRUE; + gUsbData->bEnumFlag = TRUE; + //(EIP122174+)> + do { + // + // Clear the EHCI_PCD bit of the interrupt status register EHCI_USBSTS + // + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, EHCI_PORT_CHANGE_DETECT); + + // + // Check the root hub ports to see if a device is connected. If so, then + // call USBCheckPortChange to handle the attachment of a new device. + // + for ( bPortNum = 1; bPortNum <= fpHCStruc->bNumPorts; bPortNum++) { + // + // Skip DebugPort enumeration + // + if (fpHCStruc->DebugPort && fpHCStruc->DebugPort==bPortNum) continue; + + // + // Process device connect/disconnect + // + USBCheckPortChange(fpHCStruc, bHCNumber, bPortNum); + } + } while ((EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_PORT_CHANGE_DETECT)); + //<(EIP122174+) + gUsbData->bIgnoreConnectStsChng = FALSE; + + // + // Reset enumeration flag and enable hub enumeration + // + gUsbData->bEnumFlag = FALSE; + } + + // + // Enable appropriate interrupts + // + EhciWriteOpReg(fpHCStruc, EHCI_USBINTR, EHCI_USBINT_EN | EHCI_PCDINT_EN); + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCICheckHCStatus +// +// Description: This function checks whether the host controller is still +// under BIOS +// +// Input: fpHCStruc - Host controller's HCStruc structure +// +// Output: USB_SUCCESS - If the control is with the BIOS +// USB_ERROR - If the control is not with the BIOS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCICheckHCStatus( + HC_STRUC* HcStruc +) +{ + UINT32 Cmd; + UINT32 Sts; + + Cmd = EhciReadOpReg(HcStruc, EHCI_USBCMD); + Sts = EhciReadOpReg(HcStruc, EHCI_USBSTS); + + // Don't read Periodic Frame List Base Address Register if the controller + // doesn't support periodic schedule. + if (Cmd & EHCI_PER_SCHED_ENABLE) { + if (!(Sts & EHCI_PER_SCHED_STATUS)) { + return USB_SUCCESS; + } + } + // + // Check whether the controller is still under BIOS control + // Read the base address of the Periodic Frame List to the PERIODIC BASE + // register and compare with stored value + // + if ((UINTN)HcStruc->fpFrameList == + (EhciReadOpReg(HcStruc, EHCI_PERIODICLISTBASE) & 0xFFFFF000)) + { + return USB_SUCCESS; // Control is with BIOS + } + return USB_ERROR; // HC is controlled by someone else +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStop +// +// Description: This function stops the EHCI controller. +// +// Input: fpHCStruc Host controller's HCStruc structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_Stop (HC_STRUC* fpHCStruc) +{ + UINT8 bPortNum; //(EIP26685+) + UINT8 Status; + UINT8 i; //(EIP55960+) + EHCI_DESC_PTRS *DescPtr; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + DescPtr = fpHCStruc->stDescPtrs.fpEHCIDescPtrs; + +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)DescPtr < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtr + sizeof(EHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + // + // Check whether the control is with BIOS or not + // + if (EHCICheckHCStatus(fpHCStruc) == USB_SUCCESS) // Controlled by BIOS + { +#if PCH_EHCI_OWNERSHIP_CHANGE_MECHANISM + if (fpHCStruc->dHCFlag & HC_STATE_OWNERSHIP_CHANGE_IN_PROGRESS) { + UINT16 PortReg; + UINT32 PortSts; + UINT32 Data32; + + // Disconnect all the devices connected to its ports + for (bPortNum = 1; bPortNum <= fpHCStruc->bNumPorts; bPortNum++) { + USB_StopDevice(fpHCStruc, (UINT8)(fpHCStruc->bHCNumber | BIT7), bPortNum); + } + + // Stop the asynchronous schedule + EHCIStopAsyncSchedule(fpHCStruc); + + // Stop the periodic schedule + EHCIStopPeriodicSchedule(fpHCStruc); + + for (bPortNum = 1; bPortNum <= fpHCStruc->bNumPorts; bPortNum++) { + PortReg = (UINT16)((bPortNum-1)*4 + EHCI_PORTSC); + PortSts = EhciReadOpReg(fpHCStruc, PortReg); + + if (!(PortSts & EHCI_PORTENABLE)) { + continue; + } + EhciWriteOpReg(fpHCStruc, PortReg, PortSts | EHCI_SUSPEND); + } + FixedDelay(250); // 250 us delay + + // Stop the host controller (Reset bit 0) + EhciClearOpReg(fpHCStruc, EHCI_USBCMD, EHCI_RUNSTOP); + + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if (EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + + // Clear the SMI enable bits + if (fpHCStruc->bExtCapPtr) { + Data32 = EhciReadPciReg(fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG); + + EhciWritePciReg(fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG, Data32 & ~(0x3F)); + } + + // Clear the USBSTS register bits + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, EhciReadOpReg(fpHCStruc, EHCI_USBSTS)); + + // Clear the Configure Flag bit + EhciClearOpReg(fpHCStruc, EHCI_CONFIGFLAG, BIT0); + } else +#endif + { + //(EIP26685+)> + // + // Disconnect all the devices connected to its ports + // + for (bPortNum = 1; bPortNum <= fpHCStruc->bNumPorts; bPortNum++) + { + USB_DisconnectDevice(fpHCStruc, + (UINT8)(fpHCStruc->bHCNumber | BIT7), bPortNum); + } + //<(EIP26685+) + + if (fpHCStruc->DebugPort == 0) { + // + // Stop the host controller (Reset bit 0) + // + EhciClearOpReg(fpHCStruc, EHCI_USBCMD, EHCI_RUNSTOP); + //(EIP55960)> + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if (EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + //<(EIP55960) + // + // Reset the host controller + // +// EIP#23479 EHCIResetHC(fpHCStruc); // ERROR CONDITION RETURNED IS NOT TAKEN CARE + Status = EHCIResetHC(fpHCStruc); + ASSERT(Status == USB_SUCCESS); + } + } + // + // Program the HC BIOS owned bit and return the legacy + // support register offset + // + EHCIProgramLegacyRegisters(fpHCStruc, 0); // Reset HC BIOS owned semaphore + // ERROR CONDITION IS NOT HANDLED + + // + // Clear the frame list pointers + // + USB_InitFrameList (fpHCStruc, EHCI_TERMINATE); + + // + // Disable TD schedule and free the data structures + // + if (DescPtr->fpQHRepeat) { + EhciMemFree(fpHCStruc, DescPtr->fpQHRepeat, + GET_MEM_BLK_COUNT(sizeof(EHCI_QH) + sizeof(EHCI_QTD) )); + } + + // + // Free the scheduling QHs + // + EhciMemFree(fpHCStruc, DescPtr->PeriodicQh, + GET_MEM_BLK_COUNT(1 * sizeof(EHCI_QH))); + + // + // Free descriptor structure + // + EhciMemFree(fpHCStruc, DescPtr, + GET_MEM_BLK_COUNT_STRUC(EHCI_DESC_PTRS)); + +//#if EHCI_ASYNC_BELL_SUPPORT + // + // Free the Async transfer QH + // +// EhciMemFree(fpHCStruc, gUsbData->fpQHAsyncXfer, GET_MEM_BLK_COUNT_STRUC(EHCI_QH)); +//#endif + + USBKeyRepeat(fpHCStruc, 3); + } + else // not controlled by BIOS + { + // + // Program the HC BIOS owned bit and return the legacy + // support register offset + // + EHCIProgramLegacyRegisters(fpHCStruc, 0); // Reset HC BIOS owned semaphore + } + + // + // Set the HC state to stopped + // + fpHCStruc->dHCFlag &= ~(HC_STATE_RUNNING); + + CheckBiosOwnedHc(); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_DisableInterrupts +// +// Description: This function disables the HC interrupts +// +// Input: fpHCStruc Pointer to the HCStruc structure +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_DisableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Disable interrupt generation + // + EhciClearOpReg(fpHCStruc, EHCI_USBINTR, EHCI_USBINT_EN | EHCI_PCDINT_EN); + + // + // Stop periodic and asynchoronous schedule + // + EHCIStopAsyncSchedule(fpHCStruc); + EHCIStopPeriodicSchedule(fpHCStruc); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_EnableInterrupts +// +// Description: This function enables the HC interrupts +// +// Input: fpHCStruc Pointer to the HCStruc structure +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_EnableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Start periodic and asynchoronous schedule + // + EHCIStartAsyncSchedule(fpHCStruc); + EHCIStartPeriodicSchedule(fpHCStruc); + + // + // Enable interrupt generation + // + EhciSetOpReg(fpHCStruc, EHCI_USBINTR, EHCI_USBINT_EN | EHCI_PCDINT_EN); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: ProcessRootHubChanges +// +// Description: Root hub change processing code +// +// Parameters: fpHCStruc Pointer to the HCStruc structure +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +ProcessRootHubChanges( + HC_STRUC* fpHCStruc +) +{ + UINT8 bPortNum; + + // + // Check bEnumFlag before enumerating devices behind root hub + // + if ((gUsbData->bEnumFlag) == TRUE) { + return USB_ERROR; + } + + // + // Clear the port change bit of the interrupt status register EHCI_USBSTS + // + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, EHCI_PORT_CHANGE_DETECT); + + // + // Check all the ports on the root hub for any change in connect status. + // If the connect status has been changed on either or both of these ports, + // then call the routine UsbHubPortChange for each changed port. + // + // Set enumeration flag and avoid hub port enumeration + // + gUsbData->bEnumFlag = TRUE; + + for (bPortNum = 1; bPortNum <= fpHCStruc->bNumPorts; bPortNum++) { + if (fpHCStruc->DebugPort && fpHCStruc->DebugPort==bPortNum) continue; + // + // Process device connect/disconnect + // Note: port connect status is cleared while processing + // connect/disconnect (EHCIGetRootHubStatus) + // + USBCheckPortChange(fpHCStruc, (UINT8)(fpHCStruc->bHCNumber | BIT7), bPortNum); + } + + // + // Reset enumeration flag and enable hub enumeration + // + gUsbData->bEnumFlag = FALSE; + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_ProcessInterrupt +// +// Description: This function is called when the USB interrupt bit is +// set. This function will parse through the TDs and QHs to +// find out completed TDs and call their respective call +// back functions +// +// Parameters: fpHCStruc Pointer to the HCStruc structure +// +// Output: USB_ERROR - Need more Interrupt processing +// USB_SUCCESS - No interrupts pending +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_ProcessInterrupt(HC_STRUC* fpHCStruc) +{ + UINT32 dSts, dTmp; + UINT16 wStatus; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + //(EIP71067-)> +//#if (EHCI_ASYNC_BELL_SUPPORT==0) +// EHCI_QH *fpQH; +//#endif + //<(EIP71067-) + // + // If EHCI extended capabilities pointer is present, + // then service OwnerShipChange SMI + // + if (fpHCStruc->bExtCapPtr) { + // + // Read control and status register + // + dTmp = EhciReadPciReg( + fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG); + wStatus = (UINT16)dTmp; + wStatus &= (UINT16)(dTmp >> 16); // "And" enable and status bits + if (wStatus & EHCI_OWNERSHIP_CHANGE_SMI_STS) { + ClearEECPstatus(fpHCStruc, wStatus); + ProcessOwnerShipChangeSMI(fpHCStruc); + return USB_SUCCESS; // Break from Interrupt process loop + } + } + + // + // Check whether the controller is still under BIOS control + // Read the base address of the Periodic Frame List to the PERIODIC BASE + // register and compare with stored value + // + if (EHCICheckHCStatus(fpHCStruc) == USB_ERROR) { + // + // Control is not with us anymore, we should disable SMI generation + // and come out. + // + if (fpHCStruc->bExtCapPtr) { + // + // Read control and status register + // + dTmp = EhciReadPciReg( + fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG); + + // + // Leave only Ownership SMI active. + // + dTmp &= 0xE0002000; + EhciWritePciReg( + fpHCStruc, + fpHCStruc->bExtCapPtr + EHCI_LEGACY_CTRL_STS_REG, + dTmp); + } + return USB_SUCCESS; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_SUCCESS; + } + + while(TRUE){ + // + // Get the interrupt status + // + dSts = EhciReadOpReg(fpHCStruc, EHCI_USBSTS); + + //USB_DEBUG(DEBUG_LEVEL_3, "-->> %x <<--\n", dSts); + + if (dSts & EHCI_HOST_SYSTEM_ERROR) { + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + EHCI_Start(fpHCStruc); + EHCI_EnumeratePorts(fpHCStruc); + gUsbData->dUSBStateFlag |= USB_FLAG_ENABLE_BEEP_MESSAGE; + continue; + } + + if (dSts & EHCI_HCHALTED) { + // Clear the USBSTS register bits + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, EhciReadOpReg(fpHCStruc, EHCI_USBSTS)); + break; + } + + // + // Check for transaction complete + // + if ((gUsbData->ProcessingPeriodicList == TRUE) && (dSts & EHCI_USB_INTERRUPT)) { + + // + // Clear the interrupt status + // + EhciWriteOpReg(fpHCStruc, EHCI_USBSTS, EHCI_USB_INTERRUPT); + + //Section 4.4 Schedule traversal rules. + //if the periodic schedule is enabled (see Section 4.6) then the host controller must + //execute from the periodic schedule before executing from the asynchronous schedule. + //It will only execute from the asynchronous schedule after it encounters the end of + //the periodic schedule. + + // + // Check and process periodic schedule + // + if (dSts & EHCI_PER_SCHED_STATUS) { + // + // Check the command register for Async status + // + dTmp = EhciReadOpReg(fpHCStruc, EHCI_USBCMD); + + if (dTmp & EHCI_PER_SCHED_ENABLE) { + EHCIProcessPeriodicList(fpHCStruc); + } + } + + // + // Check for Asynchronous schedule completion + // +/* //(EIP71067-)> + if (dSts & EHCI_ASYNC_SCHED_STATUS) { + dTmp = DwordReadMem(dMemAddr, EHCI_USBCMD); + if (dTmp & EHCI_ASYNC_SCHED_ENABLE) { + // + // Check and process Async. QH + // +#if EHCI_ASYNC_BELL_SUPPORT + EHCIProcessQH(fpHCStruc, fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpQHControl); + EHCIProcessQH(fpHCStruc, fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpQHBulk); +#else + // + // Get the Async list address + // + fpQH = (EHCI_QH*)(UINTN)DwordReadMem(dMemAddr, EHCI_ASYNCLISTADDR); + if (EHCIProcessQH(fpHCStruc, fpQH) == USB_ERROR) { + //continue; + //return USB_SUCCESS; + } else { + // + // Async list processed; stop the Async transfer + // + EHCIStopAsyncSchedule(fpHCStruc); + } +#endif + } + } +*/ //<(EIP71067-) + continue; + } + + // + // Check PORT_CHANGE_DETECT bit + // + if ((dSts & EHCI_PORT_CHANGE_DETECT )) { + if(ProcessRootHubChanges(fpHCStruc) == USB_SUCCESS) { + continue; + } + } + break; // No more statuses to process + } + return USB_SUCCESS; // Set as interrupt processed +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ProcessOwnerShipChangeSMI +// +// Description: This procedure process EHCI OwnerShipChange SMI. +// +// Input: fpHCStruc HCStruc pointer +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +ProcessOwnerShipChangeSMI(HC_STRUC* fpHCStruc) +{ + UINT32 dTemp = GetEhciUSBLEGSUP(fpHCStruc); + fpHCStruc->dHCFlag |= HC_STATE_OWNERSHIP_CHANGE_IN_PROGRESS; + if (dTemp & EHCI_HC_OS) { + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + ProcessSmiChangeToEHCD(fpHCStruc); + } + else { + gUsbData->dUSBStateFlag |= USB_FLAG_ENABLE_BEEP_MESSAGE; + ProcessSmiChangeToBIOS(fpHCStruc); + } + fpHCStruc->dHCFlag &= ~(HC_STATE_OWNERSHIP_CHANGE_IN_PROGRESS); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ProcessSmiChangeToEHCD +// +// Description: This procedure process OwnerShipChange for BIOS -> EHCD. +// +// Input: fpHCStruc HCStruc pointer +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +ProcessSmiChangeToEHCD (HC_STRUC* fpHCStruc) +{ + EHCI_Stop(fpHCStruc); // Stop EHCI legacy +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: ProcessSmiChangeToBIOS +// +// Description: This procedure process OwnerShipChange for EHCD -> BIOS. +// +// Input: SI HCStruc pointer +// +// Output: None +// +// Modified: None +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessSmiChangeToBIOS ( + HC_STRUC *fpHCStruc +) +{ + HC_STRUC *Hc; + UINT8 Count; + DEV_INFO *Device; + + // Stop UHCI devices connected to the companions + // Core8 executes this under MKF_PCCHECK_PATCH==1 condition, EIP10272 + for (Count = 1; Count < MAX_DEVICES; Count++) { + Device = &gUsbData->aDevInfoTable[Count]; + Hc = gUsbData->HcTable[Device->bHCNumber - 1]; + + if (Hc->bHCType != USB_HC_UHCI) continue; // Not UHCI + + if ((Device->Flag & DEV_INFO_VALID_STRUC)==0) continue; // Not valid + + if ((Hc->wBusDevFuncNum & 0xfff8) != + (fpHCStruc->wBusDevFuncNum & 0xfff8)) continue; // Not a companion + + // Found a device connected to UHCI companion controller. Stop it. + USB_StopDevice(Hc, Device->bHubDeviceNumber, Device->bHubPortNumber); + } + + EHCI_Start(fpHCStruc); // Reinitialize EHCI host controller +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_ReleasePortOwner +// +// Description: +// +// Input: HcStruc - Pointer to HCStruc of the host controller +// PortNum - Port in the HC whose status is requested +// +// Output: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_ReleasePortOwner( + HC_STRUC* HcStruc, + UINT8 PortNum +) +{ + UINT16 PortReg = (UINT16)((PortNum-1)*4 + EHCI_PORTSC); + UINT16 i; + + if ((HcStruc->dHCSParams & EHCI_N_CC) == 0) { + return USB_SUCCESS; + } + + if (!(EhciReadOpReg(HcStruc, PortReg) & EHCI_CURRENTCONNECTSTATUS)) { + return USB_ERROR; + } + + USB_DEBUG(DEBUG_LEVEL_3, "Release EHCI port %d\n", PortNum); + EhciSetOpReg(HcStruc, PortReg, EHCI_PORTOWNER); + + // Loop until Full speed device disconnect event process done. + // This change is done in sync with Core8 except the extra 400mS delay + for (i = 0; i < 200; i++) { + if (EhciReadOpReg(HcStruc, PortReg) & EHCI_CONNECTSTATUSCHANGE) { + break; + } + FixedDelay(100); + } + + EhciSetOpReg(HcStruc, PortReg, EHCI_CONNECTSTATUSCHANGE); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIGetRootHubStatus +// +// Description: This function returns the port connect status for the +// root hub port +// +// Input: fpHCStruc - Pointer to HCStruc of the host controller +// bPortNum - Port in the HC whose status is requested +// +// Output: Port status flags (see USB_PORT_STAT_XX equates) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_GetRootHubStatus( + HC_STRUC* fpHCStruc, + UINT8 bPortNum, + BOOLEAN ClearChangeBits +) +{ + UINT32 dTmp; + UINT8 bStatus = USB_PORT_STAT_DEV_OWNER; + UINT16 wPortReg = (UINT16)((bPortNum-1)*4 + EHCI_PORTSC); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (fpHCStruc->DebugPort && fpHCStruc->DebugPort==bPortNum) return 0; + + // + // Read the status of the port + // + dTmp = EhciReadOpReg(fpHCStruc, wPortReg); + USB_DEBUG(3, "Ehci port[%d] status: %08x\n", bPortNum, dTmp); + + // Detect the high-speed device. + // In case of low-speed or full-speed change the ownership to a + // companion 1.1 controller (if any) + if (dTmp & EHCI_CURRENTCONNECTSTATUS) { + // Analyze Line Status + if ((dTmp & EHCI_LINE_STATUS) == EHCI_DMINUSBIT) { // Low speed device connected + EHCI_ReleasePortOwner(fpHCStruc, bPortNum); + dTmp = EhciReadOpReg(fpHCStruc, wPortReg); + } + } + + // + // Check the connect status change bit + // + if (dTmp & EHCI_CONNECTSTATUSCHANGE) { + // + // Set connect status change flag + // + bStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + + // + // Wait 20ms for host controller could report accurate port status properly. + // + //FixedDelay(gUsbData->UsbTimingPolicy.EhciPortConnect * 1000); // 20ms delay + + // + // Read the status of the port + // + //dTmp = EhciReadOpReg(fpHCStruc, wPortReg); + + // Clear connect status change + if (ClearChangeBits == TRUE) { + EhciSetOpReg(fpHCStruc, wPortReg, EHCI_CONNECTSTATUSCHANGE); //(EIP61030+) + } + } + + if (dTmp & EHCI_CURRENTCONNECTSTATUS) { + bStatus |= USB_PORT_STAT_DEV_CONNECTED; + + if (dTmp & EHCI_PORTENABLE) { + bStatus |= USB_PORT_STAT_DEV_HISPEED; + + // Patch for CloverTrail + if (fpHCStruc->Vid == 0x8086 && + (fpHCStruc->Did == 0xE006 || fpHCStruc->Did == 0x08F2)) { + if ((dTmp & EHCI_LINE_STATUS) == EHCI_DMINUSBIT) { + bStatus &= ~USB_PORT_STAT_DEV_HISPEED; + bStatus |= USB_PORT_STAT_DEV_LOWSPEED; + } else if ((dTmp & EHCI_LINE_STATUS) == EHCI_DPLUSBIT) { + bStatus &= ~USB_PORT_STAT_DEV_HISPEED; + bStatus |= USB_PORT_STAT_DEV_FULLSPEED; + } + } + bStatus |= USB_PORT_STAT_DEV_ENABLED; + //(EIP61030+)> + } else { + if (gUsbData->bIgnoreConnectStsChng == TRUE) { + if (!(dTmp & EHCI_CONNECTSTATUSCHANGE)) { + bStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + } + } + //<(EIP61030+) + } + } + + if (dTmp & EHCI_PORTOWNER) { + bStatus &= ~USB_PORT_STAT_DEV_OWNER; + } + + return bStatus; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIDisableRootHub +// +// Description: This function disables the EHCI HC Ruoot hub port. +// +// Input: fpHCStruc - Pointer to HCStruc of the host controller +// bPortNum - Port in the HC to disable +// +// Output: USB_SUCCESS on success +// USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_DisableRootHub( + HC_STRUC* fpHCStruc, + UINT8 bPortNum) +{ + //(EIP58108+)> + UINT16 PortReg = (UINT16)((bPortNum-1)*4 + EHCI_PORTSC); + UINT32 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (fpHCStruc->DebugPort && fpHCStruc->DebugPort==bPortNum) return USB_SUCCESS; + + if (!(EhciReadOpReg(fpHCStruc, PortReg) & EHCI_PORTENABLE)) { + return USB_SUCCESS; + } + EhciClearOpReg(fpHCStruc, PortReg, EHCI_PORTENABLE); + + for (i = 0; i < 100; i++) { + if ((EhciReadOpReg(fpHCStruc, PortReg) & EHCI_PORTENABLE) == 0) { + break; + } + FixedDelay(100); + } + //<(EIP58108+) + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIEnableRootHub +// +// Description: This function enables the EHCI HC Root hub port. +// +// Input: fpHCStruc - Pointer to HCStruc of the host controller +// bPortNum - Port in the HC to enable +// +// Output: USB_SUCCESS on success +// USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_EnableRootHub( + HC_STRUC* fpHCStruc, + UINT8 bPortNum) +{ +// +// Software can only enable the EHCI root hub ports by port RESET. HC will +// enable the port only if it is a high speed device +// + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_ResetRootHub +// +// Description: This function resets the EHCI HC Root hub port. +// +// Input: HcStruc - Pointer to HCStruc of the host controller +// PortNum - Port in the HC to enable +// +// Output: USB_SUCCESS on success +// USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_ResetRootHub( + HC_STRUC* HcStruc, + UINT8 PortNum +) +{ + UINT16 PortReg = (UINT16)((PortNum-1)*4 + EHCI_PORTSC); + UINT32 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + // Disable the port if it is enabled + if (EhciReadOpReg(HcStruc, PortReg) & EHCI_PORTENABLE) { + EhciClearOpReg(HcStruc, PortReg, EHCI_PORTENABLE); + + // There may be a delay in disabling or enabling a port due to other + // host controller and bus events. + for (i = 0; i < 100; i++) { + if ((EhciReadOpReg(HcStruc, PortReg) & EHCI_PORTENABLE) == 0) { + break; + } + FixedDelay(100); // 100 us delay + } + } + + // Reset the port + EhciSetOpReg(HcStruc, PortReg, EHCI_PORTRESET); + + if ((HcStruc->dHCFlag & HC_STATE_CONTROLLER_WITH_RMH) && (PortNum == 1)) { + FixedDelay(3 * 1000); // 3 ms delay + } else { + // Wait til port disable is complete (Tdrstr=50ms Ref 7.1.7.5 of USB Spec 2.0) + FixedDelay(50 * 1000); // 50 ms delay + } + + EhciClearOpReg(HcStruc, PortReg, EHCI_PORTRESET); // Terminate reset + + if (!(EhciReadOpReg(HcStruc, PortReg) & EHCI_CURRENTCONNECTSTATUS)) { + return USB_ERROR; + } + + // if the port detects that the attached device is high-speed during reset, + // then the host controller must have the port in the enabled state within 2ms + // of software writing this bit to a zero. + for (i = 0; i < 20; i++) { + if ((EhciReadOpReg(HcStruc, PortReg) & (EHCI_PORTRESET | + EHCI_PORTENABLE)) == EHCI_PORTENABLE) { + break; + } + FixedDelay(100); // 100 us delay + } + + if (EhciReadOpReg(HcStruc, PortReg) & EHCI_PORTRESET) { // Reset failed + USBLogError(USB_ERR_PORT_RESET_FAILED); + return USB_ERROR; + } + + if (!(EhciReadOpReg(HcStruc, PortReg) & EHCI_PORTENABLE)) { + if (!(EhciReadOpReg(HcStruc, PortReg) & EHCI_CURRENTCONNECTSTATUS)) { + return USB_ERROR; + } else { + EHCI_ReleasePortOwner(HcStruc, PortNum); + return USB_ERROR; + } + } + + FixedDelay(1 * 1000); // 1 ms delay + + return USB_SUCCESS; +} + + //(EIP54018+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: EHCI_GlobalSuspend +// +// Description: +// This function suspend the EHCI HC. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_GlobalSuspend( + HC_STRUC* HcStruc +) +{ + UINT16 PortReg; + UINT32 PortSts; + UINT8 PortNum; + UINT8 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (EhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + for (PortNum = 1; PortNum <= HcStruc->bNumPorts; PortNum++) { + PortReg = (UINT16)(EHCI_PORTSC + (PortNum - 1) * 4 ); + PortSts = EhciReadOpReg(HcStruc, PortReg ); + USB_DEBUG(DEBUG_LEVEL_3,"EHCI PortSts[%x] %x \n", + PortNum, PortSts); + // Check if port is disabled or suspended. + if((PortSts & EHCI_PORTENABLE) && (!(PortSts & EHCI_SUSPEND))) { + // Suspend if necessary. + EhciClearOpReg(HcStruc, PortReg, + EHCI_WKOC_E | EHCI_WKDSCNNT_E | EHCI_WKCNNT_E); + EhciSetOpReg(HcStruc, PortReg, EHCI_SUSPEND); + // Read PortSc until port shows suspended. + for(i = 0; i < 100; i++) { + if(EhciReadOpReg(HcStruc, PortReg) & EHCI_SUSPEND) { + break; + } + FixedDelay(100); // 100 us delay + } + } + } + + // Turn HC off and wait for the Halted bit to get set + EhciClearOpReg(HcStruc, EHCI_USBCMD, EHCI_RUNSTOP); + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + HcStruc->dHCFlag |= HC_STATE_SUSPEND; + + return USB_SUCCESS; +} + //<(EIP54018+) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_GetHiSpeedHubPortNumber +// +// Description: This function gets the hi-speed hub's device and port number +// to which this low speed device is connected. It parses +// through its parents until it finds the correct device. This +// information is used for split transaction +// +// Input: fpDevInfo - Device info pointer of the device +// +// Output: UINT16 - Device/port number of the hi-speed hub +// +// Notes: This low/full speed device may be behind different hubs as +// shown below. In any case this routine will get the device +// address of the hub number HISP_A : +// Notations used: +// MBPortX Motherboard USB port +// HISP_X Hi-speed hub number X +// FUSP_X Full-speed hub number X +// Device Low/Full speed device +// Config 1: +// MBPortX --> HISP_A --> Device +// Config 2: +// MBPortX --> HISP_A --> FUSP_1 --> Device +// Config 3: +// MBPortX --> HISP_B --> HISP_A --> Device +// Config 4: +// MBPortX --> HISP_A --> FUSP_1 --> HISP_B --> Device +// In the above configuration the HISP_B will be operated in +// full speed rather than hi-speed since it is connected to a +// full speed hub +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +EHCI_GetHiSpeedHubPortNumber(DEV_INFO* fpDevInfo) +{ + DEV_INFO* fpHubDev = fpDevInfo; + DEV_INFO* fpParentHubDev; + UINT16 wRetCode; + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + +// +// Get the device info structure for the matching device address +// + // + // Get the device number of the immediate hub, then get the device + // info structure for this device number + // + for(;;) + { + fpParentHubDev = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, + 0, fpHubDev->bHubDeviceNumber, 0); + if ( !fpParentHubDev ) // Error. Exit ! + { + return 0; + } + if (((fpParentHubDev->bEndpointSpeed << USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) + & USB_PORT_STAT_DEV_SPEED_MASK) == 0) break; + fpHubDev = fpParentHubDev; + } + // + // The first USB 2.0 hub found as fpHubDev to which the low/full speed + // device is connected + // + wRetCode = (UINT16)((fpHubDev->bHubPortNumber << 7) | + fpHubDev->bHubDeviceNumber); + + return wRetCode; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EhciExexuteAsyncSchedule +// +// Description: This function insert the requested QH to asynchronous schedule +// and waits until the QH completes or the transaction time-out. +// +// Input: HcStruc - Pointer to HCStruc of the host controller +// XferQh - Pointer to the QH which has to be completed +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +EhciExexuteAsyncSchedule( + HC_STRUC *HcStruc, + EHCI_QH *XferQh +) +{ + UINT16 Status = USB_SUCCESS; + UINT32 Count; + UINT32 TimeOut = gUsbData->wTimeOutValue * 100; // in 10 macrosecond unit +// +//#if EHCI_ASYNC_BELL_SUPPORT +// UINT32 Tmp; + +// XferQh->dLinkPointer = EHCI_TERMINATE; +// XferQh->bActive = TRUE; + + // + // Insert the Control/Bulk QH into the Async list + // +// Tmp = gUsbData->fpQHAsyncXfer->dLinkPointer; +// gUsbData->fpQHAsyncXfer->dLinkPointer = (UINT32)XferQh | EHCI_QUEUE_HEAD; +// XferQh->dLinkPointer = Tmp; +//#else + // + // Set the ASYNCLISTADDR register to point to the Control/Bulk QH + // + EhciWriteOpReg(HcStruc, EHCI_ASYNCLISTADDR, (UINT32)(UINTN)XferQh); + + // + // Set next QH pointer to itself (circular link) + // + XferQh->dLinkPointer = (UINT32)((UINTN)XferQh | EHCI_QUEUE_HEAD); + XferQh->bActive = TRUE; +//#endif + + // + // Now put the Control/Bulk QH into the HC's schedule by + // setting the Async. schedule enabled field of USBCMD register + // This will cause the HC to execute the transaction in the next active frame. + // + Status = EHCIStartAsyncSchedule(HcStruc); + + if (Status == USB_ERROR) { + return Status; + } + + // Wait for tansfer complete + for(Count = 0; !TimeOut || Count < TimeOut; Count++) { + EHCIProcessQH(HcStruc, XferQh); + if(XferQh->bActive == FALSE) { + break; + } + FixedDelay(10); // 10 microsec + } + +//#if EHCI_ASYNC_BELL_SUPPORT + // + // Disconnect Control/Bulk QH from the Async list + // +// EHCIRemoveQHFromAsyncList(HcStruc, XferQh); +//#else + // + // Stop the Async transfer + // + EHCIStopAsyncSchedule(HcStruc); +//#endif + + if(XferQh->bActive == TRUE) { + XferQh->bActive = FALSE; + Status = USB_ERROR; + USB_DEBUG (DEBUG_LEVEL_3, "EHCI Time-Out\n"); + } + + // Service all interrupts + EHCI_ProcessInterrupt(HcStruc); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_ControlTransfer +// +// Description: This function executes a device request command transaction +// on the USB. One setup packet is generated containing the +// device request parameters supplied by the caller. The setup +// packet may be followed by data in or data out packets +// containing data sent from the host to the device +// or vice-versa. This function will not return until the +// request either completes successfully or completes in error +// (due to time out, etc.) +// +// Parameters: fpHCStruc Pointer to HCStruc of the host controller +// 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: Get Configuration, Set Address etc) +// 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> + +UINT16 +EHCI_ControlTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT16 wRequest, + UINT16 wIndex, + UINT16 wValue, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT32 dTmp, dTmp1; + UINT16 wRetCode = 0; // Initialize with error + EHCI_QH *fpQHCtl; + EHCI_QTD *fpQTDCtlSetup, *fpQTDCtlData, *fpQTDCtlStatus; + DEV_REQ *fpRequest = NULL; + UINT8 bEndpointSpeed; + UINT8 *BufPhyAddr = NULL; + VOID *BufferMapping = NULL; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + if (wLength != 0) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ehci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (EhciIsHalted(fpHCStruc)) { + return 0; + } + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + + gUsbData->dLastCommandStatusExtended = 0; //(EIP84790+) + +//USB_DEBUG(DEBUG_LEVEL_3, "EHCI_ControlTransfer..\n"); + // + // Build the device request in the data area of the control setup qTD + // + fpRequest = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT(sizeof(DEV_REQ))); + ASSERT(fpRequest); + if (fpRequest == NULL) { + return 0; + } + + fpRequest->wRequestType = wRequest; + fpRequest->wIndex = wIndex; + fpRequest->wValue = wValue; + fpRequest->wDataLength = wLength; + +// +// The QH endpoint characteristic field will be set so +// Function address & Endpoint number = From DeviceInfo structure, +// Direction = From TD, +// Speed = DeviceInfo.bEndpointSpeed, +// Skip = 1, Format = 0, +// Max packet size = DeviceInfo.wEndp0MaxPacket +// The dNextqTDPtr field will be set to qTDControlSetup +// The dAltNextqTDPtr field will be set to EHCI_TERMINATE +// The dCurrentqTDPtr field will be set to 0 +// + // + // Intialize the queue head with null pointers + // + //(EIP71067)> + fpQHCtl = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH))+ + (3 * sizeof(EHCI_QTD)))); + //(EIP83295+)> + if(!fpQHCtl) { + return 0; + } + //<(EIP83295+) + //(EIP81030)> + fpQTDCtlSetup = (EHCI_QTD*)((UINTN)fpQHCtl + sizeof(EHCI_QH)); + fpQTDCtlData = (EHCI_QTD*)((UINTN)fpQTDCtlSetup + sizeof(EHCI_QTD)); + fpQTDCtlStatus = (EHCI_QTD*)((UINTN)fpQTDCtlData + sizeof(EHCI_QTD)); + //<(EIP71067) + //<EIP81030) + EHCIInitializeQueueHead(fpQHCtl); + + bEndpointSpeed = fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + + // + // Assume as a high speed device + // + dTmp = QH_HIGH_SPEED; // 10b - High speed + + // + // Check for high speed + // + if (bEndpointSpeed) // Low/Full speed device + { + dTmp = ((UINT32)bEndpointSpeed & 1) << 12; // Bit 12 = full/low speed flag + dTmp |= QH_CONTROL_ENDPOINT; + // + // Set the hub address and port number + // Get the Hispeed hub port number & device number + // + dTmp1 = (UINT32)EHCI_GetHiSpeedHubPortNumber(fpDevInfo); + dTmp1 = (dTmp1 << 16); // Split complete Xaction + fpQHCtl->dEndPntCap |= dTmp1; + } + +//USB_DEBUG(DEBUG_LEVEL_3, "Tmp1..%x\n", dTmp); + + // + // Use data toggle from qTD and this QH is the head of the queue + // +//#if EHCI_ASYNC_BELL_SUPPORT +// dTmp |= QH_USE_QTD_DT; +//#else + dTmp |= QH_USE_QTD_DT; + // Do not set QH_HEAD_OF_LIST bit on VIA controller + if (fpHCStruc->Vid != 0x1106) { + dTmp |= QH_HEAD_OF_LIST; + } +//#endif + dTmp |= (UINT32)fpDevInfo->bDeviceAddress; + // + // dTmp[Bits 6:0] = Dev. Addr + // dTmp[Bit7] = I bit(0) + // dTmp[Bits11:8] = Endpoint (0) + // + + dTmp1 = (UINT32)fpDevInfo->wEndp0MaxPacket; + dTmp |= (dTmp1 << 16); // Tmp[Bits26:16] = device's packet size + fpQHCtl->dEndPntCharac = dTmp; + + // + // Fill in various fields in the qTDControlSetup. + // + //fpQTDCtlSetup = fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpqTDControlSetup; //(EIP71067-) + + // + // The token field will be set so + // Direction PID = QTD_SETUP_TOKEN, + // Size = size of the data, + // Data Toggle = QTD_SETUP_TOGGLE, + // Error Count = QTD_THREE_ERRORS, + // Status code = QTD_DO_OUT + QTD_ACTIVE + // The buffer pointers field will point to the aControlSetupData buffer + // which was before initialized to contain a DeviceRequest struc. + // The dNextqTDPtr field will point to the qTDControlData if data will + // be sent/received or to the qTDControlStatus if no data is expected. + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + fpQTDCtlSetup->dToken = QTD_SETUP_TOKEN | + QTD_SETUP_TOGGLE | QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_DO_OUT | QTD_ACTIVE | + (8 << 16); // Data size + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpQTDCtlSetup, (UINT8*)fpRequest, 8); + //fpQTDCtlData = fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpqTDControlData; //(EIP71067-) + + if (wLength) // br if no data to transfer + { + // + // Fill in various fields in the qTDControlData + // + // The token field will be set so + // Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN, + // Size = size of the data, + // Data Toggle = QTD_DATA1_TOGGLE, + // Error Count = QTD_THREE_ERRORS, + // Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE + // The buffer pointers field will point to the fpBuffer buffer + // which was before initialized to contain a DeviceRequest struc. + // The dNextqTDPtr field will point to the qTDControlSetup + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + fpQTDCtlData->dToken = QTD_IN_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_ACTIVE; + if (!(wRequest & BIT7)) // Br if host sending data to device (OUT) + { + fpQTDCtlData->dToken = QTD_OUT_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + } + + // + // Set length + // + fpQTDCtlData->dToken |= ((UINT32)wLength << 16); + + EhciDmaMap(fpHCStruc, (UINT8)(wRequest & BIT7), fpBuffer, wLength, + &BufPhyAddr, &BufferMapping); + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpQTDCtlData, + (UINT8*)BufPhyAddr, + (UINT32)wLength); + } + + // + // Fill in various fields in the qTDControlStatus + // + //fpQTDCtlStatus = fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpqTDControlStatus; //(EIP71067-) + + // + // The token field will be set so + // Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN, + // Size = 0, + // Data Toggle = QTD_DATA1_TOGGLE, + // Error Count = QTD_THREE_ERRORS, + // Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE + // The buffer pointers field will be 0 + // The dNextqTDPtr field will set to EHCI_TERMINATE + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + // For OUT control transfer status should be IN and + // for IN cotrol transfer, status should be OUT + // + fpQTDCtlStatus->dToken = QTD_IN_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_ACTIVE; + if(wRequest & BIT7) + { + fpQTDCtlStatus->dToken = QTD_OUT_TOKEN | + QTD_DATA1_TOGGLE | QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + } + + EHCISetQTDBufferPointers(fpQTDCtlStatus, NULL, 0); + + // + // Link the qTD formed now and connect them with the control queue head + // + fpQHCtl->fpFirstqTD = fpQTDCtlSetup; + fpQHCtl->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlSetup; + + if(wLength) + { + fpQTDCtlSetup->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlData; + fpQTDCtlData->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlStatus; + } + else + { + fpQTDCtlSetup->dNextqTDPtr = (UINT32)(UINTN)fpQTDCtlStatus; + } + + fpQTDCtlStatus->dNextqTDPtr = EHCI_TERMINATE; + + wRetCode = EhciExexuteAsyncSchedule(fpHCStruc, fpQHCtl); + fpQHCtl->fpFirstqTD = 0; + fpQHCtl->dNextqTDPtr = EHCI_TERMINATE; + + if (wLength) { + EhciDmaUnmap(fpHCStruc, BufferMapping); + wLength = wLength - (UINT16)((fpQTDCtlData->dToken & ~(QTD_DATA_TOGGLE)) >> 16); + } + + // + // Clear the stalled condition flag + // + gUsbData->bLastCommandStatus &= ~USB_CONTROL_STALLED; + + // + // Check whether the QH stopped or timed out + // + if (wRetCode != USB_SUCCESS) { + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; //(EIP84790+) + wLength = 0; //(EIP71067) + } + + if (fpQHCtl->bErrorStatus & QTD_HALTED) { + // + // Command stalled set the error bit appropriately + // + gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; + wLength = 0; //(EIP71067) + } + //(EIP71067+)> + EhciMemFree(fpHCStruc, fpQHCtl, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH))+ + (3 * sizeof(EHCI_QTD)))); + //<(EIP71067+) + EhciMemFree(fpHCStruc, fpRequest, GET_MEM_BLK_COUNT(sizeof(DEV_REQ))); + + return wLength; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_BulkTransfer +// +// 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.) +// NOTE: Make sure that amount of bytes to transfer should not +// exceed MAX_EHCI_DATA_SIZE +// +// Parameters: pHCStruc Pointer to HCStruc of the host controller +// pDevInfo DeviceInfo structure (if available else 0) +// bXferDir Transfer direction +// Bit 7: Data direction +// 0 Host sending data to device +// 1 Device sending data to host +// Bit 6-0 : Reserved +// fpBuffer Buffer containing data to be sent to the +// device or buffer to be used to receive data +// value in Segment:Offset format +// dwLength dwLength 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 +EHCI_BulkTransfer( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 bXferDir, + UINT8 *fpBuffer, + UINT32 dwLength) +{ + UINT16 wMaxPkt; + UINT8 bEndp, bDatToggle; + EHCI_QH *fpQHBulk; + EHCI_QTD *fpQTDBulkData; + UINT32 dTmp, dTmp1; + UINT16 Status; + UINT32 dBytesToTransfer, dBytesRemaining; + UINT32 dBytesTransferred; + UINT8 *BufPhyAddr = NULL; + VOID *BufferMapping = NULL; + UINT8 *TempBuffer = NULL; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, dwLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ehci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (EhciIsHalted(fpHCStruc)) { + return 0; + } + + if (!VALID_DEVINFO(fpDevInfo)) { + return 0; + } + + // Realtek 8111EP EHCI controller workaround + // The controller doesn't work if the buffer address isn't DWORD alignment + // (current offset of qTD). Provide the workaround to locate DWORD alignment buffer. + + if ((fpHCStruc->Vid == 0x10EC) && (fpHCStruc->Did == 0x816D)) { + if ((UINTN)fpBuffer & (BIT0 | BIT1)) { + if (dwLength < HIGHSPEED_MAX_BULK_DATA_SIZE) { + TempBuffer = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT((UINT16)dwLength)); + } else { + TempBuffer = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT(HIGHSPEED_MAX_BULK_DATA_SIZE)); + } + } + } + + //clear HW source of error + gUsbData->dLastCommandStatusExtended = 0; + + + dBytesRemaining = dwLength; + dBytesTransferred = 0; + + // + // Get Bulk IN/OUT enpoint number, data sync value & max packet size + // + if (bXferDir & BIT7) + { + wMaxPkt = fpDevInfo->wBulkInMaxPkt; + bEndp = fpDevInfo->bBulkInEndpoint; + } + else + { + wMaxPkt = fpDevInfo->wBulkOutMaxPkt; + bEndp = fpDevInfo->bBulkOutEndpoint; + } + if( wMaxPkt == 0){ + return 0; + } + //(EIP71067+)> + fpQHBulk = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH))+ + (1 * sizeof(EHCI_QTD)))); + //(EIP83295+)> + if(!fpQHBulk) { + return 0; + } + //<(EIP83295+) + fpQTDBulkData = (EHCI_QTD*)((UINTN)fpQHBulk + sizeof(EHCI_QH)); //(EIP81030) + //<(EIP71067+) + EhciDmaMap(fpHCStruc, bXferDir, fpBuffer, dwLength, &BufPhyAddr, &BufferMapping); + + while (dBytesRemaining) { + dBytesToTransfer = + (dBytesRemaining < HIGHSPEED_MAX_BULK_DATA_SIZE)? + dBytesRemaining : HIGHSPEED_MAX_BULK_DATA_SIZE; + + // + // Get data toggle value + // + bDatToggle = UsbGetDataToggle(fpDevInfo, bEndp | bXferDir); + + // + // Set the QH's dNextqTDPtr field to bulk data qTD and dAltqTDPtr field to + // EHCI_TERMINATE. Also set QH's link pointer to itself + // + //(EIP71067-)> + //fpQHBulk = fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpQHBulk; + //fpQTDBulkData = fpHCStruc->stDescPtrs.fpEHCIDescPtrs->fpqTDBulkData; + //<(EIP71067-) + // + // Intialize the queue head + // + EHCIInitializeQueueHead(fpQHBulk); + + // + // Set the first qTD pointer + // + fpQHBulk->fpFirstqTD = fpQTDBulkData; + fpQHBulk->dNextqTDPtr = (UINT32)(UINTN)fpQTDBulkData; + fpQHBulk->dLinkPointer = (UINT32)((UINTN)fpQHBulk | EHCI_QUEUE_HEAD); + + // + // Device address & Endpoint + // + dTmp = (UINT32)(fpDevInfo->bDeviceAddress | (bEndp << 8)); + + // + // Set max packet size + // + dTmp = dTmp | ((UINT32)wMaxPkt << 16); + + // + // Set the data toggle control + // +// #if EHCI_ASYNC_BELL_SUPPORT +// dTmp |= QH_USE_QTD_DT; +// #else + dTmp |= QH_USE_QTD_DT; + // Do not set QH_HEAD_OF_LIST bit on VIA controller + if (fpHCStruc->Vid != 0x1106) { + dTmp |= QH_HEAD_OF_LIST; + } +// #endif + + // + // Set the device speed + // Reset the device speed bits + // + dTmp1 = (UINT32)fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + + // + // Assume as a high speed device + // + dTmp |= QH_HIGH_SPEED; // 10b - High speed + + // + // Check for high speed + // + if (dTmp1) + { + dTmp1 = (dTmp1 & 1) << 12; // Bit 12 = full/low speed flag + dTmp &= ~(QH_ENDPOINT_SPEED); + dTmp |= dTmp1; + // + // Set the hub address and port number + // + dTmp1 = (UINT32)EHCI_GetHiSpeedHubPortNumber(fpDevInfo); + dTmp1 = (dTmp1 << 16); // Hispeed hub port number & device number + fpQHBulk->dEndPntCap |= dTmp1; // Split complete Xaction + } + + // + // Update the endpoint characteristcs field with the data formed + // + fpQHBulk->dEndPntCharac = dTmp; + + // + // Fill the bulk data qTD with relevant information + // The token field will be set so + // Direction PID = QTD_OUT_TOKEN/QTD_IN_TOKEN, + // Size = size of the data, + // Data Toggle = bDatToggle, + // Error Count = QTD_THREE_ERRORS, + // Status code = QTD_DO_OUT(if it is out) + QTD_ACTIVE + // The buffer pointers field will point to the fpBuffer buffer + // which was before initialized to contain a DeviceRequest struc. + // The dNextqTDPtr field will point to the qTDControlSetup + // The dAltNextqTDPtr field will be set to EHCI_TERMINATE + // + if (bXferDir & BIT7) { + fpQTDBulkData->dToken = QTD_IN_TOKEN | + QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_ACTIVE; + } else { + fpQTDBulkData->dToken = QTD_OUT_TOKEN | + QTD_IOC_BIT | + QTD_THREE_ERRORS | QTD_DO_OUT | QTD_ACTIVE; + if (TempBuffer != NULL) { + MemCpy(BufPhyAddr, TempBuffer, dBytesToTransfer); + } + } + + // + // Set the data toggle depending on the bDatToggle value + // + fpQTDBulkData->dToken |= (UINT32)bDatToggle << 31; + + // + // Set length + // + fpQTDBulkData->dToken |= (dBytesToTransfer << 16); + + // + // Update buffer pointers + // + if (TempBuffer != NULL) { + EHCISetQTDBufferPointers(fpQTDBulkData, TempBuffer, dBytesToTransfer); + } else { + EHCISetQTDBufferPointers(fpQTDBulkData, BufPhyAddr, dBytesToTransfer); + } + + // + // Update next & alternate next qTD pointers + // + fpQTDBulkData->dNextqTDPtr = EHCI_TERMINATE; + fpQTDBulkData->dAltNextqTDPtr = EHCI_TERMINATE; + + fpQHBulk->bActive = TRUE; + + + // + // Set bulk condition as not stalled + // + gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED + USB_BULK_TIMEDOUT); + + // + // Now wait for bulk transaction to be complete + // the EHCIProcessInterrupt will set its active flag to FALSE. + // Now wait for the bulk transfer to complete + // + Status = EhciExexuteAsyncSchedule(fpHCStruc, fpQHBulk); + + fpQHBulk->fpFirstqTD = 0; + fpQHBulk->dNextqTDPtr = EHCI_TERMINATE; + + if (Status != USB_SUCCESS) { + // + // Set time out status + // + gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + } + + if (fpQHBulk->bErrorStatus & QTD_HALTED) { + // + // Stall condition + // + gUsbData->bLastCommandStatus &= ~(USB_BULK_TIMEDOUT); + gUsbData->bLastCommandStatus |= USB_BULK_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + } + + // + // Update the data toggle value into the mass info structure + // + bDatToggle = + (UINT8)(((fpQHBulk->dToken & QH_DATA_TOGGLE) >> 31) & 1); + UsbUpdateDataToggle(fpDevInfo, bEndp | bXferDir, bDatToggle); + + // + // Get the size of data transferred + // + dTmp = (fpQTDBulkData->dToken & ~(QTD_DATA_TOGGLE)) >> 16; + dTmp = (dTmp)? dBytesToTransfer-dTmp : dBytesToTransfer; + + if (!dTmp) { + break; + } + + if (TempBuffer != NULL) { + if (bXferDir & BIT7) { + MemCpy(TempBuffer, BufPhyAddr, dTmp); + } + } + + // + // Adjust loop variables + // + dBytesRemaining = dBytesRemaining - dTmp; + dBytesTransferred += dTmp; + + if (dTmp < dBytesToTransfer) { + break; + } + + BufPhyAddr += dTmp; + } + + EhciDmaUnmap(fpHCStruc, BufferMapping); + //(EIP71067+)> + EhciMemFree(fpHCStruc, fpQHBulk, GET_MEM_BLK_COUNT( (1 * sizeof(EHCI_QH)) + + (1 * sizeof(EHCI_QTD)))); + //<(EIP71067+) + if (TempBuffer != NULL) { + if (dwLength < HIGHSPEED_MAX_BULK_DATA_SIZE) { + EhciMemFree(fpHCStruc, TempBuffer, GET_MEM_BLK_COUNT((UINT16)dwLength)); + } else { + EhciMemFree(fpHCStruc, TempBuffer, GET_MEM_BLK_COUNT(HIGHSPEED_MAX_BULK_DATA_SIZE)); + } + } + + return dBytesTransferred; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_InterruptTransfer +// +// Description: This function executes an interrupt transaction on the USB. +// The data transfer direction is always DATA_IN. This +// function wil not return until the request either completes +// successfully or completes in error (due to time out, etc.) +// +// Parameters: fpHCStruc Pointer to HCStruc of the host controller +// fpDevInfo DeviceInfo structure (if available else 0) +// EndpointAddress The destination USB device endpoint to which the device request +// is being sent. +// MaxPktSize Indicates the maximum packet size the target endpoint is capable +// of sending or receiving. +// 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 +// +// Output: Number of bytes transferred +// +// +// Notes: DO NOT TOUCH THE LINK POINTER OF THE TDInterruptData. It is +// statically allocated and linked with other items in the +// 1ms schedule +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +EHCI_InterruptTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *fpBuffer, + UINT16 wLength +) +{ + + UINT8 bDatToggle; + EHCI_QH *fpQHInt; + UINT32 dTmp, dTmp1; + EHCI_QTD *fpqTDIntData; + UINT32 Count; + UINT32 Timeout; + UINT32 BytesTransferred; + UINT8 *BufPhyAddr = NULL; + VOID *BufferMapping = NULL; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ehci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (EhciIsHalted(fpHCStruc)) { + return 0; + } + + gUsbData->dLastCommandStatusExtended = 0; + + bDatToggle = UsbGetDataToggle(fpDevInfo, EndpointAddress); + + // + // Get the QHInterrupt pointer + // + fpQHInt = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH))+ + (1 * sizeof(EHCI_QTD)))); + if (fpQHInt == NULL) { + return 0; + } + + fpqTDIntData = (EHCI_QTD*)((UINTN)fpQHInt + sizeof(EHCI_QH)); + + // + // Intialize the queue head + // + EHCIInitializeQueueHead(fpQHInt); + + // + // Set the first qTD pointer + // + fpQHInt->fpFirstqTD = fpqTDIntData; + fpQHInt->dNextqTDPtr = (UINT32)(UINTN)fpqTDIntData; + fpQHInt->dLinkPointer = EHCI_TERMINATE; + + // + // Get Device address & Endpoint + // + dTmp = (UINT32)fpDevInfo->bDeviceAddress; + dTmp |= (UINT32)(EndpointAddress & 0xF) << 8; + + // + // Set max packet size + // + dTmp |= (UINT32)(MaxPktSize) << 16; + + // + // Set the device speed, reset the device speed bits + // + dTmp1 = (UINT32)fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + + // + // Assume as a high speed device + // + dTmp |= QH_HIGH_SPEED; // 10b - High speed + + // + // Check for high speed + // + if (dTmp1) + { + dTmp1 = (dTmp1 & 1) << 12; // Bit 12 = full/low speed flag + dTmp &= ~(QH_ENDPOINT_SPEED); + dTmp |= dTmp1; + // + // Set the hub address and port number + // + dTmp1 = (UINT32)EHCI_GetHiSpeedHubPortNumber(fpDevInfo); + dTmp1 = (dTmp1 << 16) | BIT10 | BIT11 | BIT12; + fpQHInt->dEndPntCap |= dTmp1; // Split complete Xaction + } + // + // Update the endpoint characteristcs field with the data formed + // + fpQHInt->dEndPntCharac = dTmp; + fpQHInt->dEndPntCap |= (BIT0 | QH_ONE_XFER); // Interrupt schedule mask + fpQHInt->Interval = EhciTranslateInterval(fpDevInfo->bEndpointSpeed, + fpDevInfo->bPollInterval); + + // + // Set the data toggle depending on the bDatToggle value + // + fpQHInt->dToken |= (UINT32)bDatToggle << 31; + +// +// Fill the interrupt data qTD with relevant information +// The token field will be set so +// Direction PID = QTD_IN_TOKEN, +// Size = size of the data, +// Data Toggle = bDatToggle, +// Error Count = QTD_THREE_ERRORS, +// Status code = QTD_ACTIVE +// The buffer pointers field will point to the EDX +// which was before initialized to contain a DeviceRequest struc. +// The dNextqTDPtr field will point to the qTDControlSetup +// The dAltNextqTDPtr field will be set to EHCI_TERMINATE +// + fpqTDIntData->dToken = QTD_IOC_BIT | QTD_THREE_ERRORS | QTD_ACTIVE; + if (EndpointAddress & BIT7) { + fpqTDIntData->dToken |= QTD_IN_TOKEN; + } else { + fpqTDIntData->dToken |= QTD_OUT_TOKEN; + } + + // + // Set length + // + fpqTDIntData->dToken |= (UINT32)wLength << 16; + + EhciDmaMap(fpHCStruc, EndpointAddress & BIT7, fpBuffer, wLength, + &BufPhyAddr, &BufferMapping); + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpqTDIntData, BufPhyAddr, (UINT32)wLength); + + // + // Update next & alternate next qTD pointers + // + fpqTDIntData->dNextqTDPtr = EHCI_TERMINATE; + fpqTDIntData->dAltNextqTDPtr = EHCI_TERMINATE; + + // + // Schedule the QHInterrupt to 1msec schedule + // + EhciAddPeriodicQh(fpHCStruc,fpQHInt); + + // Set the QH as active + fpQHInt->bActive = TRUE; + + // + // Now wait for interrupt transaction to be complete; + // the EHCIProcessInterrupt will set its active flag to FALSE. + // + Timeout = gUsbData->wTimeOutValue * 100; // makes it number of 10 macrosecond units + + for (Count = 0; Timeout == 0 || Count < Timeout; Count++) { + if (!(fpqTDIntData->dToken & QTD_ACTIVE)) { + break; + } + FixedDelay(10); // 60 microsec + } + //Status = EHCIWaitForTransferComplete(fpHCStruc, fpQHInt, fpDevInfo); + + // Remove the QH from periodic schedule + EhciRemovePeriodicQh(fpHCStruc,(EHCI_QH*)fpQHInt); + + // + // Check whether the QH stopped or timed out + // + BytesTransferred = 0; + if (fpqTDIntData->dToken & QTD_ACTIVE) { + USB_DEBUG (DEBUG_LEVEL_3, "EHCI Time-Out\n"); + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + } else if (fpqTDIntData->dToken & QTD_HALTED) { + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + } else { + BytesTransferred = (UINT16)(wLength - ((fpqTDIntData->dToken & + ~(QTD_DATA_TOGGLE)) >> 16)); + // + // Update the data toggle value into the mass info structure + // + bDatToggle = (UINT8)(((fpQHInt->dToken & QH_DATA_TOGGLE) >> 31) & 1); + UsbUpdateDataToggle(fpDevInfo, EndpointAddress, bDatToggle); + } + + EhciDmaUnmap(fpHCStruc, BufferMapping); + + // Free the allocated QH and qTD + EhciMemFree(fpHCStruc, fpQHInt, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH)) + + (1 * sizeof(EHCI_QTD)))); + + // Service all interrupts + EHCI_ProcessInterrupt(fpHCStruc); + + return (UINT16)BytesTransferred; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_DeactivatePolling +// +// Description: This function de-activates the polling QH for the requested +// device. The device may be a USB keyboard or USB hub +// +// Input: fpHCStruc - Pointer to the HC structure +// fpDevInfo - Pointer to the device information structure +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_DeactivatePolling( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + UINT8 *fpPollED; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (EhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + // + // Get a pointer to the device's QH from the poll QH pointer and remove + // the polling ED from the schedule + // + fpPollED = fpDevInfo->fpPollEDPtr; + if(!fpPollED) return USB_ERROR; + + ((EHCI_QH*)fpPollED)->bActive = FALSE; + + EhciRemovePeriodicQh(fpHCStruc,(EHCI_QH*)fpPollED); + + UsbUpdateDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint, + (UINT8)((((EHCI_QH*)fpPollED)->dToken & QH_DATA_TOGGLE) >> 31)); + + EhciMemFree(fpHCStruc, fpPollED, GET_MEM_BLK_COUNT(sizeof(EHCI_QH)+sizeof(EHCI_QTD))); + fpDevInfo->fpPollEDPtr = NULL; + fpDevInfo->fpPollTDPtr = NULL; + + if(fpDevInfo->fpPollDataBuffer) { + EhciMemFree(fpHCStruc, fpDevInfo->fpPollDataBuffer, + GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + fpDevInfo->fpPollDataBuffer = 0; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCI_ActivatePolling +// +// Description: This function activates the polling QH for the requested +// device. The device may be a USB keyboard or USB hub +// +// Input: fpHCStruc - Pointer to the HC structure +// fpDevInfo - Pointer to the device information structure +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +// Notes: For the keyboard device this routine allocates TDRepeat +// also, if it is not already allocated. This routine allocate +// a polling TD and schedule it to 8ms schedule for keyboards +// and to 1024ms schedule for hubs. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_ActivatePolling( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + EHCI_QH *fpPollED; + EHCI_QTD *fpPollTD; + UINT32 dTmp, dTmp1; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + USB_DEBUG (DEBUG_LEVEL_3, "EHCI_AP dev type %d\n", fpDevInfo->bDeviceType); + + if (EhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + // + // Allocate a QH/qTD for polling QH & qTD + // + fpPollED = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT( + sizeof(EHCI_QH)+sizeof(EHCI_QTD))); + if (!fpPollED) + { + return USB_ERROR; // Memory allocation error + } + + // + // Save the pointers in DeviceInfo structure + // + fpDevInfo->fpPollEDPtr = (UINT8*)fpPollED; + fpPollTD = (EHCI_QTD*)((UINTN)fpPollED + sizeof(EHCI_QH)); + fpDevInfo->fpPollTDPtr = (UINT8*)fpPollTD; + +// +// Setup the polling QH +// Set the QH's dNextqTDPtr field to polling qTD and dAltqTDPtr field to +// EHCI_TERMINATE +// + + fpPollED->fpFirstqTD = fpPollTD; + fpPollED->dNextqTDPtr = (UINT32)(UINTN)fpPollTD; + + // + // Intialize the queue head + // + fpPollED->dAltNextqTDPtr = EHCI_TERMINATE; + fpPollED->dLinkPointer = EHCI_TERMINATE; + + // + // Set the device info pointer in the QH + // + fpPollED->fpDevInfoPtr = (UINT8*)fpDevInfo; + + // + // Get Device address & Endpoint + // + dTmp = ((UINT32)fpDevInfo->bDeviceAddress) | + ((UINT32)(fpDevInfo->IntInEndpoint & 0xF) << 8); + + dTmp |= ((UINT32)fpDevInfo->IntInMaxPkt) << 16; // Set max packet size //(EIP54782) + + dTmp1 = (UINT32)fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + + // + // Assume as a high speed device + // + dTmp |= QH_HIGH_SPEED; // 10b - High speed + + // + // Check for high speed + // + if (dTmp1) + { + dTmp1 = (dTmp1 & 1) << 12; // Bit 12 = full/low speed flag + dTmp &= ~(QH_ENDPOINT_SPEED); + dTmp |= dTmp1; + // + // Set the hub address and port number + // + dTmp1 = (UINT32)EHCI_GetHiSpeedHubPortNumber(fpDevInfo); + dTmp1 = (dTmp1 << 16) | (BIT10 + BIT11 + BIT12); // Split complete Xaction + fpPollED->dEndPntCap |= dTmp1; + } + + // + // Update the endpoint characteristcs field with the data formed + // + fpPollED->dEndPntCharac = dTmp; + + // + // Set a bit in interrupt mask + // + fpPollED->dEndPntCap |= (BIT0 + QH_ONE_XFER); + fpPollED->Interval = EhciTranslateInterval(fpDevInfo->bEndpointSpeed, + fpDevInfo->bPollInterval); + + // + // Set the data toggle + // + fpPollED->dToken |= (UINT32)(UsbGetDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint) << 31); + +// +// Fill the polling qTD with relevant information +// The token field will be set so +// Direction PID = QTD_IN_TOKEN, +// Size = size of the data, +// Data Toggle = QTD_DATA0_TOGGLE, +// Error Count = QTD_THREE_ERRORS, +// Status code = QTD_ACTIVE +// The buffer pointers field will point to the fpBuffer buffer +// which was before initialized to contain a DeviceRequest struc. +// The dNextqTDPtr field will point to the qTDControlSetup +// The dAltNextqTDPtr field will be set to EHCI_TERMINATE +// + fpPollTD->dToken = QTD_IN_TOKEN | + QTD_IOC_BIT | + QTD_THREE_ERRORS | + QTD_ACTIVE; + // + // Set length + // + fpPollTD->dToken |= (UINT32)fpDevInfo->PollingLength << 16; + fpDevInfo->fpPollDataBuffer = EhciMemAlloc(fpHCStruc, + GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + ASSERT(fpDevInfo->fpPollDataBuffer); + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(fpPollTD, + fpDevInfo->fpPollDataBuffer, fpDevInfo->PollingLength); + + // + // Update next & alternate next qTD pointers + // + fpPollTD->dNextqTDPtr = EHCI_TERMINATE; + fpPollTD->dAltNextqTDPtr = EHCI_TERMINATE; + + EhciAddPeriodicQh(fpHCStruc,fpPollED); + + fpPollED->bCallBackIndex = USB_InstallCallBackFunction(EhciPollingTDCallback); + fpPollED->bActive = TRUE; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIDisableKeyRepeat +// +// Description: This function disables the keyboard repeat rate logic by +// enabling the repeat TD +// +// Input: fpHCStruc - Pointer to the HCStruc structure +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_DisableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + EHCI_DESC_PTRS *DescPtr; + EHCI_QH *RepeatQh; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (EhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtr = HcStruc->stDescPtrs.fpEHCIDescPtrs; + + if (DescPtr == NULL) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)DescPtr < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtr + sizeof(EHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + + RepeatQh = DescPtr->fpQHRepeat; + + if (RepeatQh == NULL) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)RepeatQh < gUsbData->fpMemBlockStart) || + ((UINT8*)(RepeatQh + sizeof(EHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + + if (RepeatQh) { + RepeatQh->dTokenReload = ((UINT32)8 << 16) | QTD_IN_TOKEN | QTD_ONE_ERROR; + RepeatQh->bActive = FALSE; + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EHCI_EnableKeyRepeat +// +// Description: This function disables the keyboard repeat rate logic by +// enabling the repeat TD +// +// Parameters: fpHCStruc Pointer to the HCStruc structure +// +// Output: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCI_EnableKeyRepeat ( + HC_STRUC* HcStruc +) +{ + EHCI_DESC_PTRS *DescPtr; + EHCI_QH *RepeatQh; + EHCI_QTD *RepeatQtd; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (EhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtr = HcStruc->stDescPtrs.fpEHCIDescPtrs; + + if (DescPtr == NULL) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)DescPtr < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtr + sizeof(EHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + + RepeatQh = DescPtr->fpQHRepeat; + + if (RepeatQh == NULL) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)RepeatQh < gUsbData->fpMemBlockStart) || + (((UINT8*)RepeatQh + sizeof(EHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + + if ((RepeatQh->dTokenReload & QTD_ACTIVE) == 0) { + RepeatQtd = DescPtr->fpqTDRepeat; + if (RepeatQtd == NULL) { + return USB_ERROR; + } +#if USB_RUNTIME_DRIVER_IN_SMM + if (((UINT8*)RepeatQtd < gUsbData->fpMemBlockStart) || + (((UINT8*)RepeatQtd + sizeof(EHCI_QTD)) > MemBlockEnd)) { + return USB_ERROR; + } +#endif + RepeatQh->dTokenReload = ((UINT32)8 << 16) | QTD_IN_TOKEN | + QTD_ONE_ERROR | QTD_IOC_BIT | QTD_ACTIVE; + + // Update buffer pointers + EHCISetQTDBufferPointers(RepeatQtd, + &RepeatQh->aDataBuffer[0], 8); + + // Re-init the QH pointers + RepeatQh->dCurqTDPtr = 0; + RepeatQh->dAltNextqTDPtr = EHCI_TERMINATE; + RepeatQh->dNextqTDPtr = (UINT32)(UINTN)RepeatQtd; + + // + // Restart the qTD + // + RepeatQh->dToken = 0; + RepeatQtd->dToken = RepeatQh->dTokenReload; + + RepeatQh->bActive = TRUE; + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIResetHC +// +// Description: This function resets the EHCI controller +// +// Input: Pointer to the HCStruc structure +// +// Output: USB_SUCCESS HC successfully reset +// USB_ERROR Error, error log is updated +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIResetHC(HC_STRUC* fpHCStruc) +{ + UINT16 count; + + if (fpHCStruc->DebugPort) return USB_SUCCESS; + // + // Check HC is halted: attempting to reset an actively running HC will + // result in undefined behavior. + // + if (EhciReadOpReg(fpHCStruc, EHCI_USBSTS) & EHCI_HCHALTED) + { + // + // Issue reset + // + EhciSetOpReg(fpHCStruc, EHCI_USBCMD, EHCI_HCRESET); + + // + // EHCI_HCRESET bit is set to zero by the Host Controller when the reset + // process is complete. + // + for (count = 0; count < 500; count++) { + if (!(EhciReadOpReg(fpHCStruc, EHCI_USBCMD) & EHCI_HCRESET)) { + return USB_SUCCESS; + } + FixedDelay(100); // 100 us delay + } + } + + // + // Error - HC reset failed + // + USBLogError(USB_ERR_HC_RESET_FAILED); + + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIInitializesPeriodicSchedule +// +// Description: This function initializes the periodic schedules for the +// EHCI host controller +// +// Input: fpHCStruc - HCStruc for the controller +// dMemAddr - Membase address +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +// Notes: This routine creates 8ms and 32ms schedules +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIInitializePeriodicSchedule( + HC_STRUC* fpHCStruc, + UINT32 dMemBase) +{ + UINT8 *fpPtr; + EHCI_DESC_PTRS *fpDescPtr; + // + // Allocate descriptor structure and fill it in HCStruc + // + fpDescPtr = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT_STRUC(EHCI_DESC_PTRS)); + if (fpDescPtr == NULL) { + USB_DEBUG(DEBUG_LEVEL_4, "EHCI Descriptor struc alloc failed. %d \n", + GET_MEM_BLK_COUNT_STRUC(EHCI_DESC_PTRS)); + return USB_ERROR; + } + + // + // Save the value in the HC struc + // + fpHCStruc->stDescPtrs.fpEHCIDescPtrs = fpDescPtr; + + // Allocate QH/qTD for PeriodicQh + fpPtr = EhciMemAlloc(fpHCStruc, GET_MEM_BLK_COUNT((1 * sizeof(EHCI_QH))+ + (0 * sizeof(EHCI_QTD)))); + if (fpPtr == NULL) { + USB_DEBUG(DEBUG_LEVEL_4, "Schedule of EHCI QH alloc failed.\n"); + return USB_ERROR; + } + + // Save the 1 QH in appropriate location + fpDescPtr->PeriodicQh = (EHCI_QH*)fpPtr; + + EHCIInitializeQueueHead(fpDescPtr->PeriodicQh); + fpDescPtr->PeriodicQh->dNextqTDPtr = EHCI_TERMINATE; + fpDescPtr->PeriodicQh->dAltNextqTDPtr = EHCI_TERMINATE; + fpDescPtr->PeriodicQh->dEndPntCharac = ((UINT32)0x40 << 16) + QH_HIGH_SPEED; + fpDescPtr->PeriodicQh->dLinkPointer = EHCI_TERMINATE; + fpDescPtr->PeriodicQh->dToken = QTD_HALTED; + fpDescPtr->PeriodicQh->Interval = 1; + + EhciAddPeriodicQh(fpHCStruc, fpDescPtr->PeriodicQh); + + return USB_SUCCESS; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIInitializeQueueHead +// +// Description: This function initializes the queue head with default values +// +// Input: fpQH Pointer to queue head +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +EHCIInitializeQueueHead(EHCI_QH *fpQH) +{ + fpQH->dNextqTDPtr = 1; + fpQH->dAltNextqTDPtr = 1; + fpQH->dCurqTDPtr = 0; + + fpQH->dEndPntCap = QH_ONE_XFER; + fpQH->dToken = 0; + fpQH->dEndPntCharac = 0; + fpQH->dBufferPtr0 = 0; + fpQH->dBufferPtr1 = 0; + fpQH->dBufferPtr2 = 0; + fpQH->dBufferPtr3 = 0; + fpQH->dBufferPtr4 = 0; + fpQH->bErrorStatus = 0; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStartPeriodicSchedule +// +// Description: This function starts the periodic schedule for the +// EHCI host controller +// +// Input: Pointer to HcStruc +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIStartPeriodicSchedule( + HC_STRUC* HcStruc +) +{ + UINT16 i; + // + // Start periodic schedule + // + EhciSetOpReg(HcStruc, EHCI_USBCMD, EHCI_PER_SCHED_ENABLE); + + // + // Make sure the HC started the schedules + // + for (i = 0; i < 1000; i++) { + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_PER_SCHED_STATUS) { + break; + } + FixedDelay(10); + } + if (!(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_PER_SCHED_STATUS)) { + return USB_ERROR; + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStopPeriodicSchedule +// +// Description: This function stops the periodic schedule for the +// EHCI USB host controller +// +// Input: HcStruc for the controller +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIStopPeriodicSchedule( + HC_STRUC* HcStruc +) +{ + UINT16 i; + // + // Stop periodic schedule + // + EhciClearOpReg(HcStruc, EHCI_USBCMD, EHCI_PER_SCHED_ENABLE); + + // + // Make sure the HC stopped the schedules + // + for (i = 0; i < 1000; i++) { + if (!(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_PER_SCHED_STATUS)) { + break; + } + FixedDelay(10); + } + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_PER_SCHED_STATUS) { + return USB_ERROR; + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStartAsyncSchedule +// +// Description: This function starts the asynchronous schedule +// +// Input: Pointer to HcStruc +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIStartAsyncSchedule( + HC_STRUC* HcStruc +) +{ + UINT16 i; + // + // Start the Async schedule + // + EhciSetOpReg(HcStruc, EHCI_USBCMD, EHCI_ASYNC_SCHED_ENABLE); + + // + // Make sure the HC started the async. execution + // + for (i = 0; i < 1000; i++) { + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_ASYNC_SCHED_STATUS) { + break; + } + FixedDelay(10); + } + if (!(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_ASYNC_SCHED_STATUS)) { + // + // Stop the host controller (Reset bit 0) + // + EhciClearOpReg(HcStruc, EHCI_USBCMD, EHCI_RUNSTOP); + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + return USB_ERROR; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIStopAsyncSchedule +// +// Description: This function stops the asynchronous transfer and sets the +// asynchronous pointer to null +// +// Input: Pointer to HcStruc +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIStopAsyncSchedule( + HC_STRUC* HcStruc +) +{ + UINT16 i; + + if (!(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_ASYNC_SCHED_STATUS)) { + return USB_SUCCESS; + } + + // + // Stop periodic schedule + // + EhciClearOpReg(HcStruc, EHCI_USBCMD, EHCI_ASYNC_SCHED_ENABLE); + + // + // Make sure the HC stopped the async. execution + // + for (i = 0; i < 1000; i++) { + if (!(EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_ASYNC_SCHED_STATUS)) { + break; + } + FixedDelay(10); + } + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_ASYNC_SCHED_STATUS) { + // + // Stop the host controller (Reset bit 0) + // + EhciClearOpReg(HcStruc, EHCI_USBCMD, EHCI_RUNSTOP); + // The Host Controller must halt within 16 micro-frames after + // software clears the Run bit. + for (i = 0; i < 16; i++) { + if (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_HCHALTED) { + break; + } + FixedDelay(125); // 125 us delay + } + return USB_ERROR; + } + + return USB_SUCCESS; +} + +/* +#if EHCI_ASYNC_BELL_SUPPORT +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIRemoveQHFromAsyncList +// +// Description: This function stops the asynchronous transfer and sets the +// asynchronous pointer to null +// +// Input: Pointer to HCStruc +// Pointer to the Queue head that has to be removed +// from the asynchronous schedule +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +EHCIRemoveQHFromAsyncList( + HC_STRUC *fpHCStruc, + EHCI_QH *fpQH +) +{ + // + // Stop the Async transfer + // + EHCIStopAsyncSchedule(fpHCStruc); + + // + // Remove the queue head from the Async list + // + gUsbData->fpQHAsyncXfer->dLinkPointer = fpQH->dLinkPointer; + + // + // Pointer is advanced. The queue head is totally removed from the list! + // +} +#endif +*/ + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIAddPeriodicQH +// +// Description: This function adds a QH to the frame list +// +// Input: Pointer to the QH to be added +// Absolute pointer to the frame list +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EhciAddPeriodicQh( + HC_STRUC *HcStruc, + EHCI_QH *NewQh +) +{ + UINT16 Index; + UINT32 *PrevPtr; + UINT32 LinkPtr; + EHCI_QH *Qh; + EFI_STATUS Status = EFI_SUCCESS; + + if (NewQh == NULL || NewQh->Interval == 0) { + return USB_ERROR; + } + + for (Index = HcStruc->SplitPeriodicIndex; Index < HcStruc->wAsyncListSize; Index += NewQh->Interval) { + PrevPtr = &HcStruc->fpFrameList[Index]; + LinkPtr = *PrevPtr; + while (!(LinkPtr & EHCI_TERMINATE)){ + Qh = (EHCI_QH*)(LinkPtr & EHCI_POINTER_MASK); +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(EHCI_QH)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Qh->Interval <= NewQh->Interval) { + break; + } + PrevPtr = &Qh->dLinkPointer; + LinkPtr = *PrevPtr; + } + + if (!(LinkPtr & EHCI_TERMINATE) && (Qh == NewQh)) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + NewQh->dLinkPointer = *PrevPtr; + *PrevPtr = (UINT32)((UINTN)NewQh | EHCI_QUEUE_HEAD); + + } + + if (HcStruc->SplitPeriodicIndex == MAX_SPLIT_PERIODIC_NUMBER) { + HcStruc->SplitPeriodicIndex = 0; + } else { + HcStruc->SplitPeriodicIndex++; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EhciRemovePeriodicQh +// +// Description: This function removes a QH from the frame list +// +// Input: Pointer to the QH to be added +// Absolute pointer to the frame list +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EhciRemovePeriodicQh ( + HC_STRUC *HcStruc, + EHCI_QH *RetiredQh +) +{ + UINT16 Index; + UINT32 *PrevPtr; + UINT32 LinkPtr; + EHCI_QH *Qh; + EFI_STATUS Status = EFI_SUCCESS; + + if (RetiredQh == NULL || RetiredQh->Interval == 0) { + return USB_ERROR; + } + + EHCIStopPeriodicSchedule(HcStruc); + + for (Index = 0; Index < HcStruc->wAsyncListSize; Index++) { + PrevPtr = &HcStruc->fpFrameList[Index]; + LinkPtr = *PrevPtr; + + while (!(LinkPtr & EHCI_TERMINATE)){ + Qh = (EHCI_QH*)(LinkPtr & EHCI_POINTER_MASK); +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(EHCI_QH)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Qh == RetiredQh) { + break; + } + PrevPtr = &Qh->dLinkPointer; + LinkPtr = *PrevPtr; + } + + if (LinkPtr & EHCI_TERMINATE) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = RetiredQh->dLinkPointer; + } + + RetiredQh->dLinkPointer = EHCI_TERMINATE; + + EHCIStartPeriodicSchedule(HcStruc); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCISetQTDBufferPointers +// +// Description: This function will set the 5 buffer pointer in the qTD +// appropriately depending upon the input size +// +// Input: fpQtd - Pointer to the qTD +// fpBuf - 32bit absolute buffer pointer +// wSize - Amount of data to be transferred +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +EHCISetQTDBufferPointers( + EHCI_QTD *fpQtd, + UINT8 *fpBuf, + UINT32 dSize +) +{ + UINT16 wBufSize; + UINT8 *fpBuffer = fpBuf; + UINT32 *fpBufferPtr; + UINT16 w4KRemainder; + + // + // Fill the buffer pointers with 0s + // + fpQtd->dBufferPtr0 = 0; + fpQtd->dBufferPtr1 = 0; + fpQtd->dBufferPtr2 = 0; + fpQtd->dBufferPtr3 = 0; + fpQtd->dBufferPtr4 = 0; + fpQtd->dAltNextqTDPtr = 1; + + // + // If size to transfer is 0 skip updating pointers + // + if (!dSize) + { + return; + } + + // + // Make sure the amount of data to be xferred is 16K or less + // + wBufSize = (UINT16)((dSize > MAX_EHCI_DATA_SIZE) ? MAX_EHCI_DATA_SIZE : dSize); + + fpBufferPtr = &fpQtd->dBufferPtr0; + + for (;;) + { + *fpBufferPtr = (UINT32)(UINTN)fpBuffer; + // + // Calculate the number of bytes that can be transferred using current + // buffer pointer + // + w4KRemainder = (UINT16)((((UINT32)((UINTN)fpBuffer+0x1000)) & 0xFFFFF000) - + (UINT32)(UINTN)fpBuffer); + + // + // Check whether all the bytes can be accomadated in the current buffer + // + if (w4KRemainder >= wBufSize) + { + break; // Yes. Current Buffer is sufficient for the rest of data + } + + // + // We have more data to transfer - adjust data and store it in the next pointer + // + wBufSize = (UINT16)(wBufSize - w4KRemainder); // Amount of data remaining + fpBuffer = fpBuffer + w4KRemainder; // Adjust buffer (4K bound) + fpBufferPtr++; // Next buffer pointer + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIWaitForTransferComplete +// +// Description: This function waits until the requested QH completes or +// the transaction time-out +// +// Input: fpHCStruc - Pointer to HCStruc of the host controller +// fpQH - Pointer to the QH which has to be completed +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +EHCIWaitForTransferComplete( + HC_STRUC *fpHCStruc, + EHCI_QH *fpQH, + DEV_INFO* fpDevInfo + +) +{ + UINT32 dCount ; + UINT32 countLimit = gUsbData->wTimeOutValue * 100; // makes it number of macrosecond units + UINT16 Status = USB_ERROR; + + // + // Check status change loop iteration + // + for(dCount = 0; !countLimit || dCount < countLimit; dCount++) + { + EHCIProcessQH(fpHCStruc, fpQH); + if(fpQH->bActive == FALSE) { + Status = USB_SUCCESS; + break; + } + FixedDelay(10); // 60 microsec + } + + if(fpQH->bActive == TRUE) { + // Set the QH as in-active + fpQH->bActive = FALSE; + Status = USB_ERROR; + USB_DEBUG (DEBUG_LEVEL_3, "EHCI Time-Out\n"); + } + + // Service all interrupts + EHCI_ProcessInterrupt(fpHCStruc); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIProcessQH +// +// Description: This function whether all the TD's in the QH is completed +// +// Input: fpQH - Pointer to the QH which has to be completed +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EHCIProcessQH( + HC_STRUC *fpHCStruc, + EHCI_QH *fpQH +) +{ + EHCI_QTD *fpQTD = fpQH->fpFirstqTD; + EFI_STATUS Status = EFI_SUCCESS; + + for (;;) { + if (fpQTD == NULL) { + return USB_ERROR; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)fpQTD, sizeof(EHCI_QTD)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + // + // Check whether the qTD is active, if so. Exit! + // + if (fpQTD->dToken & QTD_ACTIVE) { + return USB_ERROR; + } + + // + // Check for halt condition, if halted - exit + // + if (fpQTD->dToken & QTD_HALTED) { + // + // Set the QH halted status + // + fpQH->bErrorStatus = QTD_HALTED; + // + // Set the QH as in-active + // + fpQH->bActive = FALSE; + break; + } + // + // qTD is not active and not halted. That is it is completed successfully + // Check whether this qTD is the last one in the list + // + if (fpQTD->dNextqTDPtr & EHCI_TERMINATE) { + // + // Set the QH as in-active + // + fpQH->bActive = FALSE; + break; + } + + // + // More qTDs are in the list. Process next qTD + // + fpQTD = (EHCI_QTD*)(UINTN)fpQTD->dNextqTDPtr; + } + + if ((fpQH->bCallBackIndex) && (fpQH->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[fpQH->bCallBackIndex - 1]) { + if ((gUsbData->aCallBackFunctionTable[fpQH->bCallBackIndex - 1]) + != EhciRepeatTDCallback) { + Status = UsbDevInfoValidation((DEV_INFO*)fpQH->fpDevInfoPtr); + + if (EFI_ERROR(Status)) { + return USB_ERROR; + } + } + (*gUsbData->aCallBackFunctionTable[fpQH->bCallBackIndex - 1]) + (fpHCStruc, (DEV_INFO*)fpQH->fpDevInfoPtr, + (UINT8*)fpQH, NULL, 0); + } + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIProcessPeriodicList +// +// Description: This function parses through the periodic list to find +// completed qTD. If a qTD is done it will call its associated +// call back function (in device info structure) and restarts +// the polling qTD +// +// Input: fpHCStruc - Pointer to HCStruc of the host controller +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +EHCIProcessPeriodicList( + HC_STRUC *HcStruc +) +{ + UINT16 Index; + UINT32 *PrevPtr; + UINT32 LinkPtr; + EHCI_QH *Qh; + UINT32 OrgQhLinkPointer; + EFI_STATUS Status = EFI_SUCCESS; + + + // + // Get the first entry in the periodic list. This QH list will link to all + // the periodic QH's + // + + for (Index = 0; Index <= MAX_SPLIT_PERIODIC_NUMBER; Index ++) { + PrevPtr = &HcStruc->fpFrameList[Index]; + LinkPtr = *PrevPtr; + + while (!(LinkPtr & EHCI_TERMINATE)) { + Qh = (EHCI_QH*)(LinkPtr & EHCI_POINTER_MASK); +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(EHCI_QH)); + if (EFI_ERROR(Status)) { + return; + } +#endif + // Process only QHeads, skip the other types + if ((Qh->dLinkPointer & 6) == EHCI_QUEUE_HEAD) { + + // Check whether this QH is actived + if (Qh->bActive == TRUE) { + OrgQhLinkPointer = Qh->dLinkPointer; + EHCIProcessQH(HcStruc, Qh); + // Qh is changed, we re-parses through the list. + if (Qh->dLinkPointer != OrgQhLinkPointer) { + LinkPtr = *PrevPtr; + continue; + } + } + } + + LinkPtr = Qh->dLinkPointer; + } + + } + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EhciPollingTDCallback +// +// Description: This function is called when a polling TD from the TD pool +// completes an interrupt transaction to its assigned device. +// This routine should process any data in the TD's data buffer, +// handle any errors, and then copy the TD's CSReloadValue field +// into its control status field to put the TD back into service. +// +// Input: HcStruc Pointer to the HCStruc structure +// DevInfo NULL (pDevInfo is not valid) +// QueueHead Pointer to the QH that completed +// Buffer Not used +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EhciPollingTDCallback( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *QueueHead, + UINT8 *Buffer, + UINT16 DataLength +) +{ + EHCI_QH* PollQh = (EHCI_QH*)QueueHead; + EHCI_QTD *PollQtd = PollQh->fpFirstqTD; + UINT16 BytesTransferred; + EFI_STATUS Status = EFI_SUCCESS; + +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PollQtd, sizeof(EHCI_QTD)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + + // Update datat toggle value + UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, + (UINT8)((PollQh->dToken & QH_DATA_TOGGLE) >> 31)); + + if (!(PollQh->dToken & QTD_STATUS_FIELD)) { + if ((DevInfo->bCallBackIndex) && (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1]) { + // + // Get the size of data transferred + // + BytesTransferred = DevInfo->PollingLength - (UINT16)((PollQtd->dToken & ~(QTD_DATA_TOGGLE)) >> 16); + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1]) + (HcStruc, DevInfo, (UINT8*)PollQtd, DevInfo->fpPollDataBuffer, BytesTransferred); + } + } + } + + // Keep the PID code bit in the qTD + PollQtd->dToken &= QTD_DIRECTION_PID; + + // + // Set length + // + PollQtd->dToken |= (UINT32)DevInfo->PollingLength << 16; + + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(PollQtd, + DevInfo->fpPollDataBuffer, DevInfo->PollingLength); + + // + // Re-init the QH pointers + // + PollQh->dToken &= QH_DATA_TOGGLE; + PollQh->dCurqTDPtr = 0; + PollQh->dAltNextqTDPtr = EHCI_TERMINATE; + PollQh->dBufferPtr0 = 0; + PollQh->dBufferPtr1 = 0; + PollQh->dBufferPtr2 = 0; + PollQh->dBufferPtr3 = 0; + PollQh->dBufferPtr4 = 0; + // + // Update next & alternate next qTD pointers + // + PollQtd->dNextqTDPtr = EHCI_TERMINATE; + PollQtd->dAltNextqTDPtr = EHCI_TERMINATE; + PollQh->dNextqTDPtr = (UINT32)(UINTN)PollQtd; + + // + // Restart the qTD + // + PollQtd->dToken |= (QTD_IOC_BIT | QTD_THREE_ERRORS | QTD_ACTIVE); + PollQh->bActive = TRUE; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EHCIRepeatTDCallback +// +// Description: This function is called when qTdRepeat completes +// a transaction. This qTD runs a dummy interrupt transaction +// to a non-existant device address for the purpose of +// generating a periodic timeout interrupt which in turn +// is used to generate keyboard repeat or update LED status. +// +// Input: HcStruc Pointer to the HCStruc structure +// DevInfo NULL (pDevInfo is not valid) +// QueueHead Pointer to the QH that completed +// Buffer Not used +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +EhciRepeatTDCallback( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *QueueHead, + UINT8 *Buffer, + UINT16 DataLength +) +{ + EHCI_QH *RepeatQh = (EHCI_QH*)QueueHead; + EHCI_QTD *RepeatQtd = RepeatQh->fpFirstqTD; + EFI_STATUS Status = EFI_SUCCESS; + +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)RepeatQtd, sizeof(EHCI_QTD)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + +#if USB_DEV_KBD + USBKBDPeriodicInterruptHandler(HcStruc); +#endif + + if (RepeatQh->dTokenReload & QTD_ACTIVE) { + // + // Update buffer pointers + // + EHCISetQTDBufferPointers(RepeatQtd, + &RepeatQh->aDataBuffer[0], 8); + + // + // Re-init the QH pointers + // + RepeatQh->dToken &= QH_DATA_TOGGLE; + RepeatQh->dCurqTDPtr = 0; + RepeatQh->dAltNextqTDPtr = EHCI_TERMINATE; + RepeatQh->dBufferPtr0 = 0; + RepeatQh->dBufferPtr1 = 0; + RepeatQh->dBufferPtr2 = 0; + RepeatQh->dBufferPtr3 = 0; + RepeatQh->dBufferPtr4 = 0; + RepeatQh->dNextqTDPtr = (UINT32)(UINTN)RepeatQtd; + + // + // Restart the qTD + // + RepeatQh->dToken = 0; + RepeatQtd->dToken = RepeatQh->dTokenReload; + + RepeatQh->bActive = TRUE; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EhciIsHalted +// +// Description: This function check whether HC is halted. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +EhciIsHalted ( + HC_STRUC *HcStruc +) +{ + return (EhciReadOpReg(HcStruc, EHCI_USBSTS) & EHCI_HCHALTED) == EHCI_HCHALTED; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EhciTranslateInterval +// +// Description: This function calculates the polling rate in frames unit. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +EhciTranslateInterval( + UINT8 Speed, + UINT8 Interval +) +{ + UINT8 BitCount = 0; + UINT16 PollingRate = 0; + + if (Speed == USB_PORT_STAT_DEV_HISPEED) { + // For high-speed interrupt endpoints, the Interval value must be + // from 1 to 16 + ASSERT(Interval >= 1 && Interval <= 16); + + PollingRate = (1 << (Interval - 1)) >> 3; + return PollingRate != 0 ? PollingRate : 1; + } + + // For full-/low-speed interrupt endpoints, the Interval value should + // be from 1 to 255 + ASSERT(Interval >= 1 && Interval <= 255); + + for (BitCount = 0; Interval != 0; BitCount++) { + Interval >>= 1; + } + return (1 << (BitCount - 1)); +} + +//========================================================================== + +UINT32 +EhciReadPciReg( + HC_STRUC *HcStruc, + UINT32 Offset +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + return ReadPCIConfig(HcStruc->wBusDevFuncNum, Offset); +#else + EFI_STATUS Status; + UINT32 Data = 0; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + Offset, + 1, + &Data); + ASSERT_EFI_ERROR(Status); + return Data; +#endif +} + + +VOID +EhciWritePciReg( + HC_STRUC *HcStruc, + UINT32 Offset, + UINT32 Data +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, Offset, Data); + return; +#else + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint32, + Offset, + 1, + &Data); + ASSERT_EFI_ERROR(Status); + return; +#endif +} + +UINT32 +EhciReadHcMem( + HC_STRUC *HcStruc, + UINT32 Offset +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + if (Offset > HcStruc->BaseAddressSize) { + return 0; + } + return DwordReadMem((UINT32)HcStruc->BaseAddress, Offset); +#else + EFI_STATUS Status; + UINT32 Data = 0; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + Offset, + 1, + &Data); + ASSERT_EFI_ERROR(Status); + return Data; +#endif +} + +VOID +EhciWriteHcMem( + HC_STRUC *HcStruc, + UINT32 Offset, + UINT32 Data +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + if (Offset > HcStruc->BaseAddressSize) { + return; + } + DwordWriteMem((UINT32)HcStruc->BaseAddress, Offset, Data); + return; +#else + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + 0, + Offset, + 1, + &Data); + ASSERT_EFI_ERROR(Status); + return; +#endif +} + +UINT32 +EhciReadOpReg( + HC_STRUC *HcStruc, + UINT32 Offset +) +{ + return EhciReadHcMem(HcStruc, HcStruc->bOpRegOffset + Offset); +} + +VOID +EhciWriteOpReg( + HC_STRUC *HcStruc, + UINT32 Offset, + UINT32 Data +) +{ + EhciWriteHcMem(HcStruc, HcStruc->bOpRegOffset + Offset, Data); + return; +} + +VOID +EhciSetOpReg( + HC_STRUC *HcStruc, + UINT32 Offset, + UINT32 Bit +) +{ + UINT32 Data; + + Data = EhciReadOpReg(HcStruc, Offset) | Bit; + EhciWriteOpReg(HcStruc, Offset, Data); + return; +} + +VOID +EhciClearOpReg( + HC_STRUC *HcStruc, + UINT32 Offset, + UINT32 Bit +) +{ + UINT32 Data; + + Data = EhciReadOpReg(HcStruc, Offset) & ~Bit; + EhciWriteOpReg(HcStruc, Offset, Data); + return; +} + +UINT32 +EhciReadDebugReg( + HC_STRUC *HcStruc, + UINT8 BarIndex, + UINT32 Offset +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + UINT8 BarOffset[6] = {0x10, 0x14, 0x18, 0x1C, 0x20, 0x24}; + UINT32 DebugPortsMem; + + DebugPortsMem = EhciReadPciReg(HcStruc, BarOffset[BarIndex]); + return DwordReadMem(DebugPortsMem, Offset); +#else + EFI_STATUS Status; + UINT32 Data = 0; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint32, + BarIndex, + Offset, + 1, + &Data); + ASSERT_EFI_ERROR(Status); + return Data; +#endif +} + +VOID* +EhciMemAlloc( + HC_STRUC *HcStruc, + UINT16 NumBlks +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + return USB_MemAlloc(NumBlks); +#else + UINT32 SavedMemPages = gUsbData->MemPages; + UINT8 *SavedMemPool = gUsbData->fpMemBlockStart; + UINT32 SavedMemBlkStsBytes = gUsbData->MemBlkStsBytes; + UINT32 *SavedMemBlsSts = gUsbData->aMemBlkSts; + VOID* MemPtr; + + gUsbData->MemPages = HcStruc->MemPoolPages; + gUsbData->fpMemBlockStart = HcStruc->MemPool; + gUsbData->MemBlkStsBytes = HcStruc->MemBlkStsBytes; + gUsbData->aMemBlkSts = HcStruc->MemBlkSts; + + MemPtr = USB_MemAlloc(NumBlks); + + gUsbData->MemPages = SavedMemPages; + gUsbData->fpMemBlockStart = SavedMemPool; + gUsbData->MemBlkStsBytes = SavedMemBlkStsBytes; + gUsbData->aMemBlkSts = SavedMemBlsSts; + + return MemPtr; +#endif +} + +VOID +EhciMemFree( + HC_STRUC *HcStruc, + VOID* MemPtr, + UINT16 NumBlks +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + USB_MemFree(MemPtr, NumBlks); +#else + UINT32 SavedMemPages = gUsbData->MemPages; + UINT8 *SavedMemPool = gUsbData->fpMemBlockStart; + UINT32 SavedMemBlkStsBytes = gUsbData->MemBlkStsBytes; + UINT32 *SavedMemBlsSts = gUsbData->aMemBlkSts; + + gUsbData->MemPages = HcStruc->MemPoolPages; + gUsbData->fpMemBlockStart = HcStruc->MemPool; + gUsbData->MemBlkStsBytes = HcStruc->MemBlkStsBytes; + gUsbData->aMemBlkSts = HcStruc->MemBlkSts; + + USB_MemFree(MemPtr, NumBlks); + + gUsbData->MemPages = SavedMemPages; + gUsbData->fpMemBlockStart = SavedMemPool; + gUsbData->MemBlkStsBytes = SavedMemBlkStsBytes; + gUsbData->aMemBlkSts = SavedMemBlsSts; + + return; +#endif +} + +UINT8 +EhciDmaMap( + HC_STRUC *HcStruc, + UINT8 Direction, + UINT8 *BufferAddr, + UINT32 BufferSize, + UINT8 **PhyAddr, + VOID **Mapping +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + *PhyAddr = BufferAddr; +#else + EFI_PCI_IO_PROTOCOL_OPERATION Operation; + EFI_PHYSICAL_ADDRESS Addr; + EFI_STATUS Status; + UINTN Bytes = BufferSize; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + if (Direction & BIT7) { + Operation = EfiPciIoOperationBusMasterWrite; + } else { + Operation = EfiPciIoOperationBusMasterRead; + } + + Status = PciIo->Map ( + PciIo, + Operation, + BufferAddr, + &Bytes, + &Addr, + Mapping + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status) || Bytes != BufferSize) { + return USB_ERROR; + } + + *PhyAddr = (UINT8*)Addr; +#endif + return USB_SUCCESS; +} + +UINT8 +EhciDmaUnmap( + HC_STRUC *HcStruc, + VOID *Mapping +) +{ +#if !USB_RUNTIME_DRIVER_IN_SMM + + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo = HcStruc->PciIo; + + Status = PciIo->Unmap(PciIo, Mapping); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + return USB_SUCCESS; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/ehci.h b/Core/EM/usb/rt/ehci.h new file mode 100644 index 0000000..2dbc894 --- /dev/null +++ b/Core/EM/usb/rt/ehci.h @@ -0,0 +1,420 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ehci.h 12 7/26/13 2:33a Ryanchou $ +// +// $Revision: 12 $ +// +// $Date: 7/26/13 2:33a $ +//****************************************************************************//--------------------------------------------------------------------------- +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ehci.h $ +// +// 12 7/26/13 2:33a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 11 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 10 5/04/12 5:24a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 9 7/19/11 5:17a Ryanchou +// [TAG] EIP64498 +// [Category] New Feature +// [Description] Implement EHCI key repeat function. +// [Files] ehci.c, ehci.h, usb.c, usbdef.h +// +// 8 3/29/11 10:49p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 7 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 6 3/20/07 12:21p Olegi +// +// 4 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 12/22/05 9:43a Olegi +// Ownership definitons corrected. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Ehci.h +// +// Description: AMI USB EHCI support header +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// Avoid including multiple instance of this file +#ifndef __EHCI_H +#define __EHCI_H + +// Global equates for EHCI +//------------------------------------------------------------------------- +#define EHCI_FRAMELISTSIZE 1024 // Number of DWORDs in frame list + +// Maximum data that can be transferred in a transaction +#define MAX_EHCI_DATA_SIZE 16 * 1024 + +// Mask for masking unwanted bits in the QH & qTD pointers +#define EHCI_POINTER_MASK 0xFFFFFFE0 // Mask bit 0-4 + +// Capability Registers +//------------------------------------------------------------------------- +// These registers specify the limits, restrictions and capabilities of the +// host controller implementation +//------------------------------------------------------------------------- +#define EHCI_VERCAPLENGTH 0 // Interface Version and Capability + // Register Length +#define EHCI_HCSPARAMS 4 // Structural Parameters + // EHCI_HCSPARAMS bit definitions + #define EHCI_N_PORTS BIT0+BIT1+BIT2+BIT3 // Number of implemented + // ports + #define EHCI_PPC BIT4 // Port Power Control + #define EHCI_PRR BIT7 // Port Routing Rules + #define EHCI_N_PCC BIT8+BIT9+BIT10+BIT11 // Number of Ports per + // Companion Controller + #define EHCI_N_CC BIT12+BIT13+BIT14+BIT15 // Number of Companion + // Controllers + #define EHCI_P_INDICATOR BIT16 // Port Indicators + #define EHCI_DEBUG_N BIT20+BIT21+BIT22+BIT23 // Debug Port Number +//--------------------------------------- +#define EHCI_HCCPARAMS 8 // Capability Parameters + // EHCI_HCCPARAMS bit definitions + #define EHCI_64BIT_CAP 0x01 // 64-bit addressing capability + #define EHCI_PFLFLAG 0x02 // Programmable Frame List Flag + #define EHCI_ASP_CAP 0x04 // Asynchronous Schedule Park Capability + #define EHCI_IST 0xF0 // Isochronous Scheduling Threshold + #define EHCI_EECP 0xFF00 // EHCI Extended Capabilities Pointer +//--------------------------------------- +#define EHCI_HCSP_PORTROUTE 0x0C // Companion Port Route Description + +// Host Controller operational registers +//------------------------------------------------------------------------- +// The following equates specify the HC operational registers as offsets of +// the operational register base. Operational register base is calculated by +// adding the value in the first capabilities register (EHCI_VERCAPLENGTH) to +// the base address of EHCI HC register address space. +//------------------------------------------------------------------------- +#define EHCI_USBCMD 0 // USB Command + // EHCI_USBCMD bit definitions + #define EHCI_RUNSTOP BIT0 + #define EHCI_HCRESET BIT1 + #define EHCI_FRM1024 0 // Reset BIT2 and BIT3 before + #define EHCI_FRM512 BIT2 // setting the new Frame List Size + #define EHCI_FRM256 BIT3 + #define EHCI_PER_SCHED_ENABLE BIT4 + #define EHCI_ASYNC_SCHED_ENABLE BIT5 + #define EHCI_INT_ASYNC_ADVANCE_ENABLE BIT6 + #define EHCI_INTTHRESHOLD (8 << 16) +//--------------------------------------- +#define EHCI_USBSTS 4 // USB Status + // EHCI_USBSTS bit definitions + #define EHCI_USB_INTERRUPT BIT0 // Interrupt + #define EHCI_USB_ERROR_INTERRUPT BIT1 // Error interrupt + #define EHCI_PORT_CHANGE_DETECT BIT2 // Port Change Detect + #define EHCI_FRAME_LIST_ROLLOVER BIT3 // Frame List Rollover + #define EHCI_HOST_SYSTEM_ERROR BIT4 // Host System Error + #define EHCI_INT_ASYNC_ADVANCE BIT5 // Interrupt on Async Advance + #define EHCI_HCHALTED BIT12 // HCHalted + #define EHCI_RECLAIM BIT13 // Reclamation + #define EHCI_PER_SCHED_STATUS BIT14 // Periodic Schedule Status + #define EHCI_ASYNC_SCHED_STATUS BIT15 // Asynchronous Schedule Status +//--------------------------------------- +#define EHCI_USBINTR 8 // USB Interrupt Enable + // EHCI_USBINTR bit definitions + #define EHCI_USBINT_EN BIT0 // Interrupt Enable + #define EHCI_USBERRINT_EN BIT1 // Error Interrupt Enable + #define EHCI_PCDINT_EN BIT2 // Port Change Detect Interrupt Enable + #define EHCI_FLRINT_EN BIT3 // Frame List Rollover Interrupt Enable + #define EHCI_HSEINT_EN BIT4 // Host System Error Interrupt Enable + #define EHCI_IAAINT_EN BIT5 // Interrupt on Async Advance Enable +//--------------------------------------- +#define EHCI_FRINDEX 0x0C // USB Frame Index +#define EHCI_CTRLDSSEGMENT 0x10 // 4G Segment Selector +#define EHCI_PERIODICLISTBASE 0x14 // Frame List Base Address +#define EHCI_ASYNCLISTADDR 0x18 // Next Asynchronous List Address +#define EHCI_CONFIGFLAG 0x40 // Configured Flag Register + +#define EHCI_PORTSC 0x44 // Port Status/Control + // EHCI_PORTSC bit definitions + #define EHCI_CURRENTCONNECTSTATUS BIT0 + #define EHCI_CONNECTSTATUSCHANGE BIT1 + #define EHCI_PORTENABLE BIT2 + #define EHCI_PORTENABLESTATUSCHANGE BIT3 + #define EHCI_OVERCURRENTACTIVE BIT4 + #define EHCI_OVERCURRENTCAHGE BIT5 + #define EHCI_FORCEPORTRESUME BIT6 + #define EHCI_SUSPEND BIT7 + #define EHCI_PORTRESET BIT8 + #define EHCI_LINE_STATUS (BIT10 | BIT11) + #define EHCI_DMINUSBIT BIT10 + #define EHCI_DPLUSBIT BIT11 + #define EHCI_PORTPOWER BIT12 + #define EHCI_PORTOWNER BIT13 + #define EHCI_WKCNNT_E BIT20 // Wake On Connect Enable + #define EHCI_WKDSCNNT_E BIT21 // Wake On Disconnect Enable + #define EHCI_WKOC_E BIT22 // Wake On Over-current Enable + +//EHCI Extended Capability registers +//------------------------------------------------ +#define EHCI_LEGACY_REG 0x00 +#define EHCI_LEGACY_CTRL_STS_REG 0x04 + +//USB Legacy Suport Extended Capibility +//------------------------------------------------ +#define EHCI_CAP_ID 0x000000FF +#define EHCI_NEXT_EECP 0x0000FF00 +#define EHCI_HC_BIOS 0x00010000 +#define EHCI_HC_OS 0x01000000 + +//USB Legacy Suport Control/Status +//------------------------------------------------ +#define EHCI_SMI 0x001 +#define EHCI_ERROR_SMI 0x002 +#define EHCI_PORT_CHANGE_SMI 0x004 +#define EHCI_FRAME_LIST_ROLL_OVER_SMI 0x008 +#define EHCI_HOST_SYSTEM_ERROR_SMI 0x010 +#define EHCI_ASYNC_ADVANCE_SMI 0x020 +#define EHCI_OWNERSHIP_CHANGE_SMI 0x2000 +#define EHCI_SMI_PCI_COMMAND 0x4000 +#define EHCI_SMI_ON_BAR 0x8000 +#define EHCI_SMI_STS 0x0001 +#define EHCI_ERROR_SMI_STS 0x0002 +#define EHCI_PORT_CHANGE_STS 0x0004 +#define EHCI_FRAME_LIST_ROLL_OVER_SMI_STS 0x0008 +#define EHCI_SMI_HOST_SYSTEM_ERROR 0x0010 +#define EHCI_ASYNC_ADVANCE_SMI_STS 0x0020 +#define EHCI_OWNERSHIP_CHANGE_SMI_STS 0x2000 +#define EHCI_SMI_PCI_COMMAND_STS 0x4000 +#define EHCI_SMI_ON_BAR_STS 0x8000 + +#define EHCI_PCI_TRAP_SMI EHCI_OWNERSHIP_CHANGE_SMI +#define EHCI_ALL_SMI 0x0E03F +#define EHCI_ALL_LEGACY_SMI 0x0003F + +//------------------------------------------------------------------------- +// Descriptor structure used to store TD and ED addresses +//------------------------------------------------------------------------- +// +// Bit definitions for a generic pointer +// +#define EHCI_TERMINATE 1 + +#pragma pack(push, 1) + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: EHCI_QTD +// +// Description: This is EHCI queue TD data structure used to perform +// non-isochronous transaction in EHCI based HC +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// dNextqTDPtr DWORD Pointer to next qTD +// dAltNextqTDPtr DWORD Pointer to alternate next qTD +// dToken DWORD Token double word +// dBufferPtr0 DWORD Buffer pointer page 0 +// dBufferPtr1 DWORD Buffer pointer page 1 +// dBufferPtr2 DWORD Buffer pointer page 2 +// dBufferPtr3 DWORD Buffer pointer page 3 +// dBufferPtr4 DWORD Buffer pointer page 4 +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + UINT32 dNextqTDPtr; + UINT32 dAltNextqTDPtr; + UINT32 dToken; + UINT32 dBufferPtr0; + UINT32 dBufferPtr1; + UINT32 dBufferPtr2; + UINT32 dBufferPtr3; + UINT32 dBufferPtr4; +#if EHCI_64BIT_DATA_STRUCTURE +// For 64bit data structure + UINT32 dReserved[8]; +#endif +} EHCI_QTD; + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: EHCI_QH +// +// Description: This is EHCI queue head data structure used to perform +// non-isochronous transaction in EHCI based HC +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// dLinkPointer DWORD Pointer to the next queue head +// dEndPntCharac DWORD Endpoint characteristics settings +// dEndPntCap DWORD Endpoint capability settings +// dCurqTDPtr DWORD Pointer to current qTD +// dNextqTDPtr DWORD Pointer to next qTD +// dAltNextqTDPtr DWORD Pointer to alternate next qTD +// dToken DWORD Token double word +// dBufferPtr0 DWORD Buffer pointer page 0 +// dBufferPtr1 DWORD Buffer pointer page 1 +// dBufferPtr2 DWORD Buffer pointer page 2 +// dBufferPtr3 DWORD Buffer pointer page 3 +// dBufferPtr4 DWORD Buffer pointer page 4 +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + UINT32 dLinkPointer; + UINT32 dEndPntCharac; + UINT32 dEndPntCap; + UINT32 dCurqTDPtr; + UINT32 dNextqTDPtr; + UINT32 dAltNextqTDPtr; + UINT32 dToken; + UINT32 dBufferPtr0; + UINT32 dBufferPtr1; + UINT32 dBufferPtr2; + UINT32 dBufferPtr3; + UINT32 dBufferPtr4; +#if EHCI_64BIT_DATA_STRUCTURE +// For 64bit data structure + UINT32 dReserved[8]; +#endif + UINT8 bCallBackIndex; + EHCI_QTD *fpFirstqTD; + UINT8 bActive; + UINT8 bErrorStatus; + UINT8 *fpDevInfoPtr; + UINT8 aDataBuffer[8]; + UINT32 dTokenReload; + UINT16 Interval; + UINT8 Pad[31-2*sizeof(void*)]; // sizeof(EHCI_QH)should be divisible by 32 +} EHCI_QH; // because of 32 bin pointers; the size of + // the structure has to be 32 bytes aligned +#pragma pack(pop) + +#define EHCI_QUEUE_HEAD 2 // Queue head id + +// Bit definition for queue transfer descriptor token fields +//------------------------------------------------------------------------- +#define QTD_DATA_TOGGLE 0x80000000 // BIT 31 + #define QTD_SETUP_TOGGLE 0x00000000 + #define QTD_DATA0_TOGGLE 0x00000000 + #define QTD_DATA1_TOGGLE 0x80000000 + #define QTD_STATUS_TOGGLE 0x80000000 +#define QTD_XFER_DATA_SIZE 0x7FFF0000 // BIT 30:16 +#define QTD_IOC_BIT 0x00008000 // BIT 15 +#define QTD_ERROR_COUNT 0x00000C00 + #define QTD_NO_ERRORS 0x00000000 + #define QTD_ONE_ERROR 0x00000400 + #define QTD_TWO_ERRORS 0x00000800 + #define QTD_THREE_ERRORS 0x00000C00 +#define QTD_DIRECTION_PID 0x00000300 + #define QTD_OUT_TOKEN 0x00000000 + #define QTD_IN_TOKEN 0x00000100 + #define QTD_SETUP_TOKEN 0x00000200 +#define QTD_STATUS_FIELD 0x000000FF + #define QTD_ACTIVE 0x00000080 + #define QTD_HALTED 0x00000040 + #define QTD_BUFFER_ERROR 0x00000020 + #define QTD_BABBLE 0x00000010 + #define QTD_XACT_ERROR 0x00000008 + #define QTD_MISSED_UFRAME 0x00000004 + #define QTD_SPLIT_XSTATE 0x00000002 + #define QTD_START_SPLIT 0x00000000 + #define QTD_COMPLETE_SPLIT 0x00000002 + #define QTD_SPLIT_ERROR 0x00000001 + #define QTD_PING_STATE 0x00000001 + #define QTD_DO_OUT 0x00000000 + #define QTD_DO_PING 0x00000001 +//------------------------------------------------------------------------- + +#define QH_I_BIT 0x00000080 // BIT 7 +#define QH_ENDPOINT_SPEED 0x00003000 // BIT 13:12 + #define QH_FULL_SPEED 0x00000000 + #define QH_LOW_SPEED 0x00001000 + #define QH_HIGH_SPEED 0x00002000 +#define QH_DATA_TOGGLE_CONTROL 0x00004000 // BIT 14 + #define QH_IGNORE_QTD_DT 0x00000000 + #define QH_USE_QTD_DT 0x00004000 +#define QH_HEAD_OF_LIST 0x00008000 // BIT 15 +#define QH_CONTROL_ENDPOINT 0x08000000 // BIT 27 +#define QH_DATA_TOGGLE 0x80000000 // BIT 31 + +#define QH_MULT_SETTING 0xC0000000 // BIT 31:30 + #define QH_ONE_XFER 0x40000000 + #define QH_TWO_XFER 0x80000000 + #define QH_THREE_XFER 0xC0000000 + +//------------------------------------------------------------------------- +// Descriptor structure used to store qTD and QH addresses +//------------------------------------------------------------------------- +typedef struct { + EHCI_QH *PeriodicQh; + EHCI_QH *fpQHRepeat; + EHCI_QTD *fpqTDRepeat; +} EHCI_DESC_PTRS; + +#endif // __EHCI_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/elib.c b/Core/EM/usb/rt/elib.c new file mode 100644 index 0000000..1f21b78 --- /dev/null +++ b/Core/EM/usb/rt/elib.c @@ -0,0 +1,659 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/elib.c 22 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 22 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/elib.c $ +// +// 22 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 +// +// 21 3/18/13 4:47a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 20 9/28/12 2:39a 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 +// +// 19 8/29/12 8:16a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 18 4/07/11 3:48a Ryanchou +// [TAG] EIP57802 +// [Category] Improvement +// [Description] The variable dCount should not be increase, undo the +// EIP55960 change in elib.c. +// [Files] elib.c +// +// 17 4/06/11 3:53a Ryanchou +// [TAG] EIP55960 +// [Category] Improvement +// [Description] The Host Controller must halt within 16 micro-frames +// after software clears the Run bit. +// [Files] ehci.c, elib.c +// +// 16 3/31/11 9:45a Tonylo +// [TAG] EIP56841 +// [Category] Improvement +// [Description] Remove IO port 0x61 dependency. +// [Files] elib.c +// +// 15 10/02/09 10:49a Olegi +// Code cleanup. +// +// 14 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 13 5/22/07 12:28p Olegi +// Added USB_BEEP_ENABLE token functionality. +// +// 12 4/26/07 6:10p Olegi +// DwordReadMem and DwordWriteMem work with volatile memory. +// +// 7 10/12/06 9:03p Andriyn +// Debug DELAY function: slow down portion of code +// +// 6 7/24/06 6:05p Olegi +// FixedDelay optimization (by Stacy Howell) +// +// 5 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 12/19/05 10:14a Olegi +// Beep routine modified. +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Elib.c +// +// Description: AMI USB MEM/IO/PCI access routines +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" + +extern USB_GLOBAL_DATA *gUsbData; +//extern EFI_SMM_SYSTEM_TABLE *gSmst; + +UINT8 ByteReadIO(UINT16); +UINT16 WritePCIConfig(UINT16, UINT8); + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FixedDelay +// +// Description: This routine delays for specified number of micro seconds +// +// Input: wCount Amount of delay (count in 1 microsec) +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +FixedDelay( + UINTN Usec + ) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + UINTN Counter, i; + UINT32 Data32, PrevData; + + Counter = Usec * 3; + Counter += Usec / 2; + Counter += (Usec * 2) / 25; + + // + // Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick + // periods, thus attempting to ensure Microseconds of stall time. + // + if (Counter != 0) { + + PrevData = IoRead32(PM_BASE_ADDRESS + 8); + for (i=0; i < Counter; ) { + Data32 = IoRead32(PM_BASE_ADDRESS + 8); + if (Data32 < PrevData) { // Reset if there is a overlap + PrevData=Data32; + continue; + } + i += (Data32 - PrevData); + PrevData = Data32; + } + } +#else + pBS->Stall(Usec); +#endif + return; +} + +EFI_STATUS +UsbHcStrucValidation( + HC_STRUC* HcStruc +) +{ + UINTN Index; + + if (HcStruc == NULL) { + return EFI_ACCESS_DENIED; + } + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + if (HcStruc == gUsbData->HcTable[Index]) { + break; + } + } + + if (Index == gUsbData->HcTableCount) { + return EFI_ACCESS_DENIED; + } + + if (!(HcStruc->dHCFlag & HC_STATE_USED)) { + return EFI_ACCESS_DENIED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +UsbDevInfoValidation( + DEV_INFO* DevInfo +) +{ + UINTN Index; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + if (DevInfo == NULL) { + return EFI_ACCESS_DENIED; + } + + for (Index = 0; Index < MAX_DEVICES; Index++) { + if (DevInfo == &gUsbData->aDevInfoTable[Index]) { + break; + } + } + + if (Index == MAX_DEVICES) { + return EFI_ACCESS_DENIED; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (DevInfo->fpPollEDPtr) { + if ((DevInfo->fpPollEDPtr < gUsbData->fpMemBlockStart) || + ((DevInfo->fpPollEDPtr + sizeof(MEM_BLK)) > MemBlockEnd)) { + return EFI_ACCESS_DENIED; + } + } + + if (DevInfo->fpPollTDPtr) { + if ((DevInfo->fpPollTDPtr < gUsbData->fpMemBlockStart) || + ((DevInfo->fpPollTDPtr + sizeof(MEM_BLK)) > MemBlockEnd)) { + return EFI_ACCESS_DENIED; + } + } + + if (DevInfo->fpPollDataBuffer) { + if ((DevInfo->fpPollDataBuffer < gUsbData->fpMemBlockStart) || + ((DevInfo->fpPollDataBuffer + DevInfo->PollingLength) > MemBlockEnd)) { + return EFI_ACCESS_DENIED; + } + } +#endif + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordReadMem +// +// Description: This routine reads a DWORD from the specified Memory Address +// +// Input: dBaseAddr - Memory address to read +// bOffset - Offset of dBaseAddr +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +DwordReadMem(UINT32 dBaseAddr, UINT16 wOffset) +{ + return *(volatile UINT32*)(UINTN)(dBaseAddr+wOffset); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordWriteMem +// +// Description: This routine writes a DWORD to a specified Memory Address +// +// Input: dBaseAddr - Memory address to write +// bOffset - Offset of dBaseAddr +// dValue - Data to write +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +DwordWriteMem(UINT32 dBaseAddr, UINT16 wOffset, UINT32 dValue) +{ + *(volatile UINT32*)(UINTN)(dBaseAddr+wOffset) = dValue; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordResetMem +// +// Description: This routine resets the specified bits at specified memory address +// +// Input: dBaseAddr - Memory address to read +// bOffset - Offset of dBaseAddr +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +DwordResetMem(UINT32 dBaseAddr, UINT16 wOffset, UINT32 dValue) +{ + UINT32 data = DwordReadMem(dBaseAddr, wOffset); + data &= ~dValue; + DwordWriteMem(dBaseAddr, wOffset, data); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordSetMem +// +// Description: This routine sets the specified bits at specified memory address +// +// Input: dBaseAddr - Memory address to read +// bOffset - Offset of dBaseAddr +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +DwordSetMem(UINT32 dBaseAddr, UINT16 wOffset, UINT32 dValue) +{ + UINT32 data = DwordReadMem(dBaseAddr, wOffset); + data |= dValue; + DwordWriteMem(dBaseAddr, wOffset, data); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ByteReadIO +// +// Description: This routine reads a Byte from the specified IO address +// +// Input: wIOAddr I/O address to read +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +ByteReadIO(UINT16 wIOAddr) +{ +// UINT8 value; +// gSmst->SmmIo.Io.Read(&gSmst->SmmIo, SMM_IO_UINT8, (UINT64)wIOAddr, 1, &value); +// return value; + return IoRead8(wIOAddr); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ByteWriteIO +// +// Description: This routine writes a byte to the specified IO address +// +// Input: wIOAddr I/O address to write +// bValue Byte value to write +// +// Output: None +// +// Modified: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ByteWriteIO (UINT16 wIOAddr, UINT8 bValue) +{ +// gSmst->SmmIo.Io.Write(&gSmst->SmmIo, SMM_IO_UINT8, (UINT64)wIOAddr, 1, &bValue); + IoWrite8(wIOAddr, bValue); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: WordReadIO +// +// Description: This routine reads a Word from the specified IO address +// +// Input: wIOAddr I/O address to read +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +WordReadIO(UINT16 wIOAddr) +{ +// UINT16 value; +// gSmst->SmmIo.Io.Read(&gSmst->SmmIo, SMM_IO_UINT16, (UINT64)wIOAddr, 1, &value); +// return value; + return IoRead16(wIOAddr); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: WordWriteIO +// +// Description: This routine writes a word to the specified IO address +// +// Input: wIOAddr I/O address to write +// wValue Word value to write +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +WordWriteIO (UINT16 wIOAddr, UINT16 wValue) +{ +// gSmst->SmmIo.Io.Write(&gSmst->SmmIo, SMM_IO_UINT16, (UINT64)wIOAddr, 1, &wValue); + IoWrite16(wIOAddr, wValue); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordReadIO +// +// Description: This routine reads a dword from the specified IO address +// +// Input: wIOAddr I/O address to read +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +DwordReadIO(UINT16 wIOAddr) +{ +// UINT32 value; +// gSmst->SmmIo.Io.Read(&gSmst->SmmIo, SMM_IO_UINT32, (UINT64)wIOAddr, 1, &value); +// return value; + return IoRead32(wIOAddr); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordWriteIO +// +// Description: This routine writes a double word to the specified IO address +// +// Input: wIOAddr I/O address to write +// dValue Double word value to write +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +DwordWriteIO(UINT16 wIOAddr, UINT32 dValue) +{ +// gSmst->SmmIo.Io.Write(&gSmst->SmmIo, SMM_IO_UINT32, (UINT64)wIOAddr, 1, &dValue); + IoWrite32(wIOAddr, dValue); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ReadPCIConfig +// +// Description: This routine reads from the PCI configuration space register +// the value can be typecasted to 8bits - 32bits +// +// Input: BusDevFunc - Bus, device & function number of the PCI device +// Register - Register offset to read +// +// Output: Value read +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +ReadPCIConfig(UINT16 BusDevFunc, UINT8 Register) +{ + UINT32 data; + DwordWriteIO(0xCF8, (UINT32)(0x80000000 | (BusDevFunc<<8) | (Register & 0xFC))); + data = DwordReadIO(0xCFC); + return (data >> ((Register & 3) << 3)); // Adjust uneven register + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ByteWritePCIConfig +// +// Description: This routine writes a byte value to the PCI configuration +// register space +// +// Input: BusDevFunc - Bus, device & function number of the PCI device +// Register - Register offset to read +// Value - Value to write +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ByteWritePCIConfig(UINT16 BusDevFunc, UINT8 Register, UINT8 Value) +{ + UINT16 wIOAddr; + wIOAddr = WritePCIConfig(BusDevFunc, Register); + ByteWriteIO (wIOAddr, Value); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: WordWritePCIConfig +// +// Description: This routine writes a byte value to the PCI configuration +// register space +// +// Input: BusDevFunc - Bus, device & function number of the PCI device +// Register - Register offset to read +// Value - Value to write +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +WordWritePCIConfig(UINT16 BusDevFunc, UINT8 Register, UINT16 Value) +{ + UINT16 wIOAddr; + wIOAddr = WritePCIConfig(BusDevFunc, Register); + WordWriteIO (wIOAddr, Value); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: DwordWritePCIConfig +// +// Description: This routine writes a Dword value to the PCI configuration +// register space +// +// Input: BusDevFunc - Bus, device & function number of the PCI device +// Register - Register offset to read +// Value - Value to write +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +DwordWritePCIConfig(UINT16 BusDevFunc, UINT8 Register, UINT32 Value) +{ + UINT16 wIOAddr; + wIOAddr = WritePCIConfig(BusDevFunc, Register); + DwordWriteIO (wIOAddr, Value); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: WritePCIConfig +// +// Description: This function opens PCI configuration for a given register +// +// Input: wBDF - Bus, device and function number +// bReg - Register number to read +// +// Output: IO register to write the value +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +WritePCIConfig(UINT16 wBDF, UINT8 bReg) +{ + DwordWriteIO(0xCF8, (UINT32)(0x80000000 | (wBDF<<8) | (bReg & 0xFC))); + return (UINT16)(0xCFC+(bReg & 3)); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SpeakerBeep +// +// Description: This routine produces a sound on the internal PC speaker +// +// Input: bFreq - Sound frequency +// wDuration - Sound duration in 15 microsecond units +// fpHCStruc - Pointer to HCStruc +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +SpeakerBeep (UINT8 bFreq, UINT16 wDuration, HC_STRUC* fpHCStruc) +{ +#if USB_BEEP_ENABLE + UINT8 bValue; + if(gUsbData->dUSBStateFlag & USB_FLAG_ENABLE_BEEP_MESSAGE) { + ByteWriteIO((UINT8)0x43, (UINT8)0xB6); + ByteWriteIO((UINT8)0x42, (UINT8)bFreq); + ByteWriteIO((UINT8)0x42, (UINT8)bFreq); + bValue = ByteReadIO((UINT8)0x61); + ByteWriteIO((UINT8)0x61, (UINT8)(bValue | 03)); + FixedDelay((UINTN)wDuration * 15); + ByteWriteIO((UINT8)0x61, (UINT8)(bValue)); + } +#endif +} + +#if defined(DEBUG_SWITCH) && (DEBUG_SWITCH == 1) +VOID DEBUG_DELAY() +{ + int i; + PrintDebugMsg(3,"\nDELAY: "); + for(i=0;i<10;i++){ + PrintDebugMsg(3,"%d..",i); + FixedDelay(300 * 1000); // 200 msec delay + } + PrintDebugMsg(3,"\n"); +} +#endif + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/guids.c b/Core/EM/usb/rt/guids.c new file mode 100644 index 0000000..fa0255d --- /dev/null +++ b/Core/EM/usb/rt/guids.c @@ -0,0 +1,147 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/guids.c 21 8/08/11 5:28a Ryanchou $ +// +// $Revision: 21 $ +// +// $Date: 8/08/11 5:28a $ +// +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/guids.c $ +// +// 21 8/08/11 5:28a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 20 10/02/09 10:49a Olegi +// Code cleanup. +// +// 19 2/04/09 12:54p Olegi +// Added NonSmmEmul6064TrapProtocol GUID definition. +// +// 18 9/24/08 10:19a Rameshraju +// Removed Usblegacyplatform support. +// +// 17 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 16 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 15 3/20/07 12:22p Olegi +// +// 14 11/15/06 3:42p Olegi +// +// 13 10/26/06 3:58p Olegi +// +// 12 5/03/06 9:59a Olegi +// +// 11 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 10 3/13/06 3:24p Felixp +// +// 9 3/01/06 3:51p Olegi +// +// 8 11/10/05 11:11a Olegi +// +// 7 10/20/05 2:44p Olegi +// +// 6 8/27/05 11:44a Andriyn +// +// 5 8/23/05 5:53p Olegi +// +// 4 8/05/05 3:38p Andriyn +// Complience with EFI EDK +// +// 3 5/20/05 12:09p Andriyn +// +// 2 5/20/05 11:05a Andriyn +// reconcile Aptio changes with Alaska +// +// 1 3/29/05 10:40a Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: guids.c +// +// Description: AMI USB guids library +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + + +#include "amiusb.h" +#include <Protocol\UsbHC.h> +#include <Protocol\UsbPolicy.h> +#include <setup.h> + +// +// GUID variables +// +//EFI_GUID mAMIUsbCoreGuid = {0x4eaaaa1, 0x29a1, 0x11d7, 0x88, 0x38, 0x0, 0x50, 0x4, 0x73, 0xd4, 0xeb}; +//EFI_GUID gEfiLoadedImageGuid = +//EFI_GUID gEfiSmmBaseProtocolGuid = EFI_SMM_BASE_PROTOCOL_GUID; +//EFI_GUID gEfiSmmSwDispatchProtocolGuid = EFI_SMM_SW_DISPATCH_PROTOCOL_GUID; +//EFI_GUID gEfiSmmUsbDispatchProtocolGuid = EFI_SMM_USB_DISPATCH_PROTOCOL_GUID; +//EFI_GUID gEfiLoadedImageProtocolGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; +//EFI_GUID gEfiDevicePathProtocolGuid = EFI_DEVICE_PATH_PROTOCOL_GUID; +//EFI_GUID gEfiUSBProtocolGuid = EFI_USB_PROTOCOL_GUID; +//EFI_GUID gEfiSimplePointerProtocolGuid = EFI_SIMPLE_POINTER_PROTOCOL_GUID; +//EFI_GUID gEfiSimpleTextInProtocolGuid = EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID; +//EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; +EFI_GUID gEfiHotPlugDeviceGuid = { 0x220ac432, 0x1d43, 0x49e5, 0xa7, 0x4f, 0x4c, 0x9d, 0xa6, 0x7a, 0xd2, 0x3b }; +//EFI_GUID gEfiPciIoProtocolGuid = EFI_PCI_IO_PROTOCOL_GUID; +//EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID; +//EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; +//EFI_GUID gEfiSmmControlProtocolGuid = EFI_SMM_CONTROL_PROTOCOL_GUID; +//EFI_GUID gEfiUsb2HcProtocolGuid = EFI_USB2_HC_PROTOCOL_GUID; +//EFI_GUID gEfiUsbHcProtocolGuid = EFI_USB_HC_PROTOCOL_GUID; +//EFI_GUID gEfiFirmwareVolumeProtocolGuid = EFI_FIRMWARE_VOLUME_PROTOCOL_GUID; +EFI_GUID gEfiUsbPolicyProtocolGuid = EFI_USB_POLICY_PROTOCOL_GUID; +EFI_GUID gEmul6064MsInputProtocolGuid = EFI_EMUL6064MSINPUT_PROTOCOL_GUID; +EFI_GUID gEmul6064KbdInputProtocolGuid = EFI_EMUL6064KBDINPUT_PROTOCOL_GUID; +EFI_GUID gEmul6064TrapProtocolGuid = EFI_EMUL6064TRAP_PROTOCOL_GUID; +EFI_GUID gNonSmmEmul6064TrapProtocolGuid = EFI_NONSMMEMUL6064TRAP_PROTOCOL_GUID; +EFI_GUID gUsbTimingPolicyProtocolGuid = USB_TIMING_POLICY_PROTOCOL_GUID; + +EFI_GUID gEfiSetupGuid = SETUP_GUID; + + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/ohci.c b/Core/EM/usb/rt/ohci.c new file mode 100644 index 0000000..2389a93 --- /dev/null +++ b/Core/EM/usb/rt/ohci.c @@ -0,0 +1,3379 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/ohci.c 98 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 98 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ohci.c $ +// +// 98 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 +// +// 97 7/28/16 4:56a Wilsonlee +// [TAG] EIP264662 +// [Category] Improvement +// [Description] Don't install usb hw smi after reconnecting usb +// controllers. +// [Files] uhcd.c, usb.c, ohci.c, amiusb.c, amiusbhc.c +// +// 96 7/22/16 3:50a 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 +// +// 95 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 +// +// 94 3/14/16 10:21p Wilsonlee +// [TAG] EIP257506 +// [Category] Improvement +// [Description] Add USB_KEYREPEAT_INTERVAL token to change the key +// repeat interval. +// [Files] usb.sdl, xhci.h, usbkbd.h, uhci.c, ohci.c, ehci.c +// +// 93 3/02/16 9:42p 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 +// +// 92 9/01/15 10:46p Wilsonlee +// [TAG] EIP235977 +// [Category] Improvement +// [Description] Break the loop which we check list processing TD if +// NextTd is the same as Td. +// [Files] ohci.c +// +// 91 3/08/15 10:50p Wilsonlee +// [TAG] EIP207774 +// [Category] Improvement +// [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and +// clear it if we don't start any HC. +// [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h +// +// 90 1/22/15 10:19p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 89 5/01/14 3:56a Ryanchou +// [TAG] EIP162589 +// [Category] Improvement +// [Description] Do not register external controller as key repeat +// controller. +// [Files] ehci.c, ohci.c, uhci.c +// +// 88 4/30/14 6:13a 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 +// +// 87 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 86 2/26/14 1:56a 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 +// +// 85 7/26/13 2:36a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 84 7/22/13 10:31p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 83 6/28/13 2:29a Roberthsu +// [TAG] EIP124581 +// [Category] Improvement +// [Description] Controller driver always return the length passed in +// parameter, devices may return zero length data, it should be corrected. +// [Files] ohci.c +// +// 82 6/02/13 11:42p Wilsonlee +// [TAG] EIP123235 +// [Category] Improvement +// [Description] Stop the usb host controller at ExitBootService if it +// is an extend card or it doesn't support HW SMI. +// [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, +// uhcd.c +// +// 81 4/18/13 1:02p Ryanchou +// Add Teradici USB controller support. +// +// 80 4/10/13 11:23p Ryanchou +// [TAG] EIP111483 +// [Category] Improvement +// [Description] Increase the delay when OHCI port reset complete. +// [Files] ohci.c +// +// 79 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 +// +// 78 3/18/13 4:48a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 77 2/24/13 9:00p Wilsonlee +// [TAG] EIP113541 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] System hangs at checkpoint 0xA2 when Win8 resume from S4. +// [RootCause] The "HCHalted" bit and "Port Change Detect" bit are set +// when the system S4 resume to Win8 OS. +// [Solution] We need to clear the interrupt status even if the +// "HCHalted" bit is set. +// [Files] ehci.c, ohci.c, uhci.c +// +// 76 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 75 12/24/12 5:06a Ryanchou +// [TAG] EIP103031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hans when loading QNX 6.5.0 +// [RootCause] The EHCI port detect change SMI is generated after +// ownership change to OS. +// [Solution] Clear the SMI enable bits and status bits even the +// controller is OS owned. +// [Files] ehci.c, ohci.c +// +// 74 12/06/12 12:39a Wilsonlee +// [TAG] EIP103186 +// [Category] Improvement +// [Description] Handle the error case "MEMIO was disabled" in USB +// driver. +// [Files] uhci.c, ohci.c, ehci.c, xhci.c +// +// 73 11/13/12 7:12a Wilsonlee +// [TAG] EIP82553 +// [Category] New Feature +// [Description] Support usb S5 wake up function for XHCI. +// [Files] usb.c, ehci.c, ohci.c, xhci.c, xhci.h +// +// 72 11/10/12 6:40a 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 +// +// 71 10/25/12 4:16a Wilsonlee +// [TAG] EIP82354 +// [Category] New Feature +// [Description] Support usb S5 wake up function for OHCI. +// [Files] usb.c, ehci.c, ohci.c +// +// 70 9/28/12 2:37a 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 +// +// 69 8/29/12 8:17a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 68 8/28/12 5:19a Ryanchou +// [TAG] EIP98857 +// [Category] Improvement +// [Description] WriteBackDoneHead status bit shall be cleared even +// HccaDoneHead is zero. +// [Files] ohci.c +// +// 67 7/25/12 4:44a Wilsonlee +// [TAG] EIP95959 +// [Category] Improvement +// [Description] Don't set INTERRUPT_ROUTING if the ohci is external usb +// pci controller card. +// [Files] ohci.c +// +// 66 5/04/12 6:38a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 65 5/04/12 5:25a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 64 5/03/12 6:01a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 63 11/08/11 1:57a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 62 9/26/11 11:40p Roberthsu +// [TAG] EIP67230 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ntrig touch panel can not use on CedarTrail +// [RootCause] Because ntrig report data over than 512 byte.Control +// transfer check if over 512 than set length is 512. +// [Solution] Remove check transfer length. +// [Files] ohci.c,uhci.c,usbhid.c +// +// 61 8/24/11 2:14a Ryanchou +// [TAG] EIP66448 +// [Category] New Feature +// [Description] Clear connect status change and port enable status +// change. +// [Files] ohci.c +// +// 60 8/08/11 6:58a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 59 8/08/11 5:15a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 58 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 57 7/12/11 8:10a 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 +// +// 56 7/12/11 6:17a Ryanchou +// [TAG] EIP59707 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The wireless USB keyboard does not work after boot into +// windows loader. +// [RootCause] The amount of data returned by the device exceeded the +// size of the maximum data packet allowed, that causes babble error, and +// BIOS does not re-init the polling TD. +// [Solution] Re-init polling TD even the last transaction get error. +// [Files] ohci.c +// +// 55 6/21/11 9:56a Ryanchou +// [TAG] EIP59663 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Plug USB WLAN device may causes OHCI malfunction. +// [RootCause] The devices have to connect to OHCI first, or it can't be +// configured. +// [Solution] Port routing route to EHCI after OHCI initialization. +// [Files] ehci.c, ohci.c +// +// 54 5/03/11 10:10a Ryanchou +// [TAG] EIP54283 +// [Category] Improvement +// [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery +// endpoint halt. +// [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c +// +// 53 4/06/11 1:33a Ryanchou +// [TAG] EIP54782 +// [Category] Improvement +// [Description] Change polling data size of HID devices to max packet +// size of interrupt endpoint. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c +// +// 52 3/30/11 9:04a Ryanchou +// +// 51 3/29/11 10:50p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 50 3/29/11 10:11a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 49 3/16/11 8:51a Ryanchou +// [TAG] EIP55025 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Finger Print function fail +// [RootCause] Wrong tranferred data size on short packet condition. +// [Files] ohci.c +// +// 48 11/11/10 11:34p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 47 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 46 6/07/10 8:55a Ryanchou +// EIP38547: Fixed system halt when installing FreeBSD. +// +// 45 3/10/10 6:35p Olegi +// +// 44 3/06/10 1:11p Olegi +// +// 43 2/26/10 4:23p Olegi +// +// 42 2/23/10 1:21p Olegi +// Work around Klockwork issues. EIP34370 +// +// 41 2/08/10 10:00a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 40 1/04/10 9:20a Olegi +// EIP32956: Polling rate for the keyboards has been changed from 8 ms to +// 32 ms. +// +// 39 12/23/09 11:59a Olegi +// +// 38 12/08/09 3:33p Olegi +// EIP32387: Bugfix in OHCI_FreeAllStruc; memory was not released properly +// when USB_FORCE_64BIT_ALIGNMENT is set. +// +// 37 11/24/09 12:43p Olegi +// EIP#26693: fixed OHCI_DISABLE_32MS_POLLING implementation. +// +// 36 10/30/09 5:47p Olegi +// +// 35 10/13/09 9:11a Olegi +// EIP28707: OHCI ownership change modifications. +// +// 34 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 33 9/15/09 10:21a Olegi +// Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. +// +// 32 2/17/09 4:01p Olegi +// +// 31 2/17/09 8:59a Olegi +// Additional modifications in BulkTransfer routine to maximize the +// bandwidth. +// +// 30 1/30/09 10:08a Olegi +// MAX_BULK_DATA_SIZE limitation moved to individual HC drivers. +// +// 29 10/06/08 3:33p Olegi +// EHCI change ownership testing in DOS fix (EIP#14855). +// +// 28 9/24/08 3:58p Olegi +// Bugfix in the memory allocation in OHCI_ActivatePolling. +// +// 27 6/16/08 10:07a Olegi +// Bugfix in OHCI_Start. +// +// 26 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 25 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 24 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 23 3/20/07 12:22p Olegi +// +// 22 1/16/07 3:24p Olegi +// Change in OHCI_ControlTransfer: return 0 if transfer stalled. +// +// 21 1/02/07 12:17p Olegi +// +// 20 1/02/07 11:13a Olegi +// +// 19 12/28/06 4:32p Olegi +// OHCI_ProcessRootHubStatusChange is modified to properly clear the +// connect change status bit +// +// 18 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 17 12/20/06 2:30p Olegi +// +// 16 12/13/06 5:40p Olegi +// X64 build update +// +// 14 11/09/06 10:16a Olegi +// +// 13 10/18/06 9:43a Andriyn +// Fix: race condition on hot-plug in / plug-off +// +// 12 10/12/06 9:37p Andriyn +// Fix: unexpected plug-off hangs with endless TIMEOUTs +// +// 11 6/09/06 10:29a Olegi +// USB_FLAG_ENABLE_BEEP_MESSAGE flag is reset while handling change of the +// controller ownership. +// +// 10 5/16/06 11:22a Olegi +// +// 9 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 8 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 7 3/06/06 6:26p Olegi +// +// 6 1/11/06 11:53a Olegi +// +// 5 12/01/05 5:48p Olegi +// +// 4 11/29/05 12:33p Andriyn +// +// 3 6/20/05 8:55a Olegi +// .NET compiler with highest warning level and warning-as-error +// modification. +// +// 2 6/03/05 6:09p Olegi +// HW SMI registration change. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Ohci.c +// +// Description: AMI USB OHCI driver source file +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +#pragma warning (disable :4213) +#pragma warning (disable :4706) + +UINT8 OHCI_FillHCDEntries(HCD_HEADER*); +UINT8 OHCI_Start (HC_STRUC*); +UINT8 OHCI_Stop (HC_STRUC*); +UINT8 OHCI_DisableInterrupts (HC_STRUC*); +UINT8 OHCI_EnableInterrupts (HC_STRUC*); +UINT8 OHCI_ProcessInterrupt(HC_STRUC*); +UINT8 OHCI_GetRootHubStatus (HC_STRUC*,UINT8, BOOLEAN); +UINT8 OHCI_DisableRootHub (HC_STRUC*,UINT8); +UINT8 OHCI_EnableRootHub (HC_STRUC*,UINT8); +UINT16 OHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); +UINT32 OHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); +UINT16 OHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); +UINT8 OHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 OHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 OHCI_DisableKeyRepeat (HC_STRUC*); +UINT8 OHCI_EnableKeyRepeat (HC_STRUC*); +UINT8 OHCI_ResetRootHub (HC_STRUC*,UINT8); +UINT8 OHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) + +UINT8 OHCI_EnumeratePorts(HC_STRUC*); +UINT8 OHCI_StartEDSchedule(HC_STRUC*); +UINT8 OhciAddPeriodicEd (HC_STRUC*, OHCI_ED*); +UINT8 OhciRemovePeriodicEd (HC_STRUC*, OHCI_ED*); +UINT8 OHCI_RepeatTDCallBack(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 OHCI_ResetHC(HC_STRUC*); +UINT8 OHCI_StopUnsupportedHC(HC_STRUC*); +UINT32 OHCI_ProcessRootHubStatusChange(HC_STRUC*); +UINT8 OHCIWaitForTransferComplete(HC_STRUC*, OHCI_ED*, OHCI_TD*,DEV_INFO*); +UINT8 OHCI_ControlTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID OHCI_ProcessTD(HC_STRUC*, OHCI_TD*); +UINT8 OHCI_GeneralTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 OHCI_PollingTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID StopControllerType(UINT8); +UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +VOID OHCI_FreeAllStruc(HC_STRUC* fpHCStruc); //(EIP28707+) +BOOLEAN OhciIsHalted(HC_STRUC*); +UINT8 OhciTranslateInterval(UINT8); + +UINT8 UsbGetDataToggle(DEV_INFO*,UINT8); +VOID UsbUpdateDataToggle(DEV_INFO*, UINT8, UINT8); + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +extern void USB_InitFrameList (HC_STRUC*, UINT32); +extern UINT32 ReadPCIConfig(UINT16, UINT8); +extern void WordWritePCIConfig(UINT16, UINT8, UINT16); +extern void DwordWritePCIConfig(UINT16, UINT8, UINT32); +extern UINT32 DwordReadMem(UINT32, UINT16); +extern void DwordWriteMem(UINT32, UINT16, UINT32); +extern void DwordSetMem(UINT32, UINT16, UINT32); +extern void DwordResetMem(UINT32, UINT16, UINT32); +extern void FixedDelay(UINTN); +extern void* USB_MemAlloc (UINT16); +extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); +extern DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +extern UINT8 USB_MemFree(void _FAR_*, UINT16); +extern UINT8 USB_DisconnectDevice(HC_STRUC*, UINT8, UINT8); //(EIP28707+) +#if USB_DEV_KBD +extern void USBKBDPeriodicInterruptHandler(HC_STRUC*); +extern void USBKeyRepeat(HC_STRUC*, UINT8); +#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_FillHCDEntries +// +// DESCRIPTION: This function fills the host controller driver +// routine pointers +// +// PARAMETERS: fpHCDHeader Ptr to the host controller header structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_FillHCDEntries(HCD_HEADER *fpHCDHeader) +{ + // + // Fill the routines here + // + fpHCDHeader->pfnHCDStart = OHCI_Start; + fpHCDHeader->pfnHCDStop = OHCI_Stop; + fpHCDHeader->pfnHCDEnumeratePorts = OHCI_EnumeratePorts; + fpHCDHeader->pfnHCDDisableInterrupts = OHCI_DisableInterrupts; + fpHCDHeader->pfnHCDEnableInterrupts = OHCI_EnableInterrupts; + fpHCDHeader->pfnHCDProcessInterrupt = OHCI_ProcessInterrupt; + fpHCDHeader->pfnHCDGetRootHubStatus = OHCI_GetRootHubStatus; + fpHCDHeader->pfnHCDDisableRootHub = OHCI_DisableRootHub; + fpHCDHeader->pfnHCDEnableRootHub = OHCI_EnableRootHub; + fpHCDHeader->pfnHCDControlTransfer = OHCI_ControlTransfer; + fpHCDHeader->pfnHCDBulkTransfer = OHCI_BulkTransfer; + fpHCDHeader->pfnHCDInterruptTransfer = OHCI_InterruptTransfer; + fpHCDHeader->pfnHCDDeactivatePolling = OHCI_DeactivatePolling; + fpHCDHeader->pfnHCDActivatePolling = OHCI_ActivatePolling; + fpHCDHeader->pfnHCDDisableKeyRepeat = OHCI_DisableKeyRepeat; + fpHCDHeader->pfnHCDEnableKeyRepeat = OHCI_EnableKeyRepeat; + fpHCDHeader->pfnHCDEnableEndpoints = USB_EnableEndpointsDummy; + fpHCDHeader->pfnHCDInitDeviceData = USB_InitDeviceDataDummy; + fpHCDHeader->pfnHCDDeinitDeviceData = USB_DeinitDeviceDataDummy; + fpHCDHeader->pfnHCDResetRootHub = OHCI_ResetRootHub; + fpHCDHeader->pfnHCDClearEndpointState = 0; //(EIP54283+) + fpHCDHeader->pfnHCDGlobalSuspend = OHCI_GlobalSuspend; //(EIP54018+) + + USB_InstallCallBackFunction(OHCI_ControlTDCallback); + USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + USB_InstallCallBackFunction(OHCI_PollingTDCallback); + USB_InstallCallBackFunction(OHCI_RepeatTDCallBack); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_Start +// +// DESCRIPTION: This API function is called to start a OHCI host controller. +// The input to the routine is the pointer to the HC structure +// that defines this host controller +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_Start (HC_STRUC* fpHCStruc) +{ + UINT32 OhciControlReg = 0; + UINT32 BaseAddr; + UINT32 HcFmInterval; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + fpHCStruc->wAsyncListSize = OHCI_FRAME_LIST_SIZE; + fpHCStruc->dMaxBulkDataSize = MAX_OHCI_BULK_DATA_SIZE; + + // + // Get memory base address of the HC and store it in the HCStruc + // + BaseAddr = ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_MEM_BASE_ADDRESS); + BaseAddr &= 0xFFFFFFF0; // Mask lower bits + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)BaseAddr, fpHCStruc->BaseAddressSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Usb Mmio address is invalid, it is in SMRAM\n"); + return USB_ERROR; + } + EfiStatus = AmiValidateMmioBuffer((VOID*)fpHCStruc->fpFrameList, 0x100); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + fpHCStruc->BaseAddress = BaseAddr; + + // + // Get the number of ports supported by the host controller (Offset 48h) + // + fpHCStruc->bNumPorts = (UINT8)DwordReadMem(BaseAddr, OHCI_RH_DESCRIPTOR_A); + + USB_InitFrameList (fpHCStruc, 0); + + // + // Enable the ED schedules + // + if (OHCI_StartEDSchedule(fpHCStruc) == USB_ERROR) return USB_ERROR; + + // + // First stop the host controller if it is at all active + // + if (OHCI_DisableInterrupts(fpHCStruc) == USB_ERROR) return USB_ERROR; + + // Save the contents of the HcFmInterval register + HcFmInterval = DwordReadMem(BaseAddr, OHCI_FRAME_INTERVAL); + HcFmInterval &= 0x3FFF; + if (HcFmInterval != 0x2EDF) { + USB_DEBUG(3, "OHCI: HcFmInterval %x\n", HcFmInterval); + } + HcFmInterval |= (((6 * (HcFmInterval - 210)) / 7) & 0x7FFF) << 16; + + // Issue a controller reset + if (OHCI_ResetHC(fpHCStruc) != USB_SUCCESS) { + return USB_ERROR; + } + + // Restore the value of the HcFmInterval register + DwordWriteMem(BaseAddr, OHCI_FRAME_INTERVAL, HcFmInterval); + + // + // Program the frame list base address register + // + DwordWriteMem(BaseAddr, OHCI_HCCA_REG, (UINT32)(UINTN)fpHCStruc->fpFrameList); + + // + // Set the periodic start time = 2A27h (10% off from HcFmInterval-2EDFh) + // + DwordWriteMem(BaseAddr, OHCI_PERIODIC_START, (((HcFmInterval & 0x3FFF) * 9) / 10) & 0x3FFF); + + // + // Start the host controller for periodic list and control list. + // + OhciControlReg = (PERIODIC_LIST_ENABLE | CONTROL_LIST_ENABLE | + BULK_LIST_ENABLE | USBOPERATIONAL); +#if USB_RUNTIME_DRIVER_IN_SMM + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + OhciControlReg |= INTERRUPT_ROUTING; + } +#endif + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, + OhciControlReg); + + // + // Enable interrupts from the host controller, enable SOF, WDH, RHSC interrupts + // + DwordWriteMem(BaseAddr, OHCI_INTERRUPT_ENABLE, + MASTER_INTERRUPT_ENABLE | WRITEBACK_DONEHEAD_ENABLE | + RH_STATUS_CHANGE_ENABLE | OWNERSHIP_CHANGE_ENABLE); + + // + // Set the HC state to running + // + fpHCStruc->dHCFlag |= HC_STATE_RUNNING; + + // Set USB_FLAG_DRIVER_STARTED flag when HC is running. + if (!(gUsbData->dUSBStateFlag & USB_FLAG_DRIVER_STARTED)) { + gUsbData->dUSBStateFlag |= USB_FLAG_DRIVER_STARTED; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + // + // Register the USB HW SMI handler + // + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + UsbInstallHwSmiHandler(fpHCStruc); + } else { + USBSB_InstallUsbIntTimerHandler(); + } +#endif + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_Stop +// +// DESCRIPTION: This API function is called to stop the OHCI controller. +// The input to the routine is the pointer to the HC structure +// that defines this host controller. +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_Stop (HC_STRUC* fpHCStruc) +{ + UINT8 Port; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + for (Port = 1; Port <= fpHCStruc->bNumPorts; Port++) { + USB_DisconnectDevice(fpHCStruc, (UINT8)(fpHCStruc->bHCNumber | BIT7), Port); + } + + // + // Reset Host Controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, USBRESET); + FixedDelay(gUsbData->UsbTimingPolicy.OhciHcResetDelay * 1000); // Wait 10ms for assertion of reset + + // + // Disable interrupts + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, 0xffffffff); + + // + // Disable OHCI KBC Emulation + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCE_CONTROL, 0); + + USB_InitFrameList (fpHCStruc, 0); + OHCI_FreeAllStruc(fpHCStruc); //(EIP28707+) + + USBKeyRepeat(fpHCStruc, 3); + + fpHCStruc->dHCFlag &= ~HC_STATE_RUNNING; + + CheckBiosOwnedHc(); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_RepeatTDCallBack +// +// DESCRIPTION: This function is called when TdRepeat/TD32ms completes +// a transaction. This TD runs a dummy interrupt transaction +// to a non-existant device address for the purpose of +// generating a periodic timeout interrupt which in turn +// is used to generate keyboard repeat or update LED status. +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_RepeatTDCallBack( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + OHCI_DESC_PTRS *DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpTDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpTDRepeat + sizeof(OHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + +#if USB_DEV_KBD + USBKBDPeriodicInterruptHandler(HcStruc); +#endif + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (!(DescPtrs->fpEDRepeat->dControl & ED_SKIP_TDQ)) { + // + // Rebind the TD to its parent ED + // + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + + // + // Clear the link pointer. It may point to some other TD + // + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + + // + // Reactivate the TD + // + DescPtrs->fpTDRepeat->dControlStatus = DescPtrs->fpTDRepeat->dCSReloadValue; + DescPtrs->fpTDRepeat->bActiveFlag = TRUE; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableInterrupts +// +// DESCRIPTION: This API function is called to disable the interrupts +// generated by the OHCI host controller. The input to the +// routine is the pointer to the HC structure that defines this +// host controller. This routine will stop the HC to avoid +// further interrupts. +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Disable interrupt generation (global) bit (Set bit31) + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, MASTER_INTERRUPT_ENABLE); + // + // Disable periodic, isochronous, control and bulk list processing, reset bits 2 to 5 + // + DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, BIT2 + BIT3 + BIT4 + BIT5); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableInterrupts +// +// DESCRIPTION: This function enables the HC interrupts +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Enable periodic, control and bulk list processing + // Set bit 2, 4 & 5 + // + DwordSetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, BIT2 + BIT4 + BIT5); + // + // Enable interrupt generation (global) bit + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, MASTER_INTERRUPT_ENABLE); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ProcessInterrupt +// +// DESCRIPTION: This function is called when the USB interrupt bit is +// set. This function will parse through the TDs and QHs to +// find out completed TDs and call their respective call +// back functions +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_ERROR - Interrupt not processed +// USB_SUCCESS - Interrupt processed +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ProcessInterrupt(HC_STRUC* fpHCStruc) +{ + OHCI_TD *fpTD, *fpTD1; + UINT8 bIntProcessFlag = USB_ERROR; // Set as interrupt not processed + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + // Make sure MEMIO & Bus mastering are enabled + if (((UINT8)ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_REG_COMMAND) & 0x6) != 0x6) { + return bIntProcessFlag; + } + + if ((ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_MEM_BASE_ADDRESS) & ~(0x7F)) != + (UINT32)fpHCStruc->BaseAddress) { + return bIntProcessFlag; + } + // + // Check the interrupt status register for an ownership change. If this bit + // is set, it means that the O/S USB device driver is attempting to takeover + // control of the host controller. In this case the host controller is + // shut down and the interrupt routing bit in the control register is cleared + // (this disables SMI generation and enebles standard IRQ generation from + // the USB host controller. + // + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & OWNERSHIP_CHANGE) { + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, OWNERSHIP_CHANGE); + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCCA_REG) == (UINT32)(UINTN)fpHCStruc->fpFrameList) { + // + // OS tries to take the control over HC + // + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + + OHCI_StopUnsupportedHC(fpHCStruc); + + OHCI_Stop(fpHCStruc); + return USB_SUCCESS; // Set interrupt as processed + } else { // Ownership comes back to the driver - reinit + gUsbData->bHandOverInProgress = FALSE; + gUsbData->dUSBStateFlag |= (USB_FLAG_ENABLE_BEEP_MESSAGE); + OHCI_Start(fpHCStruc); + return USB_SUCCESS; // Set interrupt as processed + } + } // ownership change + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) return USB_ERROR; + + if (OhciIsHalted(fpHCStruc)) { + // Clear All bits of the interrupt status + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, + DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS)); + return bIntProcessFlag; + } + // + // Check whether the controller is still under BIOS control + // Read the base address of the Periodic Frame List to the OHCI HCCA + // register and compare with stored value + // + if ((DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCCA_REG) & 0xFFFFFF00) != + (UINT32)(UINTN)fpHCStruc->fpFrameList) { + return bIntProcessFlag; + } + // + // Check the interrupt status register for a root hub status change. If + // this bit is set, then a device has been attached or removed from one of + // the ports on the root hub. + // + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & RH_STATUS_CHANGE) { + // + // Stop the periodic list processing to avoid more interrupts from HC + // + DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); +// USB_DEBUG(3, "before OHCI_ProcessRootHubStatusChange\n"); + // Handle root hub change + bIntProcessFlag = (UINT8)OHCI_ProcessRootHubStatusChange(fpHCStruc); +// USB_DEBUG(3, "after OHCI_ProcessRootHubStatusChange\n"); + // + // Re-enable the periodic list processing + // + DwordSetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + } + + // + // Check the interrupt status register for a one or more TDs completing. + // + if (!(DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & WRITEBACK_DONEHEAD)) { + return USB_SUCCESS; + } + bIntProcessFlag = USB_SUCCESS; // Set interrupt as processed + + // + // The memory dword at HCCADONEHEAD has been updated to contain the head + // pointer of the linked list of TDs that have completed. Walk through + // this list processing TDs as we go. + // + for (;;) { + fpTD = (OHCI_TD*)(UINTN)(((OHCI_HCCA_PTRS*)fpHCStruc->fpFrameList)->dHccaDoneHead); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpTD, sizeof(OHCI_TD)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + ((OHCI_HCCA_PTRS*)fpHCStruc->fpFrameList)->dHccaDoneHead = 0; + + // + // Clear the WRITEBACK_DONEHEAD bit of the interrupt status register + // in the host controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, WRITEBACK_DONEHEAD); + + if (!fpTD) break; // no TDs in the list + + do { + fpTD = (OHCI_TD*)((UINTN)fpTD & 0xfffffff0); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpTD, sizeof(OHCI_TD)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + fpTD1 = (OHCI_TD*)fpTD->fpLinkPointer; + OHCI_ProcessTD(fpHCStruc, fpTD); + // Host controllers might change NextTD pointer to Td, then it causes + // infinite loop in this routing. Break this loop if NextTd is the same as Td. + if (fpTD == fpTD1) { + break; + } + fpTD = fpTD1; + } while (fpTD); + } // Check if any TDs completed while processing + + return bIntProcessFlag; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_GetRootHubStatus +// +// DESCRIPTION: This function returns the port connect status for the +// root hub port +// +// PARAMETERS: pHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC whose status is requested +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GetRootHubStatus( + HC_STRUC* fpHCStruc, + UINT8 bPortNum, + BOOLEAN ClearChangeBits +) +{ + UINT8 bRHStatus = USB_PORT_STAT_DEV_OWNER; + UINT32 dPortStatus; + UINT16 wPortReg = ((UINT16)bPortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + dPortStatus = DwordReadMem((UINT32)fpHCStruc->BaseAddress, wPortReg); + USB_DEBUG(3, "Ohci port[%d] status: %08x\n", bPortNum, dPortStatus); + + if (dPortStatus & CURRENT_CONNECT_STATUS) { + bRHStatus |= USB_PORT_STAT_DEV_CONNECTED; + if (dPortStatus & PORT_ENABLE_STATUS) { + bRHStatus |= USB_PORT_STAT_DEV_ENABLED; + } + } + + bRHStatus |= USB_PORT_STAT_DEV_FULLSPEED; // Assume full speed and set the flag + if (dPortStatus & LOW_SPEED_DEVICE_ATTACHED) { + bRHStatus &= ~USB_PORT_STAT_DEV_FULLSPEED; // Reset full speed + bRHStatus |= USB_PORT_STAT_DEV_LOWSPEED; // Set low speed flag + } + + if (dPortStatus & CONNECT_STATUS_CHANGE) { + if (ClearChangeBits == TRUE) + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, wPortReg, CONNECT_STATUS_CHANGE); //(EIP66448+) + bRHStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; // Set connect status change flag + } + //(EIP66448+)> + if (dPortStatus & PORT_ENABLE_STATUS_CHANGE) { + if (ClearChangeBits == TRUE) { + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, wPortReg, PORT_ENABLE_STATUS_CHANGE); + } + } + //<(EIP66448+) + return bRHStatus; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableRootHub +// +// DESCRIPTION: This function disables the specified root hub port. +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC to be disabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableRootHub (HC_STRUC* fpHCStruc, UINT8 bPortNum) +{ + UINT32 dPortReg = ((UINT32)bPortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, (UINT16)dPortReg, CLEAR_PORT_ENABLE); + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableRootHub +// +// DESCRIPTION: This function enables the specified root hub port. +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC to be enabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableRootHub (HC_STRUC* fpHCStruc,UINT8 bPortNum) +{ + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ResetRootHub +// +// DESCRIPTION: This function resets the specified root hub port. +// +// PARAMETERS: HcStruc Pointer to HCStruc of the host controller +// PortNum Port in the HC to be disabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ResetRootHub (HC_STRUC* HcStruc, UINT8 PortNum) +{ + UINT32 BaseAddr = (UINT32)HcStruc->BaseAddress; + UINT16 PortReg = ((UINT16)PortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + UINT32 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + DwordWriteMem(BaseAddr, PortReg, SET_PORT_RESET); // Reset the port + + // The reset signaling must be driven for a minimum of 10ms + FixedDelay(10 * 1000); + + // + // Wait for reset to complete + // + for (i = 0; i < 500; i++) { + if (DwordReadMem(BaseAddr, PortReg) & PORT_RESET_STATUS_CHANGE) { + break; + } + FixedDelay(100); // 100 us delay + } + + if (!(DwordReadMem(BaseAddr, PortReg) & PORT_RESET_STATUS_CHANGE)) { + USB_DEBUG(3, "OHCI: port reset timeout, status: %08x\n", + DwordReadMem(BaseAddr, PortReg)); + return USB_ERROR; + } + + // + // Clear the reset status change status + // + DwordWriteMem(BaseAddr, PortReg, PORT_RESET_STATUS_CHANGE); + + // Some devices need a delay here + FixedDelay(3 * 1000); // 3 ms delay + + return USB_SUCCESS; +} + + //(EIP54018+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: OHCI_GlobalSuspend +// +// Description: +// This function suspend the OHCI HC. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GlobalSuspend( + HC_STRUC* HcStruc +) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, + RESUME_DETECTED_ENABLE); + FixedDelay(40 * 1000); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, + USBSUSPEND | REMOTE_WAKEUP_ENABLE); + FixedDelay(20 * 1000); + + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + HcStruc->dHCFlag |= HC_STATE_SUSPEND; + + return USB_SUCCESS; +} + //<(EIP54018+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ControlTransfer +// +// DESCRIPTION: This function executes a device request command transaction +// on the USB. One setup packet is generated containing the +// device request parameters supplied by the caller. The setup +// packet may be followed by data in or data out packets +// containing data sent from the host to the device +// or vice-versa. This function will not return until the +// request either completes successfully or completes in error +// (due to time out, etc.) +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// 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: Get Configuration, Set Address etc) +// 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 +// +// +// RETURN: Number of bytes transferred +// +// +// NOTES: Do not use USB_SUCCESS or USB_ERROR as returned values +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +OHCI_ControlTransfer ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT16 wRequest, + UINT16 wIndex, + UINT16 wValue, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT16 *fpData; + OHCI_DESC_PTRS *fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + OHCI_ED *fpED; + OHCI_TD *fpTD; + UINT32 dData; + UINT16 wData; + UINT8 CompletionCode; + UINT32 TransferLength; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + if (wLength != 0) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ohci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + //FixedDelay(5 * 1000); // 5 ms delay is necessary for OHCI host controllers + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + if (((UINT8*)fpDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpEDControl < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpEDControl + sizeof(OHCI_ED)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlSetup < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlSetup + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlData < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlData + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlStatus < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlStatus + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + gUsbData->dLastCommandStatusExtended = 0; + + // + // Build the device request in the data area of the control setup qTD + // + fpData = (UINT16*)fpDescPtrs->fpTDControlSetup->aSetupData; + *fpData++ = wRequest; + *fpData++ = wValue; + *fpData++ = wIndex; + *fpData++ = wLength; + *(UINTN*)fpData = (UINTN)fpBuffer; + // + // Prepare some registers that will be used in building the TDs below. + // wLength contains the data length. + // fpBuffer contains the absolute address of the data buffer. + // wRequest contains the request type (bit 7 = 0/1 for Out/In). + // fpDevInfo will contain a pointer to the DeviceInfo structure for the given device. + // + // Ready the EDControl for the control transfer. + // + fpED = fpDescPtrs->fpEDControl; + // + // The ED control field will be set so + // Function address & Endpoint number = ESI, + // Direction = From TD, + // Speed = DeviceInfo.bEndpointSpeed, + // Skip = 1, Format = 0, + // Max packet size = DeviceInfo.wEndp0MaxPacket + // The HeadPointer field will be set to TDControlSetup + // The TailPointer field will be set to OHCI_TERMINATE + // The LinkPointer field will be set to OHCI_TERMINATE + // + dData = (UINT32)fpDevInfo->wEndp0MaxPacket; + if (dData > 0x40) dData = 0x40; // Force the max packet size to 64 bytes + dData <<= 16; // dData[26:16] = device's packet size + wData = (UINT16)fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + wData = (wData & 1) << 13; // wData[13] = full/low speed flag + wData |= fpDevInfo->bDeviceAddress | ED_SKIP_TDQ; + fpED->dControl = dData | wData; + fpED->fpTailPointer = 0; + fpED->fpEDLinkPointer = 0; + + fpTD = fpDescPtrs->fpTDControlSetup; + // + // The ControlStatus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_SETUP_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_SETUP_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to the TD's SetupData buffer + // which was before initialized to contain a DeviceRequest struc. + // The BufferEnd field will point to the last byte of the TD's SetupData + // buffer. + // The LinkPointer field will point to the TDControlData if data will + // be sent/received or to the TDControlStatus if no data is expected. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EDControl. + // + fpTD->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_SETUP_PACKET | GTD_SETUP_TOGGLE | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + + fpTD->fpCurrentBufferPointer = (UINT32)(UINTN)fpTD->aSetupData; + fpTD->fpBufferEnd = (UINT32)(UINTN)fpTD->aSetupData + 7; // size of aSetupData - 1 + + wData = wLength ; //(EIP67230) + + if (wLength) { // some data to transfer + fpTD = fpDescPtrs->fpTDControlData; // Fill in various fields in the TDControlData. + // + // The ControlStatus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_DATA1_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to the caller's buffer + // which is now in EBP. + // The BufferEnd field will point to the last byte of the caller's buffer. + // The LinkPointer field will point to the TDControlStatus. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EDControl. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. return USB_SUCCESS; + // The DeviceAddress field does not need to be set since the Control TDs do} + // not need rebinding to the EDControl. + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + dData = (wRequest & BIT7)? (dData | GTD_IN_PACKET | GTD_IntD) : (dData | GTD_OUT_PACKET); + fpTD->dControlStatus = dData; + fpTD->fpCurrentBufferPointer = (UINT32)(UINTN)fpBuffer; + fpTD->fpBufferEnd = (UINT32)((UINTN)fpBuffer + wData - 1); + } + fpTD = fpDescPtrs->fpTDControlStatus; // Fill in various fields in the TDControlStatus. + // + // The ControlStaus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_DATA1_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to NULL + // The BufferEnd field will point to NULL. + // The LinkPointer field will point to OHCI_TERMINATE. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTdCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EdControl. + // + // Note: For OUT control transfer status should be IN and + // for IN cotrol transfer, status should be OUT. + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + dData = (wRequest & BIT7)? (dData | GTD_OUT_PACKET) : (dData | GTD_IN_PACKET | GTD_IntD); + fpTD->dControlStatus = dData; + fpTD->fpCurrentBufferPointer = 0; + fpTD->fpBufferEnd = 0; + fpTD->fpLinkPointer = 0; + // + // Link all the pointers together + // + fpTD = fpDescPtrs->fpTDControlSetup; + fpED->fpHeadPointer = (UINT32)(UINTN)fpTD; + if (wLength) { // chain in data TD + fpTD->fpLinkPointer = (UINT32)(UINTN)fpDescPtrs->fpTDControlData; + fpTD = fpDescPtrs->fpTDControlData; + } + fpTD->fpLinkPointer = (UINT32)(UINTN)fpDescPtrs->fpTDControlStatus; + + fpDescPtrs->fpTDControlStatus->fpLinkPointer = 0; + + fpTD = fpDescPtrs->fpTDControlSetup; + do { + fpTD->dCSReloadValue = 0; + fpTD->bCallBackIndex = USB_InstallCallBackFunction(OHCI_ControlTDCallback); + fpTD->bActiveFlag = TRUE; + fpTD = (OHCI_TD*)fpTD->fpLinkPointer; + } while (fpTD); + // + // Now control queue is complete, so set ED_SKIP_TDQ=0 + // + fpED->dControl &= ~ED_SKIP_TDQ; + // + // Set the HcControlHeadED register to point to the EDControl. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_HEAD_ED, (UINT32)(UINTN)fpED); + // + // Now put the control setup, data and status into the HC's schedule by + // setting the ControllListFilled field of HcCommandStatus reg. + // This will cause the HC to execute the transaction in the next active frame. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_COMMAND_STATUS, CONTROL_LIST_FILLED); + // + // Now wait for the control status TD to complete. When it has completed, + // the OHCI_ControlTDCallback will set its active flag to FALSE. + // + OHCIWaitForTransferComplete(fpHCStruc, fpED, fpDescPtrs->fpTDControlStatus,fpDevInfo); + // + // Stop the HC from processing the EDControl by setting its Skip bit. + // + fpED->dControl |= ED_SKIP_TDQ; + + // + // Finally check for any error bits set in both the TDControlStatus. + // If the TD did not complete successfully, return STC. + // + CompletionCode = (UINT8)(fpDescPtrs->fpTDControlStatus->dControlStatus >> 28); // dData[3:0] = Completion status + gUsbData->bLastCommandStatus &= ~USB_CONTROL_STALLED; + + fpTD = fpDescPtrs->fpTDControlData; + TransferLength = wLength ; + if(fpTD->fpCurrentBufferPointer != 0){ + TransferLength = fpTD->fpCurrentBufferPointer - (UINT32)(UINTN)fpBuffer; + } + + + wData = 0; + switch (CompletionCode) { + case GTD_NO_ERROR: + wData = TransferLength; + break; + case GTD_STALL: + gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + return wData; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_BulkTransfer +// +// 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 +// +// PARAMETERS: pHCStruc Pointer to HCStruc of the host controller +// pDevInfo DeviceInfo structure (if available else 0) +// bXferDir Transfer direction +// Bit 7: Data direction +// 0 Host sending data to device +// 1 Device sending data to host +// Bit 6-0 : Reserved +// fpBuffer Buffer containing data to be sent to the +// device or buffer to be used to receive data +// value in Segment:Offset format +// dwLength dwLength request parameter, number of bytes +// of data to be transferred in or out +// of the host controller +// +// RETURN: Amount of data transferred +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +OHCI_BulkTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 bXferDir, + UINT8 *fpBuffer, + UINT32 dwLength) +{ + UINT32 dData; + UINT8 bData; + OHCI_DESC_PTRS *fpDescPtrs; + UINT16 wMaxPkt; + UINT8 bEndp; + UINT8 bDatToggle; + UINT32 dBytesToTransfer, dBytesRemaining; + UINT32 dBytesTransferred; + UINT32 Buffer; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, dwLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ohci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + + gUsbData->dLastCommandStatusExtended = 0; + + fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + + if (((UINT8*)fpDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return 0; + } + + if (((UINT8*)fpDescPtrs->fpEDBulk < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpEDBulk + sizeof(OHCI_ED)) > MemBlockEnd)) { + return 0; + } + + if (((UINT8*)fpDescPtrs->fpTDBulkData < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDBulkData + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + + wMaxPkt = (bXferDir & 0x80)? fpDevInfo->wBulkInMaxPkt : fpDevInfo->wBulkOutMaxPkt; + bEndp = (bXferDir & 0x80)? fpDevInfo->bBulkInEndpoint : fpDevInfo->bBulkOutEndpoint; + bDatToggle = UsbGetDataToggle(fpDevInfo, bEndp | bXferDir); + + if( wMaxPkt == 0){ + return 0; + } + + dBytesRemaining = dwLength; + dBytesTransferred = 0; + dBytesToTransfer = 0; + + for (;dBytesRemaining != 0; dBytesRemaining -= dBytesToTransfer) { + dBytesToTransfer = + (dBytesRemaining < FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME)? + dBytesRemaining : FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME; + + Buffer = (UINT32)(UINTN)fpBuffer + dBytesTransferred; + + // + // Set the SKIP bit in the EdBulk to avoid accidental scheduling + // + fpDescPtrs->fpEDBulk->dControl = ED_SKIP_TDQ; + // + // Set the ED's head pointer field to bulk data TD and tail pointer field to + // OHCI_TERMINATE. Also set ED's link pointer to OHCI_TERMINATE. + // + fpDescPtrs->fpEDBulk->fpHeadPointer = (UINT32)(UINTN)fpDescPtrs->fpTDBulkData; + fpDescPtrs->fpEDBulk->fpTailPointer = OHCI_TERMINATE; + fpDescPtrs->fpEDBulk->fpEDLinkPointer = OHCI_TERMINATE; + // + // Form the data needed for ED's control field with the available information + // + dData = (bXferDir & 0x80)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= fpDevInfo->bDeviceAddress; + dData |= (UINT16)bEndp << 7; + dData |= (UINT32)wMaxPkt << 16; + // + // Update the ED's control field with the data formed + // ASSUME ALL MASS DEVICES ARE FULL SPEED DEVICES. + // + fpDescPtrs->fpEDBulk->dControl = dData; + // + // Fill the general bulk data TD with relevant information. Set the + // TD's control field with buffer rounding set to 1, direction PID to + // don't care, delay interrupt to INTD, data toggle to the latest data + // toggle value, error count to no errors and condition code to not accessed. + // + // Set the data toggle to DATA0 (SETUP_TOGGLE) + fpDescPtrs->fpTDBulkData->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | + GTD_IntD | GTD_SETUP_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + fpDescPtrs->fpTDBulkData->dControlStatus |= (UINT32)bDatToggle << 24; + // + // GTD current buffer pointer field will point to the caller's buffer which + // now in the variable fpBuffer + // + fpDescPtrs->fpTDBulkData->fpCurrentBufferPointer = Buffer; + fpDescPtrs->fpTDBulkData->fpBufferEnd = Buffer + dBytesToTransfer - 1; + fpDescPtrs->fpTDBulkData->fpLinkPointer = OHCI_TERMINATE; + // + // GTD's CSReloadValue field will contain 0 because this is a "one shot" packet + // + fpDescPtrs->fpTDBulkData->dCSReloadValue = 0; + fpDescPtrs->fpTDBulkData->bCallBackIndex = USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + fpDescPtrs->fpTDBulkData->bActiveFlag = TRUE; + + fpDescPtrs->fpEDBulk->dControl &= ~ED_SKIP_TDQ; + // + // Set the HCBulkHeadED register to point to the bulk ED + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_BULK_HEAD_ED, (UINT32)(UINTN)fpDescPtrs->fpEDBulk); + // + // Clear bulk stall/time out condition flag + // + gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED + USB_BULK_TIMEDOUT); + // + // Enable the bulk list processing + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_COMMAND_STATUS, BULK_LIST_FILLED); + + OHCIWaitForTransferComplete(fpHCStruc, fpDescPtrs->fpEDBulk, fpDescPtrs->fpTDBulkData,fpDevInfo); + // + // Stop the HC from processing the EDBulk by setting its Skip bit. + // + fpDescPtrs->fpEDBulk->dControl |= ED_SKIP_TDQ; + // + // Update the data toggle value into the mass info structure + // + UsbUpdateDataToggle(fpDevInfo, bEndp | bXferDir, + (UINT8)(((fpDescPtrs->fpTDBulkData->dControlStatus & GTD_DATA_TOGGLE) >> 24) & 1)); + // + // Check for the error conditions - if possible recover from them + // + bData = (UINT8)(fpDescPtrs->fpTDBulkData->dControlStatus >> 28); + switch (bData) { + case GTD_STALL: + gUsbData->bLastCommandStatus |= USB_BULK_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + if (bData != GTD_NO_ERROR) { + break; + } + + // + // Get the size of data transferred + // + dData = fpDescPtrs->fpTDBulkData->fpCurrentBufferPointer; + if (dData != 0) + { + // + // Device sent less data than requested, calculate the + // transferred size and exit + // + //dBytesTransferred += (UINT32)(UINTN)fpDescPtrs->fpTDBulkData->fpBufferEnd - dData; //(EIP55025-) + dBytesTransferred += dData - Buffer; //Short Packet (OHCI Spec 4.3.1.3.5 Transfer Completion, Pg.23) //<(EIP55025)+ + break; + } + + // + // CurrentBufferPointer equals 0. This indicates the successfull TD completion, + // all data is transferred. Adjust the total amount and continue. + // + dBytesTransferred += dBytesToTransfer; + } + + return dBytesTransferred; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_InterruptTransfer +// +// DESCRIPTION: This function executes an interrupt transaction on the USB. +// The data transfer direction is always DATA_IN. This +// function wil not return until the request either completes +// successfully or completes in error (due to time out, etc.) +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// fpDevInfo DeviceInfo structure (if available else 0) +// EndpointAddress The destination USB device endpoint to which the device request +// is being sent. +// MaxPktSize Indicates the maximum packet size the target endpoint is capable +// of sending or receiving. +// 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 +// +// RETURN: Number of bytes transferred +// +// +// NOTES: DO NOT TOUCH THE LINK POINTER OF THE TDInterruptData. It is +// statically allocated and linked with other items in the +// 1ms schedule +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +OHCI_InterruptTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT8 bEndp, bDatToggle; + UINT32 dData; + OHCI_ED *IntEd; + OHCI_TD *IntTd; + UINT8 CompletionCode; + UINT32 BytesTransferred; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ohci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + + if(!VALID_DEVINFO( fpDevInfo)) { + return 0; + } + + gUsbData->dLastCommandStatusExtended = 0; + + IntEd = USB_MemAlloc(GET_MEM_BLK_COUNT(sizeof(OHCI_ED) + sizeof(OHCI_TD))); + + if (IntEd == NULL) { + return 0; + } + + IntTd = (OHCI_TD*)((UINTN)IntEd + sizeof(OHCI_ED)); + + // + // Set the SKIP bit to avoid accidental scheduling + // + IntEd->dControl = ED_SKIP_TDQ; + // + // Set the ED's head pointer field to interrupt data TD and tail pointer + // field to OHCI_TERMINATE. Also set ED's link pointer to OHCI_TERMINATE. + // + IntEd->fpHeadPointer = (UINT32)(UINTN)IntTd; + IntEd->fpTailPointer = OHCI_TERMINATE; + IntEd->fpEDLinkPointer = OHCI_TERMINATE; + IntEd->Interval = OhciTranslateInterval(fpDevInfo->bPollInterval); + + // + // Get maximum packet size from device info structure + // + bEndp = EndpointAddress & 0xF; + bDatToggle = UsbGetDataToggle(fpDevInfo, EndpointAddress); + + // + // Form the data needed for ED's control field with the available information + // + dData = (EndpointAddress & BIT7)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= fpDevInfo->bDeviceAddress | ((UINT16)bEndp << 7); + dData |= ((UINT32)MaxPktSize << 16); + dData |= (UINT32)(fpDevInfo->bEndpointSpeed & 1) << 13; + // + // Update the ED's control field with the data formed + // ASSUME ALL MASS DEVICES ARE FULL SPEED DEVICES. + // + IntEd->dControl = dData; + // + // Fill the general interrupt data TD with relevant information. Set the + // TD's control field with buffer rounding set to 1, direction PID to + // don't care, delay interrupt to INTD, data toggle to the latest data + // toggle value, error count to no errors and condition code to not accessed. + // + // Set the data toggle to DATA0 (SETUP_TOGGLE) + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | GTD_SETUP_TOGGLE | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + IntTd->dControlStatus = dData; + // + // Set the data toggle depending on the bDatToggle value + // + IntTd->dControlStatus |= ((UINT32)bDatToggle << 24); + // + // GTD current buffer pointer field will point to the caller's buffer + // + IntTd->fpCurrentBufferPointer = (UINT32)(UINTN)fpBuffer; + // + // GTD's buffer end field will point to the last byte of the caller's buffer + // + IntTd->fpBufferEnd = (UINT32)(UINTN)(fpBuffer + wLength - 1); + // + // GTD's link pointer field will be set to OHCI_TERMINATE + // + IntTd->fpLinkPointer = OHCI_TERMINATE; + // + // GTD's CSReloadValue field will contain 0 because this is a "one shot" packet + // + IntTd->dCSReloadValue = 0; + // + // GTD's pCallback will point to the OHCI_GeneralTDCallback routine + // + IntTd->bCallBackIndex = USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + // + // GTD's ActiveFlag field will be set to TRUE. + // + OhciAddPeriodicEd(fpHCStruc, IntEd); + + IntTd->bActiveFlag = TRUE; + IntEd->dControl &= ~ED_SKIP_TDQ; + + // + // Now wait for the interrupt data TD to complete. + // + OHCIWaitForTransferComplete(fpHCStruc, IntEd, IntTd, fpDevInfo); + // + // Stop the HC from processing the EDInterrupt by setting its Skip bit. + // + OhciRemovePeriodicEd(fpHCStruc, IntEd); + // + // Get appropriate data sync shift value + // + bDatToggle = (UINT8)((IntTd->dControlStatus & GTD_DATA_TOGGLE) >> 24) & 1; + UsbUpdateDataToggle(fpDevInfo, EndpointAddress, bDatToggle); + + // + // Check for the error conditions - if possible recover from them + // + CompletionCode = (UINT8)(IntTd->dControlStatus >> 28); + switch (CompletionCode) { + case GTD_STALL: + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + BytesTransferred = IntTd->fpCurrentBufferPointer == 0 ? wLength : + IntTd->fpCurrentBufferPointer - (UINT32)fpBuffer; + + USB_MemFree(IntEd, GET_MEM_BLK_COUNT(sizeof(OHCI_ED) + sizeof(OHCI_TD))); + + return (UINT16)BytesTransferred; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ActivatePolling +// +// DESCRIPTION: This function activates the polling TD for the requested +// device. The device may be a USB keyboard or USB hub +// +// PARAMETERS: fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +// NOTES: For the keyboard device this routine allocates TDRepeat +// also, if it is not already allocated. This routine allocate +// a polling TD and schedule it to 8ms schedule for keyboards +// and to 1024ms schedule for hubs. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ActivatePolling ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + UINT32 dData; + UINT8 *fpPtr; + UINT8 bDatToggle; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + if (!VALID_DEVINFO(fpDevInfo)) { + return USB_ERROR; + } + + bDatToggle = UsbGetDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint); + + fpPtr = USB_MemAlloc(1); + ASSERT(fpPtr); + fpDevInfo->fpPollEDPtr = fpPtr; + fpPtr = USB_MemAlloc(1); + ASSERT(fpPtr); + fpDevInfo->fpPollTDPtr = fpPtr; + + dData = (fpDevInfo->IntInEndpoint & BIT7)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= (UINT32)fpDevInfo->bDeviceAddress | ((fpDevInfo->IntInEndpoint & 0xF) << 7); + dData |= ((UINT32)fpDevInfo->IntInMaxPkt << 16); + dData |= (UINT32)(fpDevInfo->bEndpointSpeed & 1) << 13; + dData |= ED_SKIP_TDQ; + + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->dControl = dData; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpHeadPointer = (UINT32)(UINTN)fpDevInfo->fpPollTDPtr; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpHeadPointer |= bDatToggle << 1; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpEDLinkPointer = OHCI_TERMINATE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpTailPointer = OHCI_TERMINATE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->Interval = OhciTranslateInterval(fpDevInfo->bPollInterval); + + fpDevInfo->fpPollDataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + ASSERT(fpDevInfo->fpPollDataBuffer); + + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->dCSReloadValue = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpCurrentBufferPointer = + (UINT32)(fpDevInfo->fpPollDataBuffer); //(EIP54782) + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpBufferEnd = + (UINT32)(fpDevInfo->fpPollDataBuffer + fpDevInfo->PollingLength - 1); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpLinkPointer = OHCI_TERMINATE; + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->bCallBackIndex = USB_InstallCallBackFunction(OHCI_PollingTDCallback); + + OhciAddPeriodicEd(fpHCStruc, (OHCI_ED*)fpDevInfo->fpPollEDPtr); + + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->bActiveFlag = TRUE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->dControl &= ~ED_SKIP_TDQ; + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DeactivatePolling +// +// DESCRIPTION: This function de-activates the polling TD for the requested +// device. The device may be a USB keyboard or USB hub +// +// PARAMETERS: fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DeactivatePolling ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + OHCI_ED *fpOHCIED = (OHCI_ED*)fpDevInfo->fpPollEDPtr; + OHCI_TD *fpOHCITD = (OHCI_TD*)fpDevInfo->fpPollTDPtr; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + if(!fpOHCIED) { + return USB_SUCCESS; + } + + fpOHCITD->dControlStatus = 0; + fpOHCITD->dCSReloadValue = 0; + fpOHCITD->bActiveFlag = FALSE; + + OhciRemovePeriodicEd(fpHCStruc, fpOHCIED); + + UsbUpdateDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint, + (UINT8)((fpOHCIED->fpHeadPointer & ED_TOGGLE_CARRY) >> 1)); + + USB_MemFree(fpOHCITD, GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + fpDevInfo->fpPollTDPtr = NULL; + + USB_MemFree(fpOHCIED, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + fpDevInfo->fpPollEDPtr = NULL; + + if(fpDevInfo->fpPollDataBuffer) { + USB_MemFree(fpDevInfo->fpPollDataBuffer, + GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + fpDevInfo->fpPollDataBuffer = 0; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_PollingTDCallback +// +// DESCRIPTION: This function is called when a polling TD from the TD pool +// completes an interrupt transaction to its assigned device. +// This routine should process any data in the TD's data buffer, +// handle any errors, and then copy the TD's CSReloadValue +// field into its control status field to put the TD back +// into service. +// +// +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_PollingTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength +) +{ + UINT8 i; + UINT16 BytesTransferred; + + if (((OHCI_TD*)Td)->bActiveFlag == FALSE) { + return USB_SUCCESS; + } + + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + DwordResetMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + + for (i = 1; i < MAX_DEVICES; i++) { + DevInfo = &gUsbData->aDevInfoTable[i]; + if (DevInfo->Flag & DEV_INFO_DEV_PRESENT) { + if (DevInfo->fpPollTDPtr == Td) { + break; + } + } + } + + if (i == MAX_DEVICES) { + return USB_ERROR; + } + + UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, + (UINT8)((((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer & ED_TOGGLE_CARRY) >> 1)); + + //(EIP59707)> + if ((((OHCI_TD*)Td)->dControlStatus & GTD_STATUS_FIELD) == GTD_NO_ERROR) { + // + // Get the size of data transferred + // + if (((OHCI_TD*)Td)->fpCurrentBufferPointer != 0) { + BytesTransferred = ((OHCI_TD*)Td)->fpCurrentBufferPointer - + (UINT32)(UINTN)(DevInfo->fpPollDataBuffer); + } else { + BytesTransferred = DevInfo->PollingLength; + } + if ((DevInfo->bCallBackIndex) && (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1])( + HcStruc, + DevInfo, + (UINT8*)Td, + DevInfo->fpPollDataBuffer, + BytesTransferred); + } + } + //<(EIP59707) + DwordSetMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + + // Clear the link pointer. It may point to some other TD + ((OHCI_TD*)Td)->fpLinkPointer = OHCI_TERMINATE; + ((OHCI_TD*)Td)->dControlStatus = ((OHCI_TD*)Td)->dCSReloadValue; + ((OHCI_TD*)Td)->fpCurrentBufferPointer = (UINT32)(UINTN)(DevInfo->fpPollDataBuffer); //(EIP54782) + ((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer &= ED_TOGGLE_CARRY; + ((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer |= (UINTN)((OHCI_TD*)Td); + ((OHCI_TD*)Td)->bActiveFlag = TRUE; + // Reset the TD's control and buffer pointer fields to their original values. + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableKeyRepeat +// +// DESCRIPTION: This function disables the keyboard repeat rate logic by +// enabling the repeat TD +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + + if (DescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (DescPtrs->fpEDRepeat == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpEDRepeat->dControl |= ED_SKIP_TDQ; // Inactive + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableKeyRepeat +// +// DESCRIPTION: This function enables the keyboard repeat rate logic by +// enabling the repeat TD +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + + if (DescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (DescPtrs->fpEDRepeat == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + DescPtrs->fpTDRepeat->dControlStatus = + DescPtrs->fpTDRepeat->dCSReloadValue; + DescPtrs->fpTDRepeat->bActiveFlag = TRUE; + DescPtrs->fpEDRepeat->dControl &= (~ED_SKIP_TDQ); // Active + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnumeratePorts +// +// DESCRIPTION: This API function is called to enumerate the root hub ports +// in the OHCI controller. The input to the routine is the +// pointer to the HC structure that defines this host controller +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnumeratePorts(HC_STRUC* fpHCStruc) +{ + UINT32 BaseAddr = (UINT32)fpHCStruc->BaseAddress; + UINT32 RhDescriptorA = 0; + UINT8 PowerOnDelay = 0; + UINT8 Index = 0; + UINT16 PortReg = OHCI_RH_PORT1_STATUS; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + RhDescriptorA = DwordReadMem(BaseAddr, OHCI_RH_DESCRIPTOR_A); + if (!(RhDescriptorA & NO_POWER_SWITCH)) { + if (!(RhDescriptorA & POWER_SWITCH_MODE)) { + // All ports are powered at the same time, enable global port power + DwordWriteMem(BaseAddr, OHCI_RH_STATUS, SET_GLOBAL_POWER); + } else { + // Each port is powered individually, enable individual port's power + for (Index = 0; Index < fpHCStruc->bNumPorts; PortReg+=4, Index++) { + // Set PortPowerControlMask bit + DwordSetMem(BaseAddr, OHCI_RH_DESCRIPTOR_B, ((1 << (Index + 1)) << 16)); + // Set PortPower bit + DwordWriteMem(BaseAddr, PortReg, SET_PORT_POWER); + } + } + PowerOnDelay = ((RhDescriptorA & POWERON2POWERGOOD_TIME) >> 24) << 1; + FixedDelay(PowerOnDelay * 1000); + } + + OHCI_ProcessRootHubStatusChange(fpHCStruc); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OhciAddPeriodicEd +// +// DESCRIPTION: This function adds a ED to the frame list +// +// PARAMETERS: HcStruc - Ptr to the host controller structure +// Ed - ED will be added in periodic schedule +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciAddPeriodicEd ( + HC_STRUC *HcStruc, + OHCI_ED *Ed +) +{ + UINT16 Index; + UINT32 *PrevPtr; + OHCI_ED *Current; + EFI_STATUS Status = EFI_SUCCESS; + + if (Ed == NULL || Ed->Interval == 0) { + return USB_ERROR; + } + + for (Index = 0; Index < HcStruc->wAsyncListSize; Index += Ed->Interval) { + PrevPtr = &HcStruc->fpFrameList[Index]; + Current = (OHCI_ED*)(*PrevPtr); + + while (Current != NULL) { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Current, sizeof(OHCI_ED)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Current->Interval <= Ed->Interval) { + break; + } + + PrevPtr = &Current->fpEDLinkPointer; + Current = (OHCI_ED*)Current->fpEDLinkPointer; + } + + if (Current == Ed) { + continue; + } + Ed->fpEDLinkPointer = (UINT32)(UINTN)Current; +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = (UINT32)(UINTN)Ed; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OhciRemovePeriodicEd +// +// DESCRIPTION: This function removes a ED from the frame list +// +// PARAMETERS: HcStruc - Ptr to the host controller structure +// Ed - ED will be removed from periodic schedule +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciRemovePeriodicEd ( + HC_STRUC *HcStruc, + OHCI_ED *Ed +) +{ + UINT16 Index; + UINT32 *PrevPtr; + OHCI_ED *Current; + EFI_STATUS Status = EFI_SUCCESS; + + if (Ed == NULL || Ed->Interval == 0) { + return USB_ERROR; + } + + Ed->dControl |= ED_SKIP_TDQ; + + for (Index = 0; Index < HcStruc->wAsyncListSize; Index += Ed->Interval) { + PrevPtr = &HcStruc->fpFrameList[Index]; + Current = (OHCI_ED*)(*PrevPtr); + + while (Current != NULL) { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Current, sizeof(OHCI_ED)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Current == Ed) { + break; + } + + PrevPtr = &Current->fpEDLinkPointer; + Current = (OHCI_ED*)Current->fpEDLinkPointer; + } + + if (Current == NULL) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = Ed->fpEDLinkPointer; + } + + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_STATUS, START_OF_FRAME); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, START_OF_FRAME_ENABLE); + + for (Index = 0; Index < 100; Index++) { + if (DwordReadMem((UINT32)HcStruc->BaseAddress, + OHCI_INTERRUPT_STATUS) & START_OF_FRAME) { + break; + } + FixedDelay(10); // 10 us delay + } + ASSERT(Index < 100); + ASSERT(DwordReadMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & START_OF_FRAME); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, START_OF_FRAME_DISABLE); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_StartEDSchedule +// +// DESCRIPTION: This function starts the standard TD schedules for the +// USB host controller +// +// PARAMETERS: HCStruc for the controller +// +// RETURN: USB_ERROR on error, USB_SUCCESS on success +// +// NOTES: This routine creates 1, 2, 8, 32 and 1024ms schedules +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_StartEDSchedule( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + UINT8 *Ptr; + + // + // Allocate descriptor structure and fill it in HCStruc + // + DescPtrs = (OHCI_DESC_PTRS*)USB_MemAlloc (GET_MEM_BLK_COUNT_STRUC(OHCI_DESC_PTRS)); + ASSERT(DescPtrs); + if (!DescPtrs) return USB_ERROR; + + // + // Save the value in the HC struc + // + HcStruc->stDescPtrs.fpOHCIDescPtrs = DescPtrs; + + // + // Allocate 4 EDs + 1 TDs and put them in Descriptor list + // + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + ASSERT(Ptr); + if (!Ptr) return USB_ERROR; + + DescPtrs->PeriodicEd = (OHCI_ED*)Ptr; + DescPtrs->PeriodicEd->dControl = ED_SKIP_TDQ; + DescPtrs->PeriodicEd->fpEDLinkPointer = 0; + DescPtrs->PeriodicEd->Interval = 1; + + // Initialize each entry of Interrupt Table as statically disable ED + OhciAddPeriodicEd(HcStruc, DescPtrs->PeriodicEd); + + // + // Allocate ED/TD for EDControl, TDControlSetup, TDControlData, + // TDControlStatus, EDBulk, TDBulkData, EDInterrupt and TDInterruptData + // + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT(2 * sizeof(OHCI_ED) + 4 * sizeof(OHCI_TD))); + ASSERT(Ptr); + if (!Ptr) return USB_ERROR; + + // + // Save the 8 ED/TD in their proper position. Note: fpHCStruc->stDescPtrs.fpEHCIDescPtrs + // is initialized earlier in OHCI_StartEDSchedule. + // + DescPtrs->fpEDControl = (OHCI_ED*)Ptr; + Ptr += sizeof (OHCI_ED); + + DescPtrs->fpTDControlSetup = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpTDControlData = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpTDControlStatus = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpEDBulk = (OHCI_ED*)Ptr; + Ptr += sizeof (OHCI_ED); + + DescPtrs->fpTDBulkData = (OHCI_TD*)Ptr; + + if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { + return USB_SUCCESS; + } + + // Allocate a ED/TD for EDRepeat/TDRepeat + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + ASSERT(Ptr); + DescPtrs->fpEDRepeat = (OHCI_ED*)Ptr; + + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + ASSERT(Ptr); + DescPtrs->fpTDRepeat = (OHCI_TD*)Ptr; + + DescPtrs->fpEDRepeat->dControl = (DUMMY_DEVICE_ADDR | + ED_IN_PACKET | ED_SKIP_TDQ | (DEFAULT_PACKET_LENGTH << 16)); + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + DescPtrs->fpEDRepeat->fpEDLinkPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->fpTailPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->Interval = REPEAT_INTERVAL; + + DescPtrs->fpTDRepeat->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_TWO_ERRORS | (GTD_NOT_ACCESSED << 28)); + DescPtrs->fpTDRepeat->dCSReloadValue = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_TWO_ERRORS | (GTD_NOT_ACCESSED << 28)); + + DescPtrs->fpTDRepeat->fpCurrentBufferPointer = + (UINT32)(UINTN)DescPtrs->fpTDRepeat->aSetupData; + DescPtrs->fpTDRepeat->fpBufferEnd = + (UINT32)(UINTN)DescPtrs->fpTDRepeat->aSetupData; + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + DescPtrs->fpTDRepeat->bCallBackIndex = USB_InstallCallBackFunction(OHCI_RepeatTDCallBack); + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + + OhciAddPeriodicEd(HcStruc, DescPtrs->fpEDRepeat); + + USBKeyRepeat(HcStruc, 0); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ResetHC +// +// DESCRIPTION: This function resets the OHCI controller +// +// PARAMETERS: Pointer to the HCStruc structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 OHCI_ResetHC(HC_STRUC* fpHCStruc) +{ + UINT32 BaseAddr = (UINT32)fpHCStruc->BaseAddress; + UINT8 i; + // + // Issue a software reset and HC go to UsbSuspend state + // + DwordWriteMem(BaseAddr, OHCI_COMMAND_STATUS, HC_RESET); + + // The reset operation must be completed within 10 us + for (i = 0; i < 100; i++) { + FixedDelay(1); // 1 us delay + if (!(DwordReadMem(BaseAddr, OHCI_COMMAND_STATUS) & HC_RESET)) { + return USB_SUCCESS; + } + } + + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ProcessRootHubStatusChange +// +// DESCRIPTION: This function is called when TD1024ms completes +// a transaction. This TD runs a dummy interrupt transaction +// to a non-existant device address for the purpose of +// generating a periodic timeout interrupt. This periodic +// interrupt may be used to check for new devices on the +// root hub etc. +// +// PARAMETERS: Pointer to HC Struc +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 OHCI_ProcessRootHubStatusChange(HC_STRUC* fpHCStruc) +{ + UINT8 bHCNumber, bPort;//, bPortStatus; //(EIP59663) + + // + // Check bEnumFlag before enumerating devices behind root hub + // + if (gUsbData->bEnumFlag == TRUE) return USB_ERROR; + gUsbData->bEnumFlag = TRUE; // Set enumeration flag and avoid hub port enumeration + // + // Mask the Host Controller interrupt so the ISR does not get re-entered due + // to an IOC interrupt from any TDs that complete in frames while we are + // configuring a new device that has just been plugged in. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, 0x80000000); + // + // Check all the ports on the root hub for any change in connect status. + // If the connect status has been changed on either or both of these ports, + // then call the routine UsbHubPortChange for each changed port. + // + bHCNumber = fpHCStruc->bHCNumber | BIT7; + + for (bPort = 1; bPort <= fpHCStruc->bNumPorts; bPort++) { + //(EIP59663)> + //bPortStatus = OHCI_GetRootHubStatus (fpHCStruc, bPort+1); + //DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_RH_PORT1_STATUS+bPort*4, 0xFFFF); + //if (bPortStatus & USB_PORT_STAT_DEV_CONNECT_CHANGED) { + USBCheckPortChange(fpHCStruc, bHCNumber, bPort); + //} + //DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_RH_PORT1_STATUS+bPort*4, 0xFFFF); + //<(EIP59663) + } + // + // Clear the RH_STATUS_CHANGE bit of the interrupt status register + // in the host controller: write 1 to bit to clear it + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, RH_STATUS_CHANGE); + + // + // Renable interrupts from the host controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, MASTER_INTERRUPT_ENABLE); + + gUsbData->bEnumFlag = FALSE; + return USB_SUCCESS; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCIWaitForTransferComplete +// +// DESCRIPTION: This function executes a device request command transaction +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// fpTD Pointer to the TD which has to be completed +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCIWaitForTransferComplete( + HC_STRUC *fpHCStruc, + OHCI_ED *XferED, + OHCI_TD *LastTD, + DEV_INFO* fpDevInfo +) +{ + UINT32 Count ; + UINT32 Timeout = gUsbData->wTimeOutValue << 4; // *16, makes it number of 60mcs units + + // + // Check status change loop iteration + // + for(Count = 0; !Timeout || Count < Timeout; Count++) { + OHCI_ProcessInterrupt(fpHCStruc); + if(!LastTD->bActiveFlag ) + return USB_SUCCESS; + else if(!VALID_DEVINFO(fpDevInfo)){ + USB_DEBUG (DEBUG_LEVEL_3, "OHCI Abort: devinfo: %x\n",fpDevInfo ); + return USB_ERROR; + } + FixedDelay(60); // 60 microseconds + } + + XferED->dControl |= ED_SKIP_TDQ; + OHCI_ProcessInterrupt(fpHCStruc); + + if(!LastTD->bActiveFlag) { + return USB_SUCCESS; + } + + USB_DEBUG (DEBUG_LEVEL_3, "OHCI Time-Out\n"); + + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI__StopUnsupportedHC +// +// DESCRIPTION: This routine is called, from host controllers that supports +// OS handover functionality (currently from OHCI driver only), when OS +// wants the BIOS to hand-over the host controllers to the OS. This routine +// will stop HC that does not support this functionality. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_StopUnsupportedHC( + HC_STRUC* HcStruc +) +{ + UINT8 i; + + if (!gUsbData->UsbEhciHandoff) { + return USB_SUCCESS; + } + +// +// Currently this host controller stops only the EHCI host controllers +// Find the EHCI host controller HCStruc +// + for (i = 0; i < gUsbData->HcTableCount; i++ ) { + if (gUsbData->HcTable[i] == NULL) { + continue; + } + if (!(gUsbData->HcTable[i]->dHCFlag & HC_STATE_USED)) { + continue; + } + if (!(gUsbData->HcTable[i]->dHCFlag & HC_STATE_RUNNING) || + (gUsbData->HcTable[i]->bHCType != USB_HC_EHCI) || + ((gUsbData->HcTable[i]->wBusDevFuncNum & ~0x7) != + (HcStruc->wBusDevFuncNum & ~0x7))) { + continue; + } + + gUsbData->bHandOverInProgress = TRUE; + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + gUsbData->HcTable[i]->bHCType)].pfnHCDStop)(gUsbData->HcTable[i]); + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_GeneralTDCallback +// +// DESCRIPTION: This function is called when bulk data or interrupt data TD +// is completed. This routine just deactivates the TD. +// +// PARAMETERS: Pointer to the HCStruc structure +// Pointer to the TD that completed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GeneralTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength + ) +{ + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ControlTDCallback +// +// DESCRIPTION: This function is called when the control transfer scheduled +// is completed. +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ControlTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength +) +{ + OHCI_DESC_PTRS *DescPtrs; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + // + // Check to see if the TD that just completed has any error bits set. If + // any of the control TDs (Setup, Data, or Status) complete with an error, set + // ActiveFlag of the control status TD and copy the error information from the + // TD that just completed into the control status TD. + // + if ((UINT8)(((OHCI_TD*)Td)->dControlStatus >> 28)) { + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + if (((UINT8*)DescPtrs->fpTDControlStatus < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpTDControlStatus + sizeof(OHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + if (DescPtrs->fpTDControlStatus != (OHCI_TD*)Td) { + DescPtrs->fpTDControlStatus->dControlStatus = ((OHCI_TD*)Td)->dControlStatus; + DescPtrs->fpTDControlStatus->bActiveFlag = FALSE; + } + } + // + // Make the TD that just completed inactive. It may be the control setup TD, + // one of the control data TDs, or the control status TD. + // + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ProcessTD +// +// DESCRIPTION: This function will check whether the TD is completed +// if so, it will call the call back routine associated with +// this TD. +// +// PARAMETERS: HCStruc structure, Pointer to the TD +// +// NOTES: For any TD whose ActiveFlag is TRUE and its ControlStatus +// bit 23 is clear (completed), process the TD by calling +// its call back routine, if one is present. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void OHCI_ProcessTD( + HC_STRUC *HcStruc, + OHCI_TD *Td +) +{ + if (!Td) { + return; // Check for NULL + } + if (Td->bActiveFlag != TRUE) { + return; // TD is not active + } + if ((Td->bCallBackIndex) && (Td->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[Td->bCallBackIndex-1]) { + (*gUsbData->aCallBackFunctionTable[Td->bCallBackIndex-1])( + HcStruc, + 0, + (UINT8*)Td, + 0, + 0); + } + } +} + + //(EIP28707+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_FreeAllStruc +// +// DESCRIPTION: This function is used to free the all the allocated TDs, +// QH and DescriptorPtr structure. This function only frees +// the entries in the DescriptorPtr and the descriptor pointer +// only. +// ; +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID OHCI_FreeAllStruc(HC_STRUC* fpHCStruc) +{ + OHCI_DESC_PTRS *fpDescPtrs; + + fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + +// Free the EDs & TDs + USB_MemFree(fpDescPtrs->PeriodicEd, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + if (fpDescPtrs->fpEDRepeat) { + USB_MemFree(fpDescPtrs->fpEDRepeat, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + } + if (fpDescPtrs->fpTDRepeat) { + USB_MemFree(fpDescPtrs->fpTDRepeat, GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + } + + USB_MemFree(fpDescPtrs->fpEDControl, + GET_MEM_BLK_COUNT(2 * sizeof(OHCI_ED) + 4 * sizeof(OHCI_TD))); + +// Free descriptor structure (in BX) + USB_MemFree(fpDescPtrs, GET_MEM_BLK_COUNT_STRUC(OHCI_DESC_PTRS)); +} + //<(EIP28707+) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: OhciIsHalted +// +// Description: This function check whether HC is halted. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +OhciIsHalted ( + HC_STRUC *HcStruc +) +{ + return (DwordReadMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG) & HC_FUNCTION_STATE) != USBOPERATIONAL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: OhciTranslateInterval +// +// Description: This function calculates the polling rate. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciTranslateInterval( + UINT8 Interval +) +{ + UINT8 BitCount = 0; + + // The Interval value should be from 1 to 255 + ASSERT(Interval >= 1 && Interval <= 255); + + for (BitCount = 0; Interval != 0; BitCount++) { + Interval >>= 1; + } + return (1 << (BitCount - 1)); +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/ohci.h b/Core/EM/usb/rt/ohci.h new file mode 100644 index 0000000..ca38dde --- /dev/null +++ b/Core/EM/usb/rt/ohci.h @@ -0,0 +1,609 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ohci.h 9 7/26/13 2:36a Ryanchou $ +// +// $Revision: 9 $ +// +// 01/08/05 11:10a +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ohci.h $ +// +// 9 7/26/13 2:36a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 8 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 7 5/04/12 5:25a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 6 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 5 3/20/07 12:22p Olegi +// +// 4 12/13/06 5:40p Olegi +// X64 build update +// +// 2 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Ohci.h +// +// Description: AMI USB OHCI driver header +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// Avoid including multiple instance of this file +#ifndef __OHCI_H +#define __OHCI_H + +// Global equates for OHCI +//------------------------------------------------------------------------- +#define OHCI_FRAME_LIST_SIZE 32 // Number of DWORDs in interrupt list +#define MAX_OHCI_BULK_DATA_SIZE (4 * 1024) // 4K + +// HCCA - Host Controller Commumications Area +//---------------------------------------------------------------------------- +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCIHCCA +// +// Description: OHCI host controller communications area is used by the +// host controller driver(BIOS) to communicate with the +// OHCI based host controller. This data area should be +// bus master capable. Refer OHCI data sheet for more +// information. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// INTERRUPTLIST ARRAY 32 entries of periodic transfer pointer +// HCCAFRAMENUMBER WORD Current frame number +// HCCAPAD1 WORD Reserved +// HCCADONEHEAD DWORD Location where the done head pointers will be placed +// RES_HCCA ARRAY 120 bytes of reserved data +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +//OHCIHCCA STRUC +// INTERRUPTLIST DD OHCI_FRAME_LIST_SIZE DUP (?) +// HCCAFRAMENUMBER DW ? +// HCCAPAD1 DW ? +// HCCADONEHEAD DD ? +// RES_HCCA DB 120 DUP (?) +//OHCIHCCA ENDS +#pragma pack(push, 1) + +typedef struct { + UINT32 aInterruptList[OHCI_FRAME_LIST_SIZE]; + UINT16 wHccaFrameNumber; + UINT16 wHccaPad1; + UINT32 dHccaDoneHead; + UINT8 aResHcca[120]; +} OHCI_HCCA_PTRS; + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCI_TD +// +// Description: OHCI general transfer descriptor structure. This structure is +// used for bulk, interrupt and control transfers. This structure +// holds the information needed for the transfer like buffer +// size, address etc. Refer to OHCI specification for more +// information. The last sixteen bytes in the structure (after +// BufferEnd) is AMIBIOS internal data structure. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// dControlStatus DWORD Control & status (OHCI_TD_CONTROL) +// fpCurrentBufferPointer DWORD Current buffer pointer +// fpLinkPointer DWORD Pointer to the next GTD +// fpBufferEnd DWORD Pointer to the end of the buffer +// dCSReloadValue DWORD Copy of control status during scheduling +// bCallBack NEAR Pointer to call back function +// bActiveFlag BYTE Non-zero value indicates TD is active +// bDeviceAddr BYTE USB device address +// aSetupData ARRAY 8 byte setup data buffer +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +/* +OHCI_TD STRUC + + ControlStatus DD ? ; Control and status fields + CurrentBufferPointer DD ? ; Current buffer pointer + LinkPointer DD ? ; Pointer to the next TD + BufferEnd DD ? ; End pointer of data buffer + + CSReloadValue DD ? ; Reload value for control + pCallback PTRFUNCTDCALLBACK ? ; Routine to call on completion + ActiveFlag DB ? ; If nonzero, TD is active + DeviceAddress DB ? ; Device address + SetupData DB 8 dup (?) ; Used for setup packet + +OHCI_TD ENDS*/ + +typedef struct { + UINT32 dControlStatus; // Control and status fields + UINT32 fpCurrentBufferPointer; // Current buffer pointer + UINT32 fpLinkPointer; // Pointer to the next TD + UINT32 fpBufferEnd; // End pointer of data buffer + + UINT32 dCSReloadValue; // Control status reload value + UINT8 bCallBackIndex; // Index of the routine to call on completion + UINT8 bActiveFlag; // Routine to call on completion + UINT8 bDeviceAddr; // Device Address + UINT8 bResvd; + UINT8 aSetupData[8]; // Used for setup packet +} OHCI_TD; + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCI_ED +// +// Description: OHCI Endpoint descriptor structure. This structure is needed +// for all the USB transaction. This structure had the +// information regarding the transfer. Refer to OHCI specification +// for more information +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// dControl DWORD ED control fields (refer OHCI_ED_CONTROL) +// fpTDTailPtr DWORD TD queue tail pointer +// fpTDHeadPointer DWORD TD queue head pointer +// fpEDLinkPointer DWORD Pointer to the next ED +// aReserved ARRAY 16 bytes of reserved data +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct _OHCI_ED { + UINT32 dControl; // ED control fields + UINT32 fpTailPointer; // TD queue tail pointer + UINT32 fpHeadPointer; // TD queue head pointer + UINT32 fpEDLinkPointer; // Pointer to next ED + UINT8 Interval; + UINT8 aReserved[15]; +} OHCI_ED; + +#pragma pack(pop) + +/* +typedef struct +{ + UINT32 dControlStatus; + PHY_ADDR pCurBufPtr; + PHY_ADDR pLinkPtr; + PHY_ADDR pBufEnd; + +// AMI defined fields + UINT32 dCSReload; // Control status reload value + UINT8 bCallBackIndex; + UINT8 bActiveFlag; + UINT8 bDevAddr; + UINT8 bReserved; + UINT8 aDataArea[8]; +} OHCI_GTD, _FAR_ *FPOHCI_GTD; +*/ +//typedef struct +//{ +// OHCI_GTD _FAR_ * fpSomeGTD; +// OHCI_ED _FAR_ * fpSomeED; +//} OHCI_DESC_PTRS, _FAR_ *FPOHCI_DESC_PTRS; + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCIDescriptors +// +// Description: Descriptors structure is used to hold the host controller +// instance specific general transfer descriptor and endpoint +// descriptor pointers. The following structure defines such +// the descriptors for OHCI based host controller instances. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// fpED1ms OHCI_ED ED scheduled in 1ms timeframe +// fpED2ms OHCI_ED ED scheduled in 2ms timeframe +// fpED8ms OHCI_ED ED scheduled in 8ms timeframe +// fpED32ms OHCI_ED ED scheduled in 32ms timeframe +// fpTD32ms OHCI_TD TD scheduled in 32ms timeframe +// fpEDRepeat OHCI_ED ED scheduled for keyboard repeat rate generator +// fpTDRepeat OHCI_TD TD scheduled for keybord repeat rate generator +// TDRepeat OHCI_TD TD associated with generation of repeat data +// fpEDControl OHCI_ED ED associated for control transfer +// fpTDControlSetup OHCI_TD TD associated with control setup +// fpTDControlData OHCI_TD TD associated with control data +// fpTDControlStatus OHCI_TD TD associated with control status +// fpEDInterrupt OHCI_ED ED associated for interrupt transfer +// fpTDInterruptData OHCI_TD TD associated to transfer interrupt data +// fpEDBulk OHCI_ED ED associated for bulk transfer +// fpTDBulkData OHCI_TD TD associated to transfer bulk data +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +/* +OHCIDescriptors STRUC + ED1ms DW ? + ED2ms DW ? + ED8ms DW ? +// Do not change the following order of ED32ms and TD32ms + ED32ms DW ? + TD32ms DW ? +// Do not change the following order of EDRepeat and TDRepeat + EDRepeat DW ? + TDRepeat DW ? + EDControl DW ? + TDControlSetup DW ? + TDControlData DW ? + TDControlStatus DW ? + EDInterrupt DW ? + TDInterruptData DW ? + EDBulk DW ? + TDBulkData DW ? +OHCIDescriptors ENDS +*/ + +typedef struct { + OHCI_ED *PeriodicEd; +// Do not change the following order of EDRepeat and TDRepeat + OHCI_ED *fpEDRepeat; + OHCI_TD *fpTDRepeat; + + OHCI_ED *fpEDControl; + OHCI_TD *fpTDControlSetup; + OHCI_TD *fpTDControlData; + OHCI_TD *fpTDControlStatus; + + OHCI_ED *fpEDInterrupt; + OHCI_TD *fpTDInterruptData; + + OHCI_ED *fpEDBulk; + OHCI_TD *fpTDBulkData; +} OHCI_DESC_PTRS; + +#define USB_OHCI_DESCRIPTOR_SIZE_BLK ((size of OHCIDescriptors + USB_MEM_BLK_SIZE - 1) >> USB_MEM_BLK_SIZE_SHIFT) + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCI_ED_CONTROL +// +// Description: Bit definition for OHCI_ED control field +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// FuncAddress BITS:06-00 USB device address +// EndpointNum BITS:10-07 Endpoint number +// Direction BITS:12-11 Direction of data flow +// Speed BITS:13 Endpoint speed +// Skip BITS:14 If set ED will be skipped +// Format BITS:15 Set for isochronous endpoint +// MaxPacketSize BITS:26-16 Endpoint max packet size +// Reserved BITS:31-27 Reserved bits +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + + +// Bit definitions for endpoint descriptor control field +//------------------------------------------------------------------------- +#define ED_FUNCTION_ADDRESS 0x0000007f +#define ED_ENDPOINT 0x00000780 +#define ED_DIRECTION 0x00001800 +#define ED_OUT_PACKET 0x00000800 +#define ED_IN_PACKET 0x00001000 +#define ED_LOW_SPEED 0x00002000 +#define ED_SKIP_TDQ 0x00004000 +#define ED_FORMAT 0x00008000 +#define ED_MAX_PACK_SIZE 0x07ff0000 + +//Bit definition for endpoint descriptor direction +//------------------------------------------------------------------------- +#define ED_DATA_OUT 0x01 +#define ED_DATA_IN 0x02 + +// Bit definition for endpoint descriptor TD queue tail pointer +//------------------------------------------------------------------------- +#define ED_HALTED 0x00000001 +#define ED_TOGGLE_CARRY 0x00000002 + +//Bit define for general pointer +//------------------------------------------------------------------------ +#define OHCI_TERMINATE 0x00000000 + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: OHCI_TD_CONTROL +// +// Description: Bit definition for OHCI_TD ControlStatus field +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// Reserved BITS:17-00 Reserved bits +// BufferRounding BITS:18 Buffer rounding (1-Allow small packets) +// DirectionPid BITS:20-19 Direction & PID (SETUP/IN/OUT etc) +// DelayInt BITS:23-21 Num. frames to wait before interrupting +// DataToggle BITS:25-24 Data toggle +// ErrorCount BITS:27-26 Error count +// ConditionCode BITS:31-28 Completion condition code +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END>*/ + +// Bit definition for general transfer descriptor control fields +//------------------------------------------------------------------------- +#define GTD_BUFFER_ROUNDING 0x000040000 +#define GTD_DIRECTION_PID 0x000180000 +#define GTD_SETUP_PACKET 0x000000000 +#define GTD_OUT_PACKET 0x000080000 +#define GTD_IN_PACKET 0x000100000 +#define GTD_DELAY_INTERRUPT 0x000e00000 +#define GTD_IntD 0x000000000 // depend on device,now guest 0 +#define GTD_DATA_TOGGLE 0x003000000 +#define GTD_SETUP_TOGGLE 0x002000000 // same as MSB of data toggle +#define GTD_DATA1_TOGGLE 0x003000000 +#define GTD_STATUS_TOGGLE 0x003000000 +#define GTD_ERROR_COUNT 0x00c000000 +#define GTD_NO_ERRORS 0x000000000 +#define GTD_ONE_ERROR 0x004000000 +#define GTD_TWO_ERRORS 0x008000000 +#define GTD_THREE_ERRORS 0x00C000000 +#define GTD_CONDITION_CODE 0x0f0000000 +//------------------------------------------------------------------------ + +// Bit define for ConditionCode or CompletionCode use for each CallBack func +// transmission error +//------------------------------------------------------------------------- +#define GTD_STATUS_FIELD 0x0f0000000 //include NOT_ACCESS +#define GTD_NO_ERROR 0x00 +#define GTD_CRC_ERROR 0x01 +#define GTD_BIT_STUFF 0x02 +#define GTD_TOGGLE_MISMATCH 0x03 +#define GTD_STALL 0x04 +#define GTD_DEVICE_NOT_RESPOND 0x05 +#define GTD_PID_CHECK_ERROR 0x06 +#define GTD_UNEXPECTED_PID 0x07 +#define GTD_DATA_OVERRUN 0x08 +#define GTD_DATA_UNDERRUN 0x09 +#define GTD_BUFFER_OVERRUN 0x0c // not used for GTD +#define GTD_BUFFER_UNDERRUN 0x0d // not used for GTD +#define GTD_NOT_ACCESSED 0x0f + +//------------------------------------------------------------------------- +// Equates for Host Controller Operational Register +// reg for control and status +//------------------------------------------------------------------------- +#define OHCI_REVISION_REG 0x00 +#define OHCI_CONTROL_REG 0x04 +#define OHCI_COMMAND_STATUS 0x08 +#define OHCI_INTERRUPT_STATUS 0x0c +#define OHCI_INTERRUPT_ENABLE 0x10 +#define OHCI_INTERRUPT_DISABLE 0x14 +// reg for memory pointer +#define OHCI_HCCA_REG 0x18 +#define OHCI_PERIOD_CURRENT_ED 0x1c +#define OHCI_CONTROL_HEAD_ED 0x20 +#define OHCI_CONTROL_CURRENT_ED 0x24 +#define OHCI_BULK_HEAD_ED 0x28 +#define OHCI_BULK_CURRENT_ED 0x2c +#define OHCI_DONE_HEAD 0x30 +// reg for frame counter +#define OHCI_FRAME_INTERVAL 0x34 +#define OHCI_FRAME_REMAINING 0x38 +#define OHCI_FRAME_NUMBER 0x3c +#define OHCI_PERIODIC_START 0x40 +#define OHCI_LS_THRESHOLD 0x44 +// reg for root hub +#define OHCI_RH_DESCRIPTOR_A 0x48 +#define OHCI_RH_DESCRIPTOR_B 0x4c +#define OHCI_RH_STATUS 0x50 +#define OHCI_RH_PORT1_STATUS 0x54 +#define OHCI_RH_PORT2_STATUS 0x58 + +// OHCI emulation register equates +#define OHCI_HCE_CONTROL 0x100 +#define OHCI_HCE_INPUT 0x104 +#define OHCI_HCE_OUTPUT 0x108 +#define OHCI_HCE_STATUS 0x10C + +// Bit definitions for emulation registers +#define HCE_CNTRL_EMULATION_ENABLE BIT0 +#define HCE_CNTRL_EMULATION_INTERRUPT BIT1 +#define HCE_CNTRL_CHARACTER_PENDING BIT2 +#define HCE_CNTRL_IRQ_ENABLE BIT3 +#define HCE_CNTRL_EXT_IRQ_ENABLE BIT4 +#define HCE_CNTRL_GA20_SEQ BIT5 +#define HCE_CNTRL_IRQ1_ACTIVE BIT6 +#define HCE_CNTRL_IRQ12_ACTIVE BIT7 +#define HCE_CNTRL_A20_STATE BIT8 + + +#define HCE_STS_OUTPUTFULL BIT0 +#define HCE_STS_INPUTFULL BIT1 +#define HCE_STS_FLAG BIT2 +#define HCE_STS_CMDDATA BIT3 +#define HCE_STS_INHIBIT_SWITCH BIT4 +#define HCE_STS_AUXOUTPUTFULL BIT5 +#define HCE_STS_TIMEOUT BIT6 +#define HCE_STS_PARITY BIT7 +//------------------------------------------------------------------------- +// Bit define for HC control register +//------------------------------------------------------------------------- +#define CONTROL_BULK_RATE 0x0003 +#define PERIODIC_LIST_ENABLE 0x0004 +#define ISOCHRONOUS_ENABLE 0x0008 +#define CONTROL_LIST_ENABLE 0x0010 +#define BULK_LIST_ENABLE 0x0020 +#define HC_FUNCTION_STATE 0x00c0 +#define USBRESET 0x0000 +#define USBRESUME 0x0040 +#define USBOPERATIONAL 0x0080 +#define USBSUSPEND 0x00c0 +#define INTERRUPT_ROUTING 0x0100 +#define REMOTE_WAKEUP_CONNECT 0x0200 +#define REMOTE_WAKEUP_ENABLE 0x0400 +//------------------------------------------------------------------------- + +// Bit define for HC command status register +//------------------------------------------------------------------------- +#define HC_RESET 0x00001 +#define CONTROL_LIST_FILLED 0x00002 +#define BULK_LIST_FILLED 0x00004 +#define OWNERSHIP_CHANGE_REQUEST 0x00008 +#define SCHEDULING_OVERRUN_COUNT 0x30000 + +// Bit define for HC interrupt status register +//------------------------------------------------------------------------- +#define SCHEDULING_OVERRUN 0x00000001 +#define WRITEBACK_DONEHEAD 0x00000002 +#define START_OF_FRAME 0x00000004 +#define RESUME_DETECTED 0x00000008 +#define UNCOVERABLE_ERR 0x00000010 +#define FRAMENUMBER_OVERFLOW 0x00000020 +#define RH_STATUS_CHANGE 0x00000040 +#define OWNERSHIP_CHANGE 0x40000000 + +// Bit define for HC interrupt enable register +//------------------------------------------------------------------------- +#define SCHEDULING_OVERRUN_ENABLE 0x00000001 +#define WRITEBACK_DONEHEAD_ENABLE 0x00000002 +#define START_OF_FRAME_ENABLE 0x00000004 +#define RESUME_DETECTED_ENABLE 0x00000008 +#define UNCOVERABLE_ERR_ENABLE 0x00000010 +#define FRAMENUMBER_OVERFLOW_ENABLE 0x00000020 +#define RH_STATUS_CHANGE_ENABLE 0x00000040 +#define OWNERSHIP_CHANGE_ENABLE 0x40000000 +#define MASTER_INTERRUPT_ENABLE 0x80000000 + +// Bit define for HC interrupt disable register +//------------------------------------------------------------------------- +#define SCHEDULING_OVERRUN_DISABLE 0x00000001 +#define WRITEBACK_DONEHEAD_DISABLE 0x00000002 +#define START_OF_FRAME_DISABLE 0x00000004 +#define RESUME_DETECTED_DISABLE 0x00000008 +#define UNCOVERABLE_ERR_DISABLE 0x00000010 +#define FRAMENUMBER_OVERFLOW_DISABLE 0x00000020 +#define RH_STATUS_CHANGE_DISABLE 0x00000040 +#define OWNERSHIP_CHANGE_DISABLE 0x40000000 +#define MASTER_INTERRUPT_DISABLE 0x80000000 + +// Bit define for HC frame interval register +//------------------------------------------------------------------------- +#define FRAME_INTERVAL 0x00003fff +#define FS_LARGEST_DATA_PACKET 0x4fff0000 +#define FRAME_INTERVAL_TOGGLE 0x80000000 + +// Bit define for HC frame remaining register +//------------------------------------------------------------------------- +#define FRAME_REMAINING 0x00003fff +#define FRAME_REMAINING_TOGGLE 0x80000000 + +// Bit define for HC root hub descriptor A register +//------------------------------------------------------------------------- +#define RH_PORT_NUMBER 0x000000ff +#define POWER_SWITCH_MODE 0x00000100 +#define NO_POWER_SWITCH 0x00000200 +#define DEVICE_TYPE 0x00000400 +#define OVERCURRENT_PROTECT 0x00000800 +#define NO_OVERCURRENT_PROTECT 0x00001000 +#define POWERON2POWERGOOD_TIME 0x0ff000000 + + +// Bit define for HC root hub descriptor B register +//------------------------------------------------------------------------- +#define DEVICE_REMOVABLE 0x0000ffff +#define PORT_POWER_MASK 0x0ffff0000 + +// Bit define for HC root hub status register +//------------------------------------------------------------------------- +#define LOCAL_POWER_STATUS 0x00000001 +#define CLEAR_GLOBAL_POWER 0x00000001 +#define OVERCURRENT 0x00000002 +#define DEVICE_REMOTE_WAKEUP 0x00008000 +#define SET_REMOTE_WAKEUP 0x00008000 +#define LOCAL_POWER_CHANGE 0x00010000 +#define SET_GLOBAL_POWER 0x00010000 +#define OVERCURRENT_CHANGE 0x00020000 +#define CLEAR_REMOTE_WAKEUP 0x80000000 + +// Bit define for HC root hub port1,2 status register +//------------------------------------------------------------------------- +#define CURRENT_CONNECT_STATUS 0x00000001 +#define CLEAR_PORT_ENABLE 0x00000001 +#define PORT_ENABLE_STATUS 0x00000002 +#define SET_PORT_ENABLE 0x00000002 +#define PORT_SUSPEND_STATUS 0x00000004 +#define SET_PORT_SUSPEND 0x00000004 +#define PORT_OVERCURRENT 0x00000008 +#define CLEAR_PORT_SUSPEND 0x00000004 +#define PORT_RESET_STATUS 0x00000010 +#define SET_PORT_RESET 0x00000010 +#define PORT_POWER_STATUS 0x00000100 +#define SET_PORT_POWER 0x00000100 +#define LOW_SPEED_DEVICE_ATTACHED 0x00000200 +#define CLEAR_PORT_POWER 0x00000200 +#define CONNECT_STATUS_CHANGE 0x00010000 +#define PORT_ENABLE_STATUS_CHANGE 0x00020000 +#define PORT_SUSPEND_STATUS_CHANGE 0x00040000 +#define PORT_OVERCURRENT_CHANGE 0x00080000 +#define PORT_RESET_STATUS_CHANGE 0x00100000 + +#endif // __OHCI_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/syskbc.c b/Core/EM/usb/rt/syskbc.c new file mode 100644 index 0000000..157a9bd --- /dev/null +++ b/Core/EM/usb/rt/syskbc.c @@ -0,0 +1,3225 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/syskbc.c 41 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 41 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/syskbc.c $ +// +// 41 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 +// +// 40 2/24/15 5:50a Wilsonlee +// [TAG] EIP149716 +// [Category] Improvement +// [Description] Error Handling in USB mouse data. +// [Files] usbms.c, usbkbd.h, syskbc.c, xhci.c +// +// 39 7/23/14 10:23p Wilsonlee +// [TAG] EIP177642 +// [Category] Improvement +// [Description] SysKbcAutoRepeat handles the error case, the +// kbdInput_Send return error status. +// [Files] syskbc.c +// +// 38 6/26/14 1:15a 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 +// +// 37 5/06/14 5:14a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 36 5/01/14 4:24a Ryanchou +// [TAG] EIP151894 +// [Category] Improvement +// [Description] Correct the break code of arrow keys. +// [Files] syskbc.c +// +// 35 4/29/14 7:53p Wilsonlee +// [TAG] EIP163828 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The mouses stop more than 4 seconds during TP 0xB4 when +// power on several times. +// [RootCause] The device sometime doesn't respond the set report +// command. +// [Solution] Change the timeout of set report command to 100 ms. +// [Files] syskbc.c, sysnokbc.c, usbhid.c, amiusb.h +// +// 34 12/30/13 3:42a Wilsonlee +// [TAG] EIP148411 +// [Category] Improvement +// [Description] Check if CCB_MOUSE_INTRPT is set before we sent mouse +// data. +// [Files] usbkbd.h, syskbc.c +// +// 33 8/22/13 6:32a Wilsonlee +// [TAG] EIP122944 +// [Category] Improvement +// [Description] Remove mouse_flag3 and check the mouse interface status +// in the CCB byte before we send the data to KBC. +// [Files] syskbc.c, usbms.c +// +// 32 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 +// +// 31 12/02/12 10:29p Roberthsu +// [TAG] EIP102150 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Push key and unplug KB , character repeat can not. +// stop +// [RootCause] Because repeat key does not clear when usb keyboard +// unplug. +// [Solution] When keyboard disconnrct, clear keyboard device id with +// device id buffer and scancode buffer. +// [Files] amiusb.c,syskbc.c,uhcd.c,usbkbd.c +// +// 30 8/27/12 5:08a Roberthsu +// [TAG] EIP98251 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] RF KB NumLock/ScrollLock/CapsLock indicator is not +// available during post or BIOS setup menu +// [RootCause] Set led command lost report id. +// [Solution] Check report id exist. +// [Files] syskbc.c,usbhid.c +// +// 29 5/22/12 10:55a Jittenkumarp +// [TAG] EIP87959 +// [Category] New Feature +// [Description] Proper Error path in the USB driver, incase KBC Input +// buffer is full +// [Files] usbkbd.h, syskbc.c +// +// 28 5/22/12 6:32a Ryanchou +// [TAG] EIP89608 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Barcode reader does not scan line-word +// [RootCause] The EIP72505 change breaks the loop of processing scan +// code buffer. +// [Solution] All the character should be processed. +// [Files] syskbc.c +// +// 27 1/04/12 6:54a Ryanchou +// [TAG] EIP72505 +// [Category] Improvement +// [Description] Clear the legacy USB keyboard buffer when switching +// between EFI and legacy. +// [Files] syskbc.c, uhcd.c, usbkbd.c +// +// 26 12/08/11 4:04a Ryanchou +// [TAG] EIP75266 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] There are garbage characters if press arrow key for a while +// [RootCause] The arrow generates 4 bytes of repeat key for scan code +// set 1, it should be 2 bytes. +// [Solution] Correct the repeat key generation. +// [Files] syskbc.c +// +// 25 9/27/11 12:07a Roberthsu +// [TAG] EIP65344 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Razer mouse will hang in post +// [RootCause] Razer has report keyboard interface.But not report led +// usage. +// [Solution] Check if not report led usage page.Do not send led +// command. +// [Files] syskbc.c,usbhid.c,usbdef.h +// +// 24 7/13/11 3:24a Ryanchou +// [TAG] EIP60380 +// [Bug fix] USB keyboard can't repeat character under DOS +// [Symptom] Insert the wireless USB keyboard. It can't repeat character +// under DOS +// [Root Cause] Because wRepeatCounter always clear by every time. +// [Solution] Do not clear wRepeatCounter everytime. +// +// 23 5/24/11 12:04p Olegi +// [TAG] EIP56557 +// [Category] Improvement +// [Description] Modified SendMouseData function. +// [Files] syskbc.c +// +// 22 5/24/11 12:00p Olegi +// [TAG] EIP60261 +// [Category] Improvement +// [Description] Ultrasound keyboard fails the LED related transfer. +// [Files] syskbc.c +// +// 21 5/03/11 6:56a Ryanchou +// [TAG] EIP57745 +// [Category] Improvement +// [Description] The token CHECK_MOUSE_FLAG is depend on CSM version, +// remove the token and check CSM verion to support this feature or not. +// [Files] syskbc.c, usbms.c, usbsrc.sdl +// +// 20 9/08/10 8:06a Ryanchou +// EIP43822: Add a toekn "CHECK_MOUSE_FLAG", the token controls whether +// apply EIP40121 solution. +// +// 19 8/18/10 4:27p Olegi +// - Klockwork related fixes; EIP37978 +// - Send mouse driver only when driver is active; EIP40121 +// +// 18 7/08/10 2:21a Rameshr +// Ohci Emulation support Added. +// EIP 39712 +// +// 17 11/24/09 11:33a Olegi +// BIOS adds an USB API (Block KBC Access) +// +// 16 11/18/09 11:49a Olegi +// +// 15 11/18/09 11:48a Olegi +// Modified the codes returned on Shift-NumLock-ExtKeys(Home, Ins,...) +// combination. For these combinations NumLock cancels Shift. EIP#27889 +// +// 14 9/15/09 12:21p Olegi +// Added KEY_REPEAT_LOGIC functionality. EIP#25841 +// +// 13 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 12 12/19/07 12:20p Rameshraju +// Emulation disabled before getting the CCB and Enabled back again if the +// Emulation is active. +// +// 11 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 10 9/27/07 4:12p Olegi +// +// 9 9/26/07 9:25a Olegi +// +// 8 8/14/07 11:03a Olegi +// USBSendMouseData is using USB_MOUSE_UPDATE_EBDA_DATA token. +// +// 7 3/29/07 6:42p Olegi +// Code improvement in USBMSSendMouseData to avoid sync problems between +// PS/2 and USB mice. +// +// 6 3/20/07 12:22p Olegi +// +// 4 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 11/15/05 3:42p Andriyn +// Fix: 2-byte keys get lost. +// +// 1 8/25/05 7:15p Andriyn +// +// 5 8/11/05 9:53a Olegi +// 60/64 port emulation related fixes for EMU6064 driver. +// +// 4 8/04/05 5:58p Andriyn +// Legacy over LegacyFree +// +// 2 6/01/05 5:22p Olegi +// Debug message shortened. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: SysKbc.c +// +// Description: AMI USB keyboard driver data conversion and presentation +// routines, KBC is present +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" + +extern USB_GLOBAL_DATA *gUsbData; + +extern UINT8 aTypematicRateDelayTable[]; +extern EFI_EMUL6064KBDINPUT_PROTOCOL* gKbdInput; +extern EFI_EMUL6064MSINPUT_PROTOCOL* gMsInput; +extern EFI_EMUL6064TRAP_PROTOCOL* gEmulationTrap; +extern void USBKB_LEDOn(); + +UINT8 IsKbcAccessBlocked=FALSE; //(EIP29733+) + +UINT8 aStaticSet2ToSet1ScanCode[133] = + { 0x000,0x0E5,0x0F5,0x006,0x016,0x026,0x01E,0x03D, //; 00h - 07h + 0x0DC,0x0DD,0x0ED,0x0FD,0x00E,0x087,0x0B6,0x035, //; 08h - 0Fh + 0x0D4,0x03E,0x0AE,0x07C,0x017,0x07F,0x0EF,0x02D, //; 10h - 17h + 0x0CC,0x074,0x09E,0x007,0x00F,0x077,0x0E7,0x025, //; 18h - 1Fh + 0x0C4,0x08E,0x096,0x0FE,0x06F,0x0D7,0x0DF,0x01D, //; 20h - 27h + 0x0BC,0x036,0x086,0x0F6,0x05F,0x067,0x0CF,0x015, //; 28h - 2Fh + 0x0B4,0x076,0x07E,0x0E6,0x0EE,0x057,0x0C7,0x00D, //; 30h - 37h + 0x0AC,0x06C,0x06E,0x0DE,0x04F,0x0BF,0x0B7,0x005, //; 38h - 3Fh + 0x0A4,0x066,0x0D6,0x047,0x03F,0x0A7,0x0AF,0x0FC, //; 40h - 47h + 0x09C,0x05E,0x056,0x0CE,0x0C6,0x037,0x09F,0x0F4, //; 48h - 4Fh + 0x094,0x064,0x0BE,0x05C,0x02F,0x097,0x0EC,0x08C, //; 50h - 57h + 0x02E,0x04E,0x01F,0x027,0x054,0x0A6,0x0E4,0x04C, //; 58h - 5Fh + 0x055,0x04D,0x044,0x03C,0x034,0x02C,0x08F,0x024, //; 60h - 67h + 0x01C,0x085,0x014,0x0A5,0x0C5,0x00C,0x004,0x084, //; 68h - 6Fh + 0x06D,0x065,0x07D,0x09D,0x095,0x0BD,0x0F7,0x0D5, //; 70h - 77h + 0x045,0x08D,0x075,0x0AD,0x046,0x0B5,0x0CD,0x05D, //; 78h - 7Fh + 0x0FB,0x0F3,0x0EB,0x0F5,0x05D //; 80h - 84h + }; + +//---------------------------------------------------------------------------- +//------ USA ENGLISH keyboard ------- +// USB Key Code to Scan Code Set 2 + +UINT8 aUSBKeyCodeToScanCodeSet2Table[256] = + { + 0x00, 0x00, 0x00, 0x00, 0x1C, 0x32, 0x21, 0x23, //00 - 07h + 0x24, 0x2B, 0x34, 0x33, 0x43, 0x3B, 0x42, 0x4B, //08 - 0Fh + 0x3A, 0x31, 0x44, 0x4D, 0x15, 0x2D, 0x1B, 0x2C, //10 - 17h + 0x3C, 0x2A, 0x1D, 0x22, 0x35, 0x1A, 0x16, 0x1E, //18 - 1Fh + 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, 0x45, //20 - 27h + 0x5A, 0x76, 0x66, 0x0D, 0x29, 0x4E, 0x55, 0x54, //28 - 2Fh + 0x5B, 0x5D, 0x5D, 0x4C, 0x52, 0x0E, 0x41, 0x49, //30 - 37h + 0x4A, 0x58, 0x05, 0x06, 0x04, 0x0C, 0x03, 0x0B, //38 - 3Fh + 0x83, 0x0A, 0x01, 0x09, // 40 - 43h + 0x78, 0x07, PRINT_SCREEN,0x7E, // 44 - 47h + PAUSE_KEY, INSERT_KEY, HOME_KEY, // 48 - 4Ah + PAGE_UP_KEY, DEL_KEY, END_KEY, // 4B - 4Dh + PAGE_DOWN_KEY, RIGHT_KEY, // 4E - 4Fh + LEFT_KEY, DOWN_KEY, UP_KEY, 0x77, // 50 - 53h + SLASH_KEY, 0x7C, 0x7B, 0x79, // 54 - 57h + RIGHT_ENTER, 0x69, 0x72, 0x7A, // 58 - 5Ch + 0x6B, 0x73, 0x74, 0x6C, // 5D - 5Fh + 0x75, 0x7D, 0x70, 0x71, 0x61, APP_MS_KEY,00, 0x00, // 60 - 67h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 68 - 6Fh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 70 - 77h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //78 - 7Fh + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, // 80 - 87h + 0x13, 0x6A, 0x64, 0x67, 0x00, 0x00, 0x00, 0x00, // 88 - 8Fh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 90 - 97h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 98 - 9Fh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A0 - A7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // A8 - AFh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B0 - B7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B8 - BFh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C0 - C7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C8 - CFh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D0 - D7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D8 - DFh + 0x14, 0x12, 0x11, LEFT_MS_KEY, // E0 - E3h + RIGHT_CTRL, 0x59, RIGHT_ALT, RIGHT_MS_KEY, // E4 - E7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E8 - EFh + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F0 - F7h + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // F8 - FFh + }; +// Keyboard Scan Code Set 3 Table +#define SCAN_CODE_SET_TABLE_SIZE_DW 8 // In double word +UINT8 aStaticScanCodeSet3Table[32] = + { + 0x00, 0x15, 0x00, 0x28, 0x94, 0x29, 0xA4, 0x2A, + 0xA8, 0x2A, 0xA8, 0x2A, 0xA8, 0x2A, 0xA0, 0x2A, + 0xA8, 0x2A, 0xA8, 0x2A, 0xA8, 0x0A, 0xA4, 0x0A, + 0x8A, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02 + }; + + +UINT8 aStaticExtendedKeyScan2Table[6] = + { RIGHT_ALT, RIGHT_CTRL, RIGHT_ENTER, LEFT_MS_KEY, + RIGHT_MS_KEY, APP_MS_KEY }; + +UINT8 aStaticKeyPadScan2Table[10] = + { END_KEY, LEFT_KEY, HOME_KEY, INSERT_KEY, + DEL_KEY, DOWN_KEY, RIGHT_KEY, UP_KEY, + PAGE_DOWN_KEY, PAGE_UP_KEY }; + + +UINT8 aStaticExtendedKeyScan3Table[6] = + { 0x39, 0x58, 0x79, 0x8B, 0x8C, 0x8D}; +UINT8 aStaticKeyPadScan3Table[10] = + { 0x65, 0x61, 0x6E, 0x67, 0x64, 0x60, 0x6A, 0x63, 0x6D, 0x6F }; + +//---------------------------------------------------------------------------- +// Table used to find length of scan code needed. Please refer to comments +// in the code below (somewhere) for the usage. +// +UINT8 aScanCodeLengthTable_1112[4] = {0x01, 0x01, 0x01, 0x02}; +UINT8 aScanCodeLengthTable_2223[4] = {0x02, 0x02, 0x02, 0x003}; +UINT8 aScanCodeLengthTable_4446[4] = {0x04, 0x04, 0x04, 0x06}; +UINT8 aScanCodeLengthTable_4500[4] = {0x04, 0x05, 0x00, 0x00}; +UINT8 aScanCodeLengthTable_4545[4] = {0x04, 0x05, 0x04, 0x05}; +UINT8 aScanCodeLengthTable_6800[4] = {0x06, 0x08, 0x00, 0x00}; + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_WaitForInputBufferToBeFree +// +// Description: This routine checks the input buffer free bit and waits till +// it is set by the keyboard controller +// +// Input: Nothing +// +// Output: USB_SUCCESS - If Input buffer is Empty +// USB_ERROR - If Input buffer is Full +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_WaitForInputBufferToBeFree () +{ + UINT8 bCount = 16, + bStatus; + UINT16 wCount = 0xFFFF; + do { + bStatus = (UINT8)(ByteReadIO(KBC_STATUS_REG) & BIT1); + while(bStatus) { + if(wCount == 0) + break; + bStatus = (UINT8)(ByteReadIO(KBC_STATUS_REG) & BIT1); + --wCount; + } + --bCount; + } while (bCount && bStatus); + + if (!bStatus) { + return USB_SUCCESS; + } else { + return USB_ERROR; + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_WaitForOutputBufferToBeFilled +// +// Description: This routine checks the output buffer full bit and waits till +// it is set by the keyboard controller +// +// Input: Nothing +// +// Output: USB_SUCCESS - If OutPut buffer is Full +// USB_ERROR - If Output buffer Empty +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_WaitForOutputBufferToBeFilled () +{ + UINT8 bCount = 16, + bStatus; + UINT16 wCount = 0xffff; + do { + bStatus = (UINT8)(ByteReadIO(KBC_STATUS_REG) & BIT0); + while (!bStatus) { + if(wCount == 0) break; + bStatus = (UINT8)(ByteReadIO(KBC_STATUS_REG) & BIT0); + wCount--; + } + bCount--; + } while (bCount && (!bStatus)); + + if (bStatus) { + return USB_SUCCESS; + } else { + return USB_ERROR; + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_ReadDataByte +// +// Description: This routine till the keyboard controller sends a data byte +// +// Input: Nothing +// +// Output: Status - USB_SUCCESS +// - USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_ReadDataByte ( + IN UINT8 *Data ) +{ + UINT8 Status; + + Status = KBC_WaitForOutputBufferToBeFilled(); + + if (Status == USB_SUCCESS) { + *Data = ByteReadIO(KBC_DATA_REG); + } + + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_WriteCommandByte +// +// Description: This routine sends the command byte to the keyboard +// controller +// +// Input: IN UNIT8 bCmd - Command byte +// +// Output: Status - USB_SUCCESS +// - USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_WriteCommandByte ( + IN UINT8 bCmd ) +{ + UINT8 Status; + + Status = KBC_WaitForInputBufferToBeFree(); + + if (Status == USB_SUCCESS) { + ByteWriteIO(KBC_COMMAND_REG, bCmd); + } + + Status = KBC_WaitForInputBufferToBeFree(); + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_WriteSubCommandByte +// +// Description: This routine sends the sub-command byte to the keyboard +// controller +// +// Input: bCmd Sub-command byte +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +KBC_WriteSubCommandByte (UINT8 bCmd) +{ + ByteWriteIO(KBC_SUBCOMMAND_REG, bCmd); + KBC_WaitForInputBufferToBeFree(); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_ReadKeyboardControllerData +// +// Description: This routine sends a command and receives the response byte +// for that command +// +// Input: IN UINT8 bCmd - Command to be sent +// In UINT8 *Data - Data to be Read +// +// Output: Status - USB_SUCCESS +// - USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_ReadKeyboardControllerData ( + IN UINT8 bCmd, + IN UINT8 *Data ) +{ + UINT8 Status; + + Status = KBC_WaitForInputBufferToBeFree(); // Wait for input buffer to be free + + if (Status == USB_SUCCESS) { + Status = KBC_WriteCommandByte(bCmd); // Send the command + if (Status == USB_SUCCESS) { + Status = KBC_ReadDataByte(Data); // Read the data + } + } + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: KBC_WriteKeyboardControllerData +// +// Description: This routine writes a data byte to the keyboard controller +// by first sending a command byte first +// +// Input: IN UINT8 bCmd - Command to be sent +// IN UINT8 bData - Data to be sent +// +// Output: Status - USB_SUCCESS +// USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +KBC_WriteKeyboardControllerData ( + IN UINT8 bCmd, + IN UINT8 bData ) +{ + UINT8 Status; + + Status = KBC_WaitForInputBufferToBeFree(); // Wait for input buffer to be free + + if (Status == USB_SUCCESS) { + Status = KBC_WriteCommandByte(bCmd); // Send the command + if (Status == USB_SUCCESS) { + ByteWriteIO(KBC_DATA_REG, bData); // Write the data + } + } + + Status = KBC_WaitForInputBufferToBeFree(); // Wait for input buffer to be free + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SYSKBC_UpdateLEDState +// +// Description: This routine updates LEDs on Legacy keyboard +// +// Input: LED state data +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SYSKBC_UpdateLEDState ( + EFI_EMUL6064KBDINPUT_PROTOCOL* pThis, + UINT8 bData +) +{ +/* + UINT8 bCmd, + bKBData = 0, + bSave; + + // + // Wait for input buffer to be free + // + KBC_WaitForInputBufferToBeFree(); + KBC_WriteCommandByte(USB_SEND_COMMAND_TO_KBC); + bSave = ByteReadIO(KBC_STATUS_REG); + + // + // Data is pending. Read it in AL + // + if(bSave & BIT0) + { + bKBData = ByteReadIO(KBC_DATA_REG); + } + KBC_WriteCommandByte(0xAE); + KBC_WriteSubCommandByte(0xED); + KBC_ReadDataByte(); + KBC_WriteSubCommandByte(bData); + KBC_ReadDataByte(); + + if((bSave & BIT0) == 0) + { + return EFI_SUCCESS; + } + bCmd = 0xD2; + if(bSave & BIT5) + { + bCmd = 0xD3; + } + KBC_WriteKeyboardControllerData(bCmd, bKBData); +*/ + return EFI_SUCCESS; +} + +void +SYSKBC_GetAndStoreCCB() +{ + UINT8 bStatus, + bCmd, + bData = 0; + UINT8 Temp; + UINT8 Status; + + + // + //If Emulation Active disable the SMI Generation + // + if(gEmulationTrap) + gEmulationTrap->TrapDisable(gEmulationTrap); + + bStatus = ByteReadIO(KBC_STATUS_REG); + if(bStatus & BIT0) + { + bData = ByteReadIO(KBC_DATA_REG); + } + + Status = KBC_ReadKeyboardControllerData(0x20, &Temp); + if (Status == USB_SUCCESS) { + gUsbData->bCCB = Temp; + } + + if(bStatus & BIT0) + { + bCmd = 0xD2; + if(bStatus & BIT5) + { + bCmd = 0xD3; + } + KBC_WriteKeyboardControllerData(bCmd, bData); + } + // + //If Emulation Active Enable the SMI Generation + // + if(gEmulationTrap) + gEmulationTrap->TrapEnable(gEmulationTrap); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMSUpdateMouseInterface +// +// Description: This routine is called to enable or disable the mouse +// interface +// +// Input: None +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +/* +void USBMSUpdateMouseInterface() +{ + UINT8 bCmd = 0xA8; // Enable mouse interface + + if (!(gUsbData->bMouseStatusFlag & MOUSE_DATA_READY_BIT_MASK)) + { + if(gUsbData->fpMouseInputBufferHeadPtr != + gUsbData->fpMouseInputBufferTailPtr) + { + bCmd = 0xA7; // Disable mouse interface + } + } + KBC_WriteCommandByte(bCmd); // Send command to KBC + +} +*/ + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBMSSendMouseData +// +// Description: This routine is called to send the mouse data to the KB +// controller +// +// Input: Nothing +// +// Output: 0xFF data processed +// 0 data not processed +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 USBMSSendMouseData() +{ + UINT16 ebdaSeg = *(UINT16*)0x40E; + UINT8 bData; + UINT8 *ebda = (UINT8*)((UINTN)ebdaSeg<<4); + UINT8 packageSize = ebda[0x27] & 7; + UINT8 index=0; +/* + if (gUsbData->bMouseStatusFlag & MOUSE_DATA_READY_BIT_MASK) { + if (gUsbData->bCCB & 0x20) + { + gUsbData->fpMouseInputBufferHeadPtr = &gUsbData->aMouseInputBuffer[0]; + gUsbData->fpMouseInputBufferTailPtr = &gUsbData->aMouseInputBuffer[0]; + return 0; + } else { + ebda[0x26] &= ~7; + KBC_WriteCommandByte(0xA7); // Disable mouse interface + } + } +*/ + if (gUsbData->fpMouseInputBufferHeadPtr == gUsbData->fpMouseInputBufferTailPtr) { + return 0; + } + + if ((gUsbData->bCCB & CCB_MOUSE_DISABLED) || + !(gUsbData->bCCB & CCB_MOUSE_INTRPT)) { + gUsbData->fpMouseInputBufferHeadPtr = &gUsbData->aMouseInputBuffer[0]; + gUsbData->fpMouseInputBufferTailPtr = &gUsbData->aMouseInputBuffer[0]; + return 0; + } + + ebda[0x26] &= ~7; + +#if USB_MOUSE_UPDATE_EBDA_DATA + for (; index<packageSize; index++) { + ebda[0x28+index] = USBMouse_GetFromMouseBuffer(); + ebda[0x26]++; + } +#endif + bData = USBMouse_GetFromMouseBuffer(); + KBC_WriteKeyboardControllerData(0xD3, bData); // Send the last byte of data + + // + // Flag indicates data from USB mouse + // + //gUsbData->bMouseStatusFlag |= MOUSE_DATA_FROM_USB_BIT_MASK; + + // + // Indicate that first byte already sent + // + //gUsbData->bMouseStatusFlag &= ~(MOUSE_DATA_READY_BIT_MASK); + + //USBMSUpdateMouseInterface(); // Enable/disable mouse interface + + return 0xFF; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMouse_SendToMouseBuffer +// +// Description: This routine puts a byte into the mouse input buffer. +// Mouse input buffer pointers are also updated +// +// Input: bData - Byte to be put in the mouse input buffer +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +void +USBMouse_SendToMouseBuffer(UINT8 bData) +{ + *gUsbData->fpMouseInputBufferHeadPtr = bData; // Put the byte in the buffer + gUsbData->fpMouseInputBufferHeadPtr++; // Advance the buffer pointer + + // + // Check whether the buffer end is reached, if buffer end reached + // then position the buffer pointer to the start + // + if (gUsbData->fpMouseInputBufferHeadPtr == + (gUsbData->aMouseInputBuffer + sizeof(gUsbData->aMouseInputBuffer))) + { + gUsbData->fpMouseInputBufferHeadPtr = gUsbData->aMouseInputBuffer; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMouse_GetFromMouseBuffer +// +// Description: This routine retrieves a byte from the mouse input buffer. +// Mouse input buffer pointers are also updated +// +// Input: None +// +// Output: bData - Byte to be taken from the mouse input buffer +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 USBMouse_GetFromMouseBuffer () +{ + UINT8 bData = *gUsbData->fpMouseInputBufferTailPtr; + *gUsbData->fpMouseInputBufferTailPtr = 0; + gUsbData->fpMouseInputBufferTailPtr++; + + // + // Check whether the buffer end is reached, if buffer end reached + // then wrap around to the start + // + if (gUsbData->fpMouseInputBufferTailPtr == + (&gUsbData->aMouseInputBuffer[0] + sizeof(gUsbData->aMouseInputBuffer))) + { + gUsbData->fpMouseInputBufferTailPtr = &gUsbData->aMouseInputBuffer[0]; + } + return bData; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SYSKBC_SendKBCData +// +// Description: This routine is invoked periodically (every 8msec) to send +// USB keyboard and mouse data to the keyboard controller +// or to the keyboard controller emulation code +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SYSKBC_SendKBCData() +{ + UINT8 bCmd = 0, + bTemp1 = 0, + bTemp = 0, + bFlag = 1; + UINT16 wTemp; +// UINT16 ebdaSeg = *(UINT16*)0x40E; +// UINT8 *ebda = (UINT8*)((UINTN)ebdaSeg<<4); +// UINT8 mouse_flag3; + UINT8 Status; + UINT8 Temp; + + //Is KBC access allowed? + if(IsKbcAccessBlocked) { + return EFI_NOT_READY; + } +// USBKBC_CheckAutoRepeat(); + + // + //If Emulation Active disable the SMI Generation + // + if(gEmulationTrap){ + if (!gEmulationTrap->TrapDisable(gEmulationTrap)) { + // Data is still pending. So don't push data. + goto enableRepeat_Exit; + } + } + + // + // Check whether BIOS is processing IRQ1 or IRQ12 + // + ByteWriteIO(0x20, 0xB); + if (ByteReadIO(0x20) & 2) { + goto enableRepeat_Exit; + } + + ByteWriteIO(0xA0, 0xB); + if (ByteReadIO(0xA0) & 0x10) { + goto enableRepeat_Exit; + } + + if (ByteReadIO(KBC_STATUS_REG) & BIT0){ + goto enableRepeat_Exit; + } + + for(;;) { + // + // Check the data transmit order + // + wTemp = (UINT16)(gUsbData->wUSBKBC_StatusFlag & + KBC_DATA_TX_ORDER_BIT_MASK); + if(wTemp == KBC_DATA_TX_ORDER_KB_FIRST) { + bFlag = 0; + bCmd = 0xD2; // Send keyboard data + // + // Check for keyboard data and then for mouse data + // + if(gUsbData->fpKBCCharacterBufferHead != + gUsbData->fpKBCCharacterBufferTail) + break; + // + // Check for mouse data + // + #if USB_DEV_MOUSE + bCmd = 0xD3; + if(gUsbData->fpMouseInputBufferHeadPtr != + gUsbData->fpMouseInputBufferTailPtr) + { + break; + } + #endif + bFlag = 1; + } else { + bFlag = 0; + #if USB_DEV_MOUSE + bCmd = 0xD3; + if(gUsbData->fpMouseInputBufferHeadPtr != + gUsbData->fpMouseInputBufferTailPtr) + { + // + // Check for keyboard data and then for mouse data + // + break; + } + #endif + // + // Check for keyboard data + // + bCmd = 0xD2; + if(gUsbData->fpKBCCharacterBufferHead != + gUsbData->fpKBCCharacterBufferTail) + break; + bFlag = 1; + } + break; + } + + if(bFlag) { + USB_DEBUG (DEBUG_LEVEL_8, "USBKBC_SendKBCData: Scan Code Buffer Empty \n"); + // + // Check whether the scan code buffer is empty + // + if(gUsbData->fpKBCScanCodeBufferPtr != gUsbData->aKBCScanCodeBufferStart) + { + goto enableRepeat_Exit; + } + // + // Get pointer to the HC driver + // Scan code buffer is empty. Stop the key repeat by stopping repeat TD + // + USB_DEBUG (DEBUG_LEVEL_8, "HCDDisableKeyRepeat \n"); + USBKeyRepeat(NULL, 1); // Disable Key repeat + + if(gEmulationTrap) { + gEmulationTrap->TrapEnable(gEmulationTrap); + } + return EFI_SUCCESS; + } + + for (;;) { + Status = KBC_WaitForInputBufferToBeFree(); + if (Status == USB_SUCCESS) { + ByteWriteIO(KBC_COMMAND_REG, USB_SEND_COMMAND_TO_KBC); + } else { + goto enableRepeat_Exit; + } + // + // Check the return status + // + do { + bTemp1 = ByteReadIO(KBC_STATUS_REG); + if(bTemp1 & BIT0) { + bFlag = 3 ; + break; + } + } while (bTemp1 & BIT1); + USB_DEBUG (DEBUG_LEVEL_8, "USBKBC_SendKBCData: bFlag %x\n",bFlag); + if (bFlag == 3) break; + // + // Update the data transmit order + // + gUsbData->wUSBKBC_StatusFlag = + (UINT16)((gUsbData->wUSBKBC_StatusFlag) + + (KBC_DATA_TX_ORDER_INC_VALUE)); + wTemp = (UINT16)(gUsbData->wUSBKBC_StatusFlag & + KBC_DATA_TX_ORDER_BIT_MASK); + if((wTemp & KBC_DATA_TX_ORDER_BIT_MASK) == 0) { + gUsbData->wUSBKBC_StatusFlag &= + ~((UINT16)KBC_DATA_TX_ORDER_BIT_MASK); + } + + // + // Get the CCB + // + Status = KBC_WriteCommandByte(0x20); // Send command to KBC + if (Status == USB_SUCCESS) { + Status = KBC_ReadDataByte(&Temp); // Get data from KBC + if (EFI_ERROR(Status)) { + goto enableRepeat_Exit; + } + gUsbData->bCCB = Temp; + } else { + goto enableRepeat_Exit ; + } + + // + // Check for mouse data + // + if((bCmd & 1) == 0) { + // + // Check whether keyboard is disabled + // + if((gUsbData->bCCB & CCB_KEYBOARD_DISABLED) == 0) { + // + // Check whether the current mode is IRQ + // Check whether password is enabled + // + if((gUsbData->wUSBKBC_StatusFlag & + KBC_PASSWORD_FLAG_BIT_MASK) == 0) + bTemp = USBKBC_GetFromCharacterBuffer(); + + if (bTemp == 0xff) { + goto enableRepeat_Exit; + } + KBC_WriteKeyboardControllerData(bCmd , bTemp); + USBKeyRepeat(NULL, 2); // Enable Key repeat + if (gEmulationTrap) { + gEmulationTrap->TrapEnable(gEmulationTrap); + } + return EFI_SUCCESS; + } + bTemp = 0xFF; + } else { + #if USB_DEV_MOUSE + if (USBMSSendMouseData()) { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + +/* + //(EIP57745+)> + // + // Check the version of CSM16, support is available for ver 7.64 or later + // + { + UINT8 MjCsmVer = *(UINT8*)0xF0018; + UINT8 MnCsmVer = *(UINT8*)0xF0019; + + if (MjCsmVer > 7 || MnCsmVer > 0x63) + { + mouse_flag3 = ebda[0x30] & 1; //check mouse driver + if(mouse_flag3) { + if(USBMSSendMouseData()) { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + } else { + gUsbData->fpMouseInputBufferHeadPtr = &gUsbData->aMouseInputBuffer[0]; + gUsbData->fpMouseInputBufferTailPtr = &gUsbData->aMouseInputBuffer[0]; + } + } + else + { + if(USBMSSendMouseData()) { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + } + } + //<(EIP57745+) +*/ + if(gEmulationTrap) + gEmulationTrap->TrapEnable(gEmulationTrap); + return EFI_SUCCESS; + #else + bTemp = 0xFF; + #endif + } + break; + } + + if(bFlag == 3) { + bTemp = 0xAE; + if(bTemp1 & 0x20) { // 0/1 = KB/Mouse data + #if USB_DEV_MOUSE + // + // Enable/disable mouse depending on the data + // + //USBMSUpdateMouseInterface(); + #endif + goto enableRepeat_Exit; + } + } + KBC_WriteCommandByte(bTemp); + +enableRepeat_Exit: + USBKeyRepeat(NULL, 2); // Enable Key repeat + if (gEmulationTrap) { + gEmulationTrap->TrapEnable(gEmulationTrap); + } + return EFI_NOT_READY; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SYSKBC_KbdInput_Send +// +// Description: This routine sends the Keyboard Data to Controller +// +// Input: +// IN EFI_EMUL6064KBDINPUT_PROTOCOL* This, +// IN UINT8* Data, +// IN UINT32 Count +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SYSKBC_KbdInput_Send( + IN EFI_EMUL6064KBDINPUT_PROTOCOL* This, + IN UINT8* Data, + IN UINT32 Count +) +{ + EFI_STATUS Status; + + if (Count == 0) { + return EFI_SUCCESS; + } + + do { + Status=SYSKBC_SendKBCData(); + Count--; + } while (Count != 0 && Status == EFI_SUCCESS); + + return Status; + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SYSKBC_MouseInput_Send +// +// Description: This routine sends the Mouse Data to Controller +// +// Input: +// IN EFI_EMUL6064MSINPUT_PROTOCOL* This, +// IN PS2MouseData* Data +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SYSKBC_MouseInput_Send( + IN EFI_EMUL6064MSINPUT_PROTOCOL* This, + IN PS2MouseData* Data +) +{ + return SYSKBC_SendKBCData(); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SendMouseData +// +// Description: This routine sends the Mouse Data to Local Mouse Buffer +// +// Input: +// IN PS2MouseData* Data +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SendMouseData( + IN PS2MouseData* Data +) +{ + USBMouse_SendToMouseBuffer(Data->flags); // Send status byte + USBMouse_SendToMouseBuffer(Data->x); // Send X-axis information + USBMouse_SendToMouseBuffer(Data->y); // Send Y-axis information + + // + // Check for 4-byte mouse data and send the 4th dummy data if needed + // + //if(gUsbData->bMouseStatusFlag & MOUSE_4BYTE_DATA_BIT_MASK) + //{ + // USBMouse_SendToMouseBuffer(0); + //} + // + // Set flag to indicate mouse data ready + // + //gUsbData->bMouseStatusFlag |= MOUSE_DATA_READY_BIT_MASK; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SYSKBC_GetTranslation +// +// Description: This routine Get the KBC SCAN code transalation value +// +// Input: +// IN EFI_EMUL6064KBDINPUT_PROTOCOL* This, +// OUT KBC_KBDTRANSLATION* OutTrans +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +SYSKBC_GetTranslation( + IN EFI_EMUL6064KBDINPUT_PROTOCOL* This, + OUT KBC_KBDTRANSLATION* OutTrans +) +{ + static BOOLEAN IsCcbLoaded = FALSE; + + if (!IsCcbLoaded) { + IsCcbLoaded = TRUE; + SYSKBC_GetAndStoreCCB(); + } + + *OutTrans = (gUsbData->bCCB & CCB_TRANSLATE_SCAN_CODE_BIT_MASK) != 0? + KBC_KBDTRANS_PCXT : KBC_KBDTRANS_AT; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_Scanner +// +// Description: This routine converts the USB keyboard input data into +// IBM PC format scan code +// +// Input: fpDevInfo Pointer to the device info. structure +// fpBuffer Pointer to the 8byte USB keyboard data +// +// Output: Nothing +// +// Notes: The format of the 8byte USB keyboard data is as follows: +//---------------------------------------------------------------------------- +// Byte Description +//---------------------------------------------------------------------------- +// Byte 0 Contains modifier key bits like SHIFT, CTRL, ALT etc +// Byte 1 Reserved +// Byte 2 - 7 Keycode (1-6) of the keys pressed +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_Scanner ( + DEV_INFO *fpDevInfo, + UINT8 *fpBuffer +) +{ + UINT8 bKeyCode; + UINT8 bValue; + UINT8 bTemp1; + + UINT16 wWorkOffset; + UINT16 wCount; + UINT16 wTemp; + + UINT8 *fptKBInputBuffer; + UINT8 *fptBuffer; + UINT8 *fPointer; + + fptKBInputBuffer = gUsbData->aKBInputBuffer ; + fptBuffer = (UINT8*)fpBuffer; + + // + // Convert the device address (1,2,3 .. 8) into + // device ID bit pattern (001h, 002h, 004h .. 080h) + // + gUsbData->bCurrentDeviceID = (UINT8)(1 << ((fpDevInfo->bDeviceAddress) -1)); + + bTemp1 = 0xE0; + wCount = 0x0; + bValue = (UINT8)(*fptBuffer); + + do { + if(bValue & 0x01) { + *fptKBInputBuffer = bTemp1; // Modifier key pressed. Send appropriate byte to the input buffer + ++fptKBInputBuffer; + } + bValue >>= 1; + ++bTemp1; + } while (bTemp1 <= 0xE7); + + // + // Discard the reserved byte from the USB KB input data stream + // + ++fptBuffer; + ++fptBuffer; + + // + // Process the remaining 6 input bytes + // + wCount = 6; + + do { + if(*fptBuffer) { + // + // Check whether the input is overrun. Overrun condition occurs if more than + // 6 keys are pressed at a same time. In that case, USB KB sends 01h in all + // its 6 key code bytes + // + if(*fptBuffer == 1) { // Keyboard error roll over (overrun) ? +// USB_DEBUG (DEBUG_LEVEL_5, "USBKB_Scanner: Overrun condition occur\n"); + // + // Check the space availability for the overrun code in the + // character buffer + // Overrun code needs 1 byte (0+1) + // + bTemp1 = USBKBC_CheckCharacterBufferFull(0); + if(bTemp1 == 0) { + return; + } + bTemp1 = 0xFF; // Scan code set 2 & 3 overrun code +#if USB_6064_TRAP +// +// The following routine returns overrun code depending upon the scan code +// set chosen. This facility is available only when 60/64h port trapping +// is enabled. Otherwise the scan code set is locked to set 2. +// + bTemp1 = USBTrap_GetOverrunCode(); +#endif + USBKBC_SendToCharacterBuffer(bTemp1); + // + // Invalidate the last key code processed data + // +// gUsbData->bLastUSBKeyCode = 0x00; //(EIP102150-) + return; + } + else { + *fptKBInputBuffer = *fptBuffer; + ++fptKBInputBuffer; + ++fptBuffer; + } + } + else { + ++fptBuffer; + } + --wCount; + } while (wCount); + + *fptKBInputBuffer = 0; // Null terminate the input buffer + ++fptKBInputBuffer; + + // + // Check for break code generation condition + // + wCount = (UINT16)(fptKBInputBuffer - gUsbData->aKBInputBuffer); + fptKBInputBuffer = gUsbData->aKBInputBuffer; + bValue = 0; + // + // wCount = Length of the buffer + // + while(wCount) { + if (*fptKBInputBuffer) + break; + ++fptKBInputBuffer; + --wCount; + } + + if(!wCount) { + // + // No key pressed. Set flags to generate break code + // + gUsbData->bBreakCodeDeviceID |= gUsbData->bCurrentDeviceID; + } + + fptKBInputBuffer = gUsbData->aKBInputBuffer; + //(EIP60380-)> +/* + // + // Check and load typematic rate setting + // + wTemp = (UINT16)(gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_DELAY_BIT_MASK); + wTemp >>= KBC_TYPE_DELAY_BIT_SHIFT; + gUsbData->wRepeatRate = aTypematicRateDelayTable[wTemp]; + gUsbData->wRepeatCounter = 0; +*/ + //<(EIP60380-) +// +// Save the keycode in the local variable +// +UKS_KeyCodeGenerateLoop: + + bKeyCode = *fptKBInputBuffer; + ++fptKBInputBuffer; + + if(bKeyCode) { // Check end of the list + // + // Get scan code buffer size + // + wCount = (UINT16)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); + bTemp1 = 0; + + while(wCount) { + if(bKeyCode == gUsbData->aKBCScanCodeBufferStart[bTemp1]) { + gUsbData->aKBCDeviceIDBufferStart[bTemp1] |= + gUsbData->bCurrentDeviceID; + goto UKS_KeyCodeGenerateLoop; + } + ++bTemp1; + --wCount; + }; + if(bTemp1 >= sizeof (gUsbData->aKBCScanCodeBufferStart)) + goto UKS_CheckBreakCodeGen; + // + // The key code is not in the buffer and also the buffer is not full. So + // generate the make code for the newly pressed key. + // + USBKB_GenerateScanCode(USB_GEN_MAKE_CODE, bKeyCode, 0); +// gUsbData->bLastUSBKeyCode = bKeyCode; //(EIP102150-) + gUsbData->aKBCScanCodeBufferStart[bTemp1] = bKeyCode; + // + // Store the device ID + // + gUsbData->aKBCDeviceIDBufferStart[bTemp1] = gUsbData->bCurrentDeviceID; + // + // Store the shift key status + // + gUsbData->aKBCShiftKeyStatusBufferStart[bTemp1] = gUsbData->bUSBKBShiftKeyStatus; + ++(gUsbData->fpKBCScanCodeBufferPtr); // Update pointer index + //(EIP60380+)> + // + // Check and load typematic rate setting + // + wTemp = (UINT16)(gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_DELAY_BIT_MASK); + wTemp >>= KBC_TYPE_DELAY_BIT_SHIFT; + gUsbData->wRepeatRate = aTypematicRateDelayTable[wTemp]; + gUsbData->wRepeatCounter = 0; + //<(EIP60380+) + goto UKS_KeyCodeGenerateLoop; + } +UKS_CheckBreakCodeGen: + --fptKBInputBuffer; + + fPointer = (UINT8*)(gUsbData->aKBCScanCodeBufferStart); + wTemp = (UINT16)(fptKBInputBuffer - gUsbData->aKBInputBuffer); + +UKS_ProcessNextCharacter: + if(fPointer >= gUsbData->fpKBCScanCodeBufferPtr) + goto UKS_BreakCodeGenCompleted; + + bKeyCode = *fPointer; + ++fPointer; + + fptKBInputBuffer = gUsbData->aKBInputBuffer; + wCount = wTemp; + while(wCount) { + if(bKeyCode == *fptKBInputBuffer) + goto UKS_ProcessNextCharacter; + + ++fptKBInputBuffer; + --wCount; + } + + --fPointer; + wWorkOffset = (UINT16)(fPointer - gUsbData->aKBCScanCodeBufferStart); + + gUsbData->aKBCDeviceIDBufferStart[wWorkOffset] &= ~((UINT8)(gUsbData->bCurrentDeviceID)); + if(gUsbData->aKBCDeviceIDBufferStart[wWorkOffset] ) { + ++fPointer; + goto UKS_ProcessNextCharacter; + } + bValue = gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset]; + gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset] = + gUsbData->bUSBKBShiftKeyStatus; + gUsbData->bUSBKBShiftKeyStatus = bValue; + USBKB_GenerateScanCode(USB_GEN_BREAK_CODE,(UINT8)*fPointer, wWorkOffset); + // + // Restore shift key status + // + bValue = gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset]; + gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset] = gUsbData->bUSBKBShiftKeyStatus; + gUsbData->bUSBKBShiftKeyStatus = bValue; + bValue = *fPointer; + USBKB_DiscardCharacter(&gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset]); + + --(gUsbData->fpKBCScanCodeBufferPtr); + // + // Stop auto repeat + // +// gUsbData->bLastUSBKeyCode = 0; //(EIP102150-) + goto UKS_ProcessNextCharacter; +UKS_BreakCodeGenCompleted: + gUsbData->bBreakCodeDeviceID &= ~((UINT8)(gUsbData->bCurrentDeviceID)); + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_Scanner: End\n"); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_GenerateScanCode +// +// Description: This routine generates the make/break code for th key +// pressed depending on the make/break flag +// +// Input: bCodeGenFlag Flag indicating whether it is a make or +// break code sequence +// bKeyCode USB key code for the key pressed +// wWorkOffset Offset into the buffers which has the +// code we are processing +// +// Output: 0xFFFF -on success , 0 on error +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_GenerateScanCode ( + UINT8 bCodeGenFlag, + UINT8 bKeyCode, + UINT16 wWorkOffset) +{ + UINT8 bMakeCode, + bTemp = 0, + bValue; + UINT16 wScanCode, + wTemp; + UINT8 *fPointer; + UINT8 ScanCodeCount; //(EIP102150+) + UINT16 i=0; //(EIP102150+) + +USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: bKeyCode %x:\n",bKeyCode); + + // + // Set the flag to indicate that make code is generated + // + gUsbData->wUSBKBC_StatusFlag &= ~((UINT16) KBC_MK_BRK_CODE_BIT_MASK); + + // + // Set the approprate flag indicating make or break code sequence + // + if (bCodeGenFlag != USB_GEN_MAKE_CODE) + { + // + // Set the flag to indicate that break code is generated + // + gUsbData->wUSBKBC_StatusFlag |= KBC_MK_BRK_CODE_BIT_MASK; + } + + // + // Save the current USB key code + // + gUsbData->bCurrentUSBKeyCode = bKeyCode; + + // + // Convert the USB key code into scan code (Set 2) + // + bMakeCode = USBKB_ConvertUSBKeyCodeToScanCodeSet2(bKeyCode); + USB_DEBUG (DEBUG_LEVEL_8, "USBKB_GenerateScanCode: bMakeCode %x:\n",bMakeCode); + + // + // Save the make code in the temporary variable + // + gUsbData->bSet2ScanCode = bMakeCode; + // + // Check whether any modifier keys (ALT, CTRL & SHIFT) are pressed + // + wScanCode = USBKB_CheckModifierKeyPress(bMakeCode); + wTemp = (UINT16)(wScanCode >> 8); + + if(wTemp) + { + // + // Check whether it is a make or break code generation + // + if(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK) + { + // + // Generating the break code, so clear the modifier status. + // Check for left/right shift key press + // + if(!(wTemp & (KB_LSHIFT_KEY_BIT_MASK + KB_RSHIFT_KEY_BIT_MASK))) + { + fPointer = gUsbData->fpKBCScanCodeBufferPtr ; + + while(fPointer != (gUsbData->aKBCScanCodeBufferStart)) + { + --fPointer; // Decrement scan code buffer pointer + bTemp = USBKB_ConvertUSBKeyCodeToScanCodeSet2(*fPointer); + if(bTemp == (wScanCode & 0xFF)) + { + break; + } + } + } + + if(bTemp != (wScanCode & 0xFF) || + (wTemp & (KB_LSHIFT_KEY_BIT_MASK + KB_RSHIFT_KEY_BIT_MASK))) + { + wTemp = (UINT16)(~wTemp); + gUsbData->bUSBKBShiftKeyStatus &= wTemp; + gUsbData->aKBCShiftKeyStatusBufferStart[wWorkOffset] &= wTemp; + } + } + else + { + gUsbData->bUSBKBShiftKeyStatus |= wTemp; // Set proper bits + } + } + +#if USB_KBC_EMULATION + bScanNum = USBTrap_GetCurrentScanCodeSetNumber(); + if(bScanNum == 3) + { + USBTrap_ProcessScanCodeSet3(); + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Return 1.\n"); + return; + } +#endif + // + // Check and process pause key + // + if(gUsbData->bSet2ScanCode == PAUSE_KEY ) + { +// +// It is scan code for pause key. No need to auto repeat pause key and +// also pause key doesn't have break key. Check the above two conditions +// and take care of them properly +// + // + // Check whether it is to generate make or break code + // + if(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK) + { + USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateScanCode: Return 2.\n"); + return; + } +// +// It is not a break code check whether it is for auto repeat +// Compare old key code and the current key code +// + //(EIP102150+)> + ScanCodeCount = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); + for (i = 0; i < ScanCodeCount; i++) { + if ((gUsbData->aKBCDeviceIDBufferStart[i] & gUsbData->bCurrentDeviceID) && + (gUsbData->bCurrentUSBKeyCode == gUsbData->aKBCScanCodeBufferStart[i])) { + return; + } + } + //<(EIP102150+) +// +// Pause key can have +// 4 bytes of make code for scan code set 1, if CTRL key is also pressed +// 5 bytes of make code for scan code set 2, if CTRL key is also pressed +// 6 bytes of make code for scan code set 1, if CTRL key is not pressed +// 8 bytes of make code for scan code set 2, if CTRL key is not pressed +// 0 bytes if it is a break code for pause key. +// The above conditions are handled generically using two tables +// pScanCodeLengthTable_4500 & pScanCodeLengthTable_6800. If CTRL key is +// pressed then _4500 table will be used or else _6800 table will be used. +// The logic in the later stage of the code can then choose one entry from +// this table depending on whether it is make or break code and whether +// it is for scan code set 1 or 2. +// + fPointer = aScanCodeLengthTable_4500; // CTRL + PAUSE + if((gUsbData->bUSBKBShiftKeyStatus & + KB_CTRL_KEY_BIT_MASK) == 0) + fPointer = aScanCodeLengthTable_6800; // PAUSE + } + else + if(gUsbData->bSet2ScanCode == PRINT_SCREEN ) + { +/*--- + Print screen key can have + 1 bytes of make code for scan code set 1, if pressed with ALT key + 1 bytes of make code for scan code set 2, if pressed with ALT key + 1 bytes of break code for scan code set 1, if pressed with ALT key + 2 bytes of break code for scan code set 2, if pressed with ALT key + 2 bytes of make code for scan code set 1, if pressed with CTRL+SFT key + 2 bytes of make code for scan code set 2, if pressed with CTRL+SFT key + 2 bytes of break code for scan code set 1, if pressed with CTRL+SFT key + 4 bytes of make code for scan code set 1, if no other key is pressed + 4 bytes of make code for scan code set 2, if no other key is pressed + 4 bytes of break code for scan code set 1, if no other key is pressed + 6 bytes of break code for scan code set 2, if no other key is pressed + The above conditions are handled generically using three tables + pScanCodeLengthTable_1112, pScanCodeLengthTable_2223 + & pScanCodeLengthTable_4446. If ALT key is pressed then _1112 table + will be used. If CTRL key is pressed then _2223 table will be used or + else _4446 table will be used. + The logic in the later stage of the code can then choose one entry from + this table depending on whether it is make or break code and whether + it is for scan code set 1 or 2. +---*/ + if(gUsbData->bUSBKBShiftKeyStatus & + KB_ALT_KEY_BIT_MASK) + fPointer = aScanCodeLengthTable_1112; + else if(gUsbData->bUSBKBShiftKeyStatus & + ( KB_CTRL_KEY_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) + fPointer = aScanCodeLengthTable_2223; + else + fPointer = aScanCodeLengthTable_4446; + + /* fPointer = aScanCodeLengthTable_1112; + if((gUsbData->bUSBKBShiftKeyStatus & KB_ALT_KEY_BIT_MASK) == 0) + { + fPointer = aScanCodeLengthTable_2223; + if((gUsbData->bUSBKBShiftKeyStatus & (KB_NUM_LOCK_BIT_MASK + KB_LSHIFT_KEY_BIT_MASK + KB_RSHIFT_KEY_BIT_MASK)) == 0) + { + fPointer = aScanCodeLengthTable_4446; + bTemp = (UINT8)USBKB_CheckForNumericKeyPadKey(gUsbData->bSet2ScanCode); + if(bTemp) + { +// goto UKGSC_NotANumericKeyPadKey; + } + fPointer = aScanCodeLengthTable_2223; + if(gUsbData->bUSBKBShiftKeyStatus & (KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) + { + fPointer = aScanCodeLengthTable_4446; + if((gUsbData->bUSBKBShiftKeyStatus & KB_NUM_LOCK_BIT_MASK) == 0) + { + if((gUsbData->bUSBKBShiftKeyStatus & KB_NUM_LOCK_BIT_MASK) == 0) + { + fPointer = aScanCodeLengthTable_4545; + } + } + } + } + } */ + } + else + { + wScanCode = USBKB_CheckForNumericKeyPadKey(gUsbData->bSet2ScanCode); + wTemp = (UINT16)(wScanCode & 0xFF); + if(!wTemp) + { + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Extended Key Pressed\n"); + +/*--- + It is a numeric key pad key. It can have + if no key is pressed or (NUMLOCK is ENABLED and SHIFT key is pressed) + 2 bytes of make code for scan code set 1 + 2 bytes of make code for scan code set 2 + 2 bytes of break code for scan code set 1 + 3 bytes of break code for scan code set 2 + if NUMLOCK is ENABLED + 4 bytes of make code for scan code set 1 + 4 bytes of make code for scan code set 2 + 4 bytes of break code for scan code set 1 + 6 bytes of break code for scan code set 2 + if pressed with SHIFT key + 4 bytes of make code for scan code set 1 + 5 bytes of make code for scan code set 2 + 4 bytes of break code for scan code set 1 + 5 bytes of break code for scan code set 2 + The above conditions are handled generically using three tables + pScanCodeLengthTable_2223, pScanCodeLengthTable_4446 + & pScanCodeLengthTable_4545. If no other key is pressed then _2223 table + will be used. If NUMLOCK is enabled then _4446 table will be used or + else _4545 table will be used. + The logic in the later stage of the code can then choose one entry from + this table depending on whether it is make or break code and whether + it is for scan code set 1 or 2. +---*/ + //(EIP27889)> + if( (!(gUsbData->bUSBKBShiftKeyStatus & + ( KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK))) || + ((gUsbData->bUSBKBShiftKeyStatus & + ( KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK)) == + ( KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK)) || + ((gUsbData->bUSBKBShiftKeyStatus & + ( KB_NUM_LOCK_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) == + ( KB_NUM_LOCK_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) ) + fPointer = aScanCodeLengthTable_2223; + //<(EIP27889) + else if(gUsbData->bUSBKBShiftKeyStatus & + KB_NUM_LOCK_BIT_MASK) + { + //(EIP102150+)> + fPointer = aScanCodeLengthTable_4446; + if (!(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK)) { + ScanCodeCount = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); + for (i = 0; i < ScanCodeCount; i++) { + if ((gUsbData->aKBCDeviceIDBufferStart[i] & gUsbData->bCurrentDeviceID) && + (gUsbData->bCurrentUSBKeyCode == gUsbData->aKBCScanCodeBufferStart[i])) { + fPointer = aScanCodeLengthTable_2223; + break; + } + } + } + //<(EIP102150+) + } + else + fPointer = aScanCodeLengthTable_4545; + } + else + { + // UKGSC_NotANumericKeyPadKey +/*--- + The extended keys will have + 2 bytes of make code for scan code set 1 + 2 bytes of make code for scan code set 2 + 2 bytes of break code for scan code set 1 + 3 bytes of break code for scan code set 2 +---*/ + wScanCode = USBKB_CheckForExtendedKey(gUsbData->bSet2ScanCode); + if(!(wScanCode & 0xff)) + fPointer = aScanCodeLengthTable_2223; + else if(gUsbData->bSet2ScanCode == SLASH_KEY) + { +/*--- + The slash key will normally have + 2 bytes of make code for scan code set 1 + 2 bytes of make code for scan code set 2 + 2 bytes of break code for scan code set 1 + 3 bytes of break code for scan code set 2 + But if pressed with slash key it has + 4 bytes of make code for scan code set 1 + 5 bytes of make code for scan code set 2 + 4 bytes of break code for scan code set 1 + 5 bytes of break code for scan code set 2 +---*/ + if(!(gUsbData->bUSBKBShiftKeyStatus & + (KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK))) + fPointer = aScanCodeLengthTable_2223; + else + fPointer = aScanCodeLengthTable_4545; + } + else // UKGSC_NotSlashKey: + /*--- + Regular keys will have + 1 bytes of make code for scan code set 1 + 1 bytes of make code for scan code set 2 + 1 bytes of break code for scan code set 1 + 2 bytes of break code for scan code set 2 + ---*/ + fPointer = aScanCodeLengthTable_1112; + } + } + // + // Find the appropriate scan code length from the table + // bOffset = Offset in the table + // + bValue = 0; // Assume make code for set 1 + + // + // Check whether to generate make or break code + // + if(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK) + { + bValue = 2; + } + // + // Check whether to generate set 1 scan code or set 2 + // + if((gUsbData->bCCB & CCB_TRANSLATE_SCAN_CODE_BIT_MASK) == 0 ) + { + ++bValue; // Update offset (for scan code set 2) + } + + bValue = fPointer[bValue]; + + bValue = USBKBC_CheckCharacterBufferFull(bValue); + + if (!bValue) return; + + // + // We had found out correct scan code length to generate and also we + // verified we have enough space. Now generate the scan code + // + bValue = gUsbData->bSet2ScanCode; + + if(bValue == PAUSE_KEY ) + { + // + // Check whether CTRL key is pressed + // + if(!(gUsbData->bUSBKBShiftKeyStatus & KB_CTRL_KEY_BIT_MASK)) + { + // + // Pause key scan code generation + // + USBKBC_SendToCharacterBuffer(0x0E1); + gUsbData->bSet2ScanCode = 0x14; + USBKB_GenerateType1MakeCode(); + gUsbData->bSet2ScanCode = 0x77; + USBKB_GenerateType1MakeCode(); + USBKBC_SendToCharacterBuffer(0xE1); + gUsbData->bSet2ScanCode = 0x14; + USBKB_GenerateType1BreakCode(); + gUsbData->bSet2ScanCode = 0x77; + USBKB_GenerateType1BreakCode(); + return; + } + else + { + gUsbData->bSet2ScanCode = 0x7E; + USBKB_GenerateType2MakeCode(); + USBKB_GenerateType2BreakCode(); + } + + } + else if(bValue == PRINT_SCREEN ) + { + gUsbData->bSet2ScanCode = 0x7C; // PRNSCRN for scan code set 2 + // + // Check for ALT+PRNSCRN key combination + // + if(!(gUsbData->bUSBKBShiftKeyStatus & KB_ALT_KEY_BIT_MASK )) + { + // + // Check for CTRL or SHIFT+PRNSCRN key combination + // + if(!(gUsbData->bUSBKBShiftKeyStatus & + (KB_CTRL_KEY_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK))) + { + UKGSC_KeyCombination2: +// +// Process PRNSCRN only key processing, NUMLOCK + any numeric key press +// processing at this point. Generate either (E0,12,E0,xx) or +// (E0,F0,xx,E0,F0,12). Where xx bSet2ScanCode +// + // + // Check whether to generate make or break code + // + if(!(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK)) + { + bTemp = gUsbData->bSet2ScanCode; + gUsbData->bSet2ScanCode = 0x12; + USBKB_GenerateType2MakeCode(); + gUsbData->bSet2ScanCode = bTemp; + USBKB_GenerateType2MakeCode(); + USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateScanCode: Return 5.\n"); + return; + + } + else + { + USBKB_GenerateType2BreakCode(); + gUsbData->bSet2ScanCode = 0x12; + USBKB_GenerateType2BreakCode(); + USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateScanCode: Return 6.\n"); + return; + } + } + else + goto UKGSC_KeyCombination1; + + } + else + { + gUsbData->bSet2ScanCode = 0x84; +UKGSC_ProcessRegularKey: +// +// Regular key press make & break code generation (xx or 0F0h, xx) +// Check whether to generate make or break code +// + if((gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK ) == 0) + { + USBKB_GenerateType1MakeCode(); + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Return 7.\n"); + return; + } + USBKB_GenerateType1BreakCode(); + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Return 8.\n"); + return; + } + + } + else + { + // + // Check for numeric key pad keys + // + wScanCode = USBKB_CheckForNumericKeyPadKey(gUsbData->bSet2ScanCode); + wTemp = (UINT16)(wScanCode & 0xFF); + if(wTemp == 0) + { + gUsbData->bSet2ScanCode &= 0x7F; + //(EIP27889)> + if( (!(gUsbData->bUSBKBShiftKeyStatus & + (KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK))) || + ((gUsbData->bUSBKBShiftKeyStatus & + ( KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK)) == + ( KB_NUM_LOCK_BIT_MASK + + KB_LSHIFT_KEY_BIT_MASK)) || + ((gUsbData->bUSBKBShiftKeyStatus & + ( KB_NUM_LOCK_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) == + ( KB_NUM_LOCK_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK)) ) + //<(EIP27889) + goto UKGSC_KeyCombination1; + + if(gUsbData->bUSBKBShiftKeyStatus & KB_NUM_LOCK_BIT_MASK) + //(EIP102150+)> + { + if (!(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK)) { + ScanCodeCount = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); + for (i = 0; i < ScanCodeCount; i++) { + if ((gUsbData->aKBCDeviceIDBufferStart[i] & gUsbData->bCurrentDeviceID) && + (gUsbData->bCurrentUSBKeyCode == gUsbData->aKBCScanCodeBufferStart[i])) { + goto UKGSC_KeyCombination1; + } + } + } + goto UKGSC_KeyCombination2; + } + //<(EIP102150+) +UKGSC_KeyCombination3: +// +// The following code will generate scan code for SHIFT+Numeric key pad +// key combination. It will generate one of the following sequence +// (0E0h, 0F0h, 012H or 059h, 0E0h, xx) or +// (0E0h, 0F0h, xx, 0E0h, 012H or 059h) +// + if((gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK) == 0) + { + // + // Check whether to generate make or break code + // + bTemp = gUsbData->bSet2ScanCode; + if(gUsbData->bUSBKBShiftKeyStatus & KB_LSHIFT_KEY_BIT_MASK) + { + gUsbData->bSet2ScanCode = 0x12; // Save current scan code (xx) + USBKB_GenerateType2BreakCode(); // 0E0h, 0F0h, 012h + } + if(gUsbData->bUSBKBShiftKeyStatus & KB_RSHIFT_KEY_BIT_MASK) + { + gUsbData->bSet2ScanCode = 0x59; + USBKB_GenerateType2BreakCode(); // 0E0h, 0F0h, 059h + } + gUsbData->bSet2ScanCode = bTemp; // Restore current code (xx) + USBKB_GenerateType2MakeCode(); // 0E0h, xx + USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateScanCode: Return 9.\n"); + return; + } + else + { + USBKB_GenerateType2BreakCode(); + if(gUsbData->bUSBKBShiftKeyStatus & KB_RSHIFT_KEY_BIT_MASK) + { + gUsbData->bSet2ScanCode = 0x59; // Save current scan code (xx) + USBKB_GenerateType2MakeCode(); // 0E0h, 59h + } + if(gUsbData->bUSBKBShiftKeyStatus & KB_LSHIFT_KEY_BIT_MASK) + { + gUsbData->bSet2ScanCode = 0x12; // Save current scan code (xx) + USBKB_GenerateType2MakeCode(); // 0E0h, 12h + } + USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateScanCode: Return 10.\n"); + return; + } + } + else + { + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Notnumeric key\n"); + // + // Check and process extended key press + // + bValue = (UINT8)USBKB_CheckForExtendedKey(gUsbData->bSet2ScanCode); + if(bValue == 0) + { + gUsbData->bSet2ScanCode &= 0x7F; +UKGSC_KeyCombination1: +// +// Following code processes the following key combinations: +// Extended key make & break code generation +// CTRL or SHIFT + PRNSCRN key combination +// Numeric key pad key code generation +// One of the following sequence will be generated (0E0h, xx) or +// (0E0h, 0F0h, xx) +// + if(gUsbData->wUSBKBC_StatusFlag & KBC_MK_BRK_CODE_BIT_MASK) + { + USBKB_GenerateType2BreakCode(); + return; + } + USBKB_GenerateType2MakeCode(); + return; + } + else + { + // + // Check and process '/' key + // + if (gUsbData->bSet2ScanCode != SLASH_KEY) + { + USB_DEBUG (DEBUG_LEVEL_7, "USBKB_GenerateScanCode: Regular Key.\n"); + goto UKGSC_ProcessRegularKey; + } + // + // Generate make or break code for '/' key + // + gUsbData->bSet2ScanCode = 0x4A; + if(!(gUsbData->wUSBKBC_StatusFlag & + ( KB_LSHIFT_KEY_BIT_MASK + + KB_RSHIFT_KEY_BIT_MASK))) + goto UKGSC_KeyCombination1; + goto UKGSC_KeyCombination3; + return; + } + } + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_UpdateLEDState +// +// Description: This routine is used to update the LED state between the +// USB & PS/2 keyboard +// +// Input: bFlag Indicates how the LED local variables are adjusted +// +// Output: Nothing +// +// NOTE: This routine is not executed during EFI phase +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_UpdateLEDState (UINT8 bFlag) +{ + UINT8 bLStatus, + bHStatus; + + UINT8* fPtr; + + fPtr = (UINT8*)(UINTN)0x417; + // + // Make sure the password LED status is not changed. If KBC password is + // enabled then the LED state for NUMLOCK should be off, SCROLL-LOCK LED + // state should be on and CAPSLOCK LED state is in dont-care state. + // + bLStatus = gUsbData->bNonUSBKBShiftKeyStatus; + bLStatus &= 0x07 ; // Masking BIT0, BIT1 and BIT2 + if (bLStatus & 1) + { + // + // None of the LED is ON. Make Scroll LOCK LED to be ON + // + bLStatus = 0x04; + } + else + { + bLStatus >>= 1; + } + + gUsbData->bNonUSBKBShiftKeyStatus &= 0xF8; + gUsbData->bNonUSBKBShiftKeyStatus |= bLStatus; + + // + // Check whether password is disabled + // + if (gUsbData->wUSBKBC_StatusFlag & KBC_PASSWORD_FLAG_BIT_MASK) + { + bHStatus = (UINT8)(gUsbData->bUSBKBShiftKeyStatus & 0x70); + bLStatus = (UINT8)((gUsbData->bNonUSBKBShiftKeyStatus & 0x07) << 0x04); + + if(bHStatus == bLStatus) + { + return; + } + gUsbData->bUSBKBShiftKeyStatus &= + ~ (KB_CAPS_LOCK_BIT_MASK + + KB_NUM_LOCK_BIT_MASK + + KB_SCROLL_LOCK_BIT_MASK); + + gUsbData->bUSBKBShiftKeyStatus |= bLStatus; + // + // Check whether SCROLL-LOCK is ON + // + bLStatus = (UINT8)(bLStatus >> 3); + if(bLStatus & 0x08) + { + bLStatus ^= 0x09; + } + // + // ScrollOff + // + USBKB_LEDOn(); + return; + } + + // + // Get the current PS/2 keyboard LED state + // +// USB_DEBUG(DEBUG_LEVEL_5, "USBKB_UpdateLEDState : [0:417] = %x\n", *fPtr); + bLStatus = (UINT8)(((*fPtr) & 0x70) >> 1); + bHStatus = (UINT8)((gUsbData->bUSBKBShiftKeyStatus) & 0x70); + if(bLStatus & 0x08) + bLStatus ^= 0x48; + + if(bLStatus == bHStatus) + return; + + gUsbData->bUSBKBShiftKeyStatus &= + ~ (KB_CAPS_LOCK_BIT_MASK + + KB_NUM_LOCK_BIT_MASK + + KB_SCROLL_LOCK_BIT_MASK); + + gUsbData->bUSBKBShiftKeyStatus |= bLStatus; + USBKB_LEDOn(); + + return; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_LEDOn +// +// Description: This routine updates the keyboard LED status for all the +// USB keyboards present in the sytem +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKB_LEDOn( +) +{ + UINT8 LByte; + UINT8 Count; + DEV_INFO* DevInfo; + EFI_STATUS Status; + // + // Set the LED update progress status + // + gUsbData->bUSBKBC_ExtStatusFlag |= KBCEXT_LED_UPDATE_IN_PROGRESS_BIT; + + // + // Get the current USB LED status + // + USB_DEBUG(DEBUG_LEVEL_7, "USBKB_LEDOn: LedStatus %x\n", gUsbData->bUSBKBShiftKeyStatus); + // + // Form the byte to be transmitted to the USB keyboard + // + LByte = (UINT8)(((gUsbData->bUSBKBShiftKeyStatus) >> 4) & 0x07); + USB_DEBUG(DEBUG_LEVEL_4, "USBKB_LEDOn: LedStatus %x, bLByte %x\n", + gUsbData->bUSBKBShiftKeyStatus, LByte); + + // + // Update LED status in every USB keyboard on the system + // + for(Count = 0; Count < USB_DEV_HID_COUNT; Count++) { + DevInfo = gUsbData->aUSBKBDeviceTable[Count]; + if (DevInfo != NULL) { + Status = UsbDevInfoValidation(DevInfo); + if (EFI_ERROR(Status)) { + return; + } + UsbKbdSetLed(DevInfo, LByte); + } + } + // + // Reset the LED update progress status + // + gUsbData->bUSBKBC_ExtStatusFlag &= ~(KBCEXT_LED_UPDATE_IN_PROGRESS_BIT); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_ConvertSet2CodeToSet1Code +// +// Description: Converts the set 2 scan code to set 1 scan code +// +// Input: bScanCode Set 2 scan code +// +// Output: Set 1 scan code +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKB_ConvertSet2CodeToSet1Code(UINT8 bScanCode) +{ + return USBKB_ConvertScanCodeBetweenCodeSet( + bScanCode, + aStaticSet2ToSet1ScanCode); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_ConvertScanCodeBetweenCodeSet +// +// Description: Converts the set 2 scan code to set 3/1 scan code +// +// Input: bScanCode Set 2 scan code +// bConvTable Pointer to the code set conversion table +// +// Output: Set 1/3 scan code +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKB_ConvertScanCodeBetweenCodeSet( + UINT8 bScanCode, + UINT8 *fPointer +) +{ + UINT8 bValue; + // + // Load the parameter from the stack to register + // + bScanCode = fPointer[bScanCode]; + bScanCode = (UINT8)((bScanCode << 4) | (bScanCode >> 4)); + bValue = (UINT8)((bScanCode & 0x80) >> 7); + bScanCode = (UINT8)(~((bScanCode << 1) | bValue)); + return bScanCode; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_GenerateType1MakeCode +// +// Description: This routine generates the type 1 make code for the byte +// in the variable bSet2ScanCode +// +// Input: bSet2ScanCode - Byte containing the scan code +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_GenerateType1MakeCode() +{ + UINT8 bValue =0; + +// USB_DEBUG (DEBUG_LEVEL_5, "USBKB_GenerateType1MakeCode"); +#if USB_KBC_EMULATION + bValue = USBTrap_GetCurrentScanCodeSetNumber(); +#endif +// Check whether conversion (from set 2 to set 1) is opted + if(bValue != 1) + { + if(((UINT32)(gUsbData->bCCB) & (UINT32)CCB_TRANSLATE_SCAN_CODE_BIT_MASK ) == 0) + { + USBKBC_SendToCharacterBuffer(gUsbData->bSet2ScanCode); + return; + } + } + bValue = USBKB_ConvertSet2CodeToSet1Code(gUsbData->bSet2ScanCode); + + USBKBC_SendToCharacterBuffer(bValue); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_GenerateType1BreakCode +// +// Description: This routine generates the type 1 break code for the byte +// in the variable bSet2ScanCode +// +// Input: bSet2ScanCode - Byte containing the scan code +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_GenerateType1BreakCode() +{ + UINT8 bValue =0; + + USB_DEBUG (DEBUG_LEVEL_8, "USBKB_GenerateType1BreakCode \n"); + +#if USB_KBC_EMULATION + bValue = USBTrap_GetCurrentScanCodeSetNumber(); +#endif + // + // Check whether conversion (from set 2 to set 1) is opted + // + if(bValue != 1) + { + if(((UINT32)(gUsbData->bCCB) & (UINT32)CCB_TRANSLATE_SCAN_CODE_BIT_MASK ) == 0) + { + USBKBC_SendToCharacterBuffer(0xF0); + USBKBC_SendToCharacterBuffer(gUsbData->bSet2ScanCode); + return; + } + } + bValue = USBKB_ConvertSet2CodeToSet1Code(gUsbData->bSet2ScanCode); + bValue |= 0x80; + USBKBC_SendToCharacterBuffer(bValue); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_GenerateType2MakeCode +// +// Description: This routine generates the type 2 make code for the byte +// in the variable bSet2ScanCode +// +// Input: bSet2ScanCode - Byte containing the scan code +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_GenerateType2MakeCode() +{ + USBKBC_SendToCharacterBuffer(0xE0); + USBKB_GenerateType1MakeCode(); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_GenerateType2BreakCode +// +// Description: This routine generates the type 2 break code for the byte +// in the variable bSet2ScanCode +// +// Input: bSet2ScanCode - Byte containing the scan code +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_GenerateType2BreakCode() +{ + USBKBC_SendToCharacterBuffer(0xE0); + USBKB_GenerateType1BreakCode(); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBTrap_GetCurrentScanCodeSetNumber +// +// Description: Returns the current scan code set number +// +// Input: Nothing +// +// Output: Scan code set number (1, 2 or 3) +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBTrap_GetCurrentScanCodeSetNumber() +{ + UINT16 wStatus; + wStatus = (UINT16)(gUsbData->wUSBKBC_StatusFlag & KBC_SCAN_CODE_SET_BIT_MASK); + wStatus >>= KBC_SCAN_CODE_SET_BIT_SHIFT; + + return (UINT8)wStatus; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBTrap_GetOverrunCode +// +// Description: Returns the overrun code depending on the current +// scan code set +// +// Input: Nothing +// +// Output: Overrun code +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBTrap_GetOverrunCode() +{ + return 0xFF; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_DiscardCharacter +// +// Description: This routine discards the top character in the scan +// code buffer, keyboard status flag buffer and device ID +// buffer +// +// Input: fPointer Points to the keyboard status flag buffer +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKB_DiscardCharacter (UINT8* fPointer) +{ + UINT8 bCount; + UINT32 dCount = 0; + UINT8* fPtrEnd; + + fPtrEnd = gUsbData->aKBCShiftKeyStatusBufferStart + + sizeof (gUsbData->aKBCShiftKeyStatusBufferStart); + bCount = (UINT8)(fPtrEnd - (fPointer + 1)); + + do + { + fPointer[dCount] = fPointer[dCount+1]; + ++dCount; + --bCount; + } while(bCount); + + // + // Calculate offset + // + dCount = (UINT32)(fPointer - + (UINT8*)gUsbData->aKBCShiftKeyStatusBufferStart); + bCount = (UINT8)(fPtrEnd - (fPointer + 1)); + do + { + gUsbData->aKBCDeviceIDBufferStart[dCount] = + gUsbData->aKBCDeviceIDBufferStart[dCount+1]; + ++dCount; + --bCount; + } while(bCount); + + dCount = (UINT32)(fPointer - + (UINT8*)gUsbData->aKBCShiftKeyStatusBufferStart); + // + // Update device ID buf + // + bCount = (UINT8)(fPtrEnd - (fPointer + 1)); + do + { + gUsbData->aKBCScanCodeBufferStart[dCount] = + gUsbData->aKBCScanCodeBufferStart[dCount+1]; + ++dCount; + --bCount; + } while(bCount); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_CheckForExtendedKey +// +// Description: Checks whether the key pressed is a extended key +// +// Input: bScanCode Set 2 scan code for the key pressed +// +// Output: 0 Key pressed matches the numeric key pad key +// <> 0 It is not a numeric key pad key +// Set 3 scan code for the key pressed +// (if set 3 is chosen) +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBKB_CheckForExtendedKey (UINT8 bScanCode) +{ + UINT8 bCount, + bFound = FALSE; + UINT16 wRetValue = 0xff; + + bCount = 0; + while(bCount < sizeof (aStaticExtendedKeyScan2Table)) + { + if(aStaticExtendedKeyScan2Table[bCount] == bScanCode) + { + bFound = TRUE; + break; + } + ++bCount; + } + if(bFound == TRUE) + { +#if USB_KBC_EMULATION + wRetValue = (UINT16)aStaticExtendedKeyScan3Table[bCount]; + wRetValue = wRetValue << 8; +#endif + wRetValue &= 0xff00; + } + + return(wRetValue); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_CheckForNumericKeyPadKey +// +// Description: Checks whether the key pressed is from numeric key pad +// +// Input: bScanCode Set 2 scan code for the key pressed +// +// Output: 0 Key pressed matches the numeric key pad key +// <> 0 It is not a numeric key pad key +// Set 3 scan code for the key pressed +// (if set 3 is chosen) +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBKB_CheckForNumericKeyPadKey (UINT8 bScanCode) +{ + UINT8 bCount, + bFound = FALSE; + UINT16 wRetValue = 0xff; + + bCount = 0; + while(bCount < sizeof (aStaticKeyPadScan2Table)) + { + if(aStaticKeyPadScan2Table[bCount] == bScanCode) + { + bFound = TRUE; + break; + } + ++bCount; + } + if(bFound == TRUE) + { +#if USB_KBC_EMULATION + wRetValue = aStaticKeyPadScan3Table[bCount]; + wRetValue = wRetValue SHL 8; +#endif + wRetValue &= 0xff00; + } + return(wRetValue); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_CheckCharacterBufferFull +// +// Description: This routine checks whether the character buffer can hold +// 'N'+1 character +// +// Input: bCount Space needed in the buffer (in characters) +// +// Output: 0 If buffer is full +// <> 0 If buffer is not full +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKBC_CheckCharacterBufferFull (UINT8 bCount) +{ + UINT8 *dHead, *dTail, *dStart, *dEnd; + + dHead = gUsbData->fpKBCCharacterBufferHead; + dTail = gUsbData->fpKBCCharacterBufferTail; + dStart = gUsbData->aKBCCharacterBufferStart; + dEnd = dHead + sizeof (gUsbData->aKBCCharacterBufferStart); + ++bCount; + do { + ++dHead; + if(dHead == dEnd) dHead = dStart; + if(dHead == dTail) return 0; + --bCount; + } while(bCount); + + return 0xFF; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_GetFromCharacterBuffer +// +// Description: This routine gets a character from the character buffer. +// Character buffer pointers are also updated +// +// Input: Nothing +// +// Output: Character taken from the character buffer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKBC_GetFromCharacterBuffer() +{ + UINT8 bValue; + UINT8 *fPtr, *fPtrEnd; + + fPtrEnd = gUsbData->aKBCCharacterBufferStart + + sizeof (gUsbData->aKBCCharacterBufferStart); + fPtr = gUsbData->fpKBCCharacterBufferTail; + bValue = *fPtr; + ++fPtr; + // + // Check for buffer end condition + // + if(fPtr == fPtrEnd) + fPtr = gUsbData->aKBCCharacterBufferStart; + gUsbData->fpKBCCharacterBufferTail = fPtr; + + return bValue; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_SendToCharacterBuffer +// +// Description: This routine puts a character into the character buffer. +// Character buffer pointers are also updated +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKBC_SendToCharacterBuffer (UINT8 bChar) +{ + UINT8 *fPointer, *fPtrEnd; + + fPtrEnd = gUsbData->aKBCCharacterBufferStart + + sizeof (gUsbData->aKBCCharacterBufferStart); + + fPointer = gUsbData->fpKBCCharacterBufferHead; + *fPointer = bChar; + ++fPointer; + + if(fPointer == fPtrEnd) { + fPointer = gUsbData->aKBCCharacterBufferStart; + } + + gUsbData->fpKBCCharacterBufferHead = fPointer; + + USBKeyRepeat(NULL, 2); // Enable Key repeat +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_ConvertUSBKeyCodeToScanCodeSet2 +// +// Description: This routine converts the USB keycode into scan code set +// 2 scan code. Conversion is accomplished using a static table. +// +// Input: bKeyCode USB Key code +// +// Output: Set 2 scan code for the key +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKB_ConvertUSBKeyCodeToScanCodeSet2 (UINT8 bKeyCode) +{ + return aUSBKeyCodeToScanCodeSet2Table[bKeyCode]; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_CheckModifierKeyPress +// +// Description: This routine checks whether any of the modifier keys, like +// shift, control or alternate keys, are pressed +// +// Input: bScanCode Scan code set 2 scan code +// +// Output: 0 None of the modifier keys are pressed +// Modifier key is pressed +// High Byte, Low Byte = Modifier key identifier +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBKB_CheckModifierKeyPress (UINT8 bScanCode) +{ + UINT8 bLByte = 0, + bHByte = 0; + UINT16 wValue; + // + // Check for left shift key status + // + if(bScanCode == LEFT_SHIFT) + bHByte = KB_LSHIFT_KEY_BIT_MASK; + // + // Check for right shift key status + // + if (bScanCode == RIGHT_SHIFT) + bHByte = KB_RSHIFT_KEY_BIT_MASK; + // + // Check for left control key status + // + if (bScanCode == LEFT_CTRL) + { + bHByte = KB_CTRL_KEY_BIT_MASK; + bLByte = RIGHT_CTRL; + } + // + // Check for left control key status + // + if (bScanCode == RIGHT_CTRL) + { + bHByte = KB_CTRL_KEY_BIT_MASK; + bLByte = LEFT_CTRL; + } + // + // Check for left alternate key status + // + if (bScanCode == LEFT_ALT) + { + bHByte = KB_ALT_KEY_BIT_MASK; + bLByte = RIGHT_ALT; + } + // + // Check for left alternate key status + // + if (bScanCode == RIGHT_ALT) + { + bHByte = KB_ALT_KEY_BIT_MASK; + bLByte = LEFT_ALT; + } + wValue = (UINT16)(bLByte + (bHByte << 8)); + return(wValue); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_GetAndStoreCCB +// +// Description: This routine will read the CCB from the keyboard controller +// and store it in a local variable +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKBC_GetAndStoreCCB() +{ + KBC_KBDTRANSLATION tr; + + ASSERT(gKbdInput); + // + // CCB is internal buisness of KBC relted code + // USB code only need to know about translation type + // + VERIFY_EFI_ERROR( + gKbdInput->GetTranslation(gKbdInput,&tr)); + gUsbData->bCCB = tr == KBC_KBDTRANS_PCXT? 0x40 : 0; + return ; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_CheckAutoRepeat +// +// Description: This routine will check the repeat counter and repeat rate +// and perform the auto repeat appropriately +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKBC_CheckAutoRepeat() +{ + //(EIP102150+)> + UINT8 ScanCodeCount = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); + UINT8 i; + + if(ScanCodeCount){ + USB_DEBUG (DEBUG_LEVEL_7, "USBKBC_CheckAutoRepeat: \n"); + + // + // Update repeat counter + // + gUsbData->wRepeatCounter++; + + if (gUsbData->wRepeatCounter >= gUsbData->wRepeatRate) { + + // + // Repeat rate reached. Reload repeat delay counter + // + gUsbData->wRepeatRate = aTypematicRateDelayTable[ + (gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_RATE_BIT_MASK) >> + KBC_TYPE_RATE_BIT_SHIFT]; + gUsbData->wRepeatCounter = 0; + + // + // Check for scan code in the buffer + // + if(gUsbData->fpKBCCharacterBufferHead == + gUsbData->fpKBCCharacterBufferTail) + { + // + // Buffer has character to process. + // + for(i = 0; i < ScanCodeCount; i++) + { + USBKB_GenerateScanCode(USB_GEN_MAKE_CODE, + gUsbData->aKBCScanCodeBufferStart[i], 0); + } + } + } + } + //<(EIP102150+) +} + + +VOID +SysKbcAutoRepeat( + HC_STRUC* HcStruc +) +{ + UINT8 BreakCodeDeviceId; + UINT8 DevAddr; + UINT8 *KbInputBuffer; + DEV_INFO *DevInfo; + PS2MouseData MouseData; + EFI_STATUS EfiStatus; + UINT8 DummyData; + static UINT8 Buffer[64]; + UINT32 Count = 1; + + USBKB_UpdateLEDState(0x0); + + BreakCodeDeviceId = gUsbData->bBreakCodeDeviceID; + + USB_DEBUG (DEBUG_LEVEL_8, "USBKBDpih: BreakCodeID %x \n", BreakCodeDeviceId); + + if (BreakCodeDeviceId) { + DevAddr = 1; + + while (!(BreakCodeDeviceId & 1)) { + BreakCodeDeviceId >>= 1; + ++DevAddr; + } + DevInfo = USB_GetDeviceInfoStruc( + USB_SRCH_DEV_ADDR, + (DEV_INFO*)0, + DevAddr, + HcStruc); + ASSERT(DevInfo != NULL); + if (DevInfo == NULL) { + return; + } + + KbInputBuffer = gUsbData->aKBInputBuffer; + *KbInputBuffer = 0; + ++KbInputBuffer; + *KbInputBuffer = 0; + --KbInputBuffer; + + USBKB_Scanner(DevInfo, KbInputBuffer); + } + + USBKBC_CheckAutoRepeat(); + if (gUsbData->fpKBCCharacterBufferTail != gUsbData->fpKBCCharacterBufferHead) { + // Get the Data from aKBInputBuffer Local Buffer + *Buffer = *gUsbData->fpKBCCharacterBufferTail; + //Optimization: Enable the code below; it must be more efficient + // UINT8 *p; + // for( p = Buffer; gUsbData->fpKBCCharacterBufferTail != gUsbData->fpKBCCharacterBufferHead; + // ++Count) + // *p++ = USBKBC_GetFromCharacterBuffer(); + + if (gKbdInput->Send == SYSKBC_KbdInput_Send) { + + // USB driver Emulation function already working on the aKBInputBuffer buffer + // So we don't need to remove the data from aKBInputBuffer incase if data send + // Successfully + EfiStatus = gKbdInput->Send(gKbdInput, Buffer, Count); + } else { + // Other Emulation drivers doesn't use the aKBInputBuffer. + // So remove the data from aKBInputBuffer if the data sent successfully. + EfiStatus = gKbdInput->Send(gKbdInput, Buffer, Count); + + if (!EFI_ERROR(EfiStatus)) { + *Buffer = USBKBC_GetFromCharacterBuffer(); + } + } + + USBKBC_GetAndStoreCCB(); + USBKeyRepeat(NULL, 2); + } else if (gUsbData->fpMouseInputBufferHeadPtr != + gUsbData->fpMouseInputBufferTailPtr) { + + // Get the Mouse data Packet from aMouseInputBuffer buffer + MouseData.flags = *gUsbData->fpMouseInputBufferTailPtr; + MouseData.x = *(gUsbData->fpMouseInputBufferTailPtr + 1); + MouseData.y = *(gUsbData->fpMouseInputBufferTailPtr + 2); + + if (gMsInput->Send == SYSKBC_MouseInput_Send) { + + // USB driver Emulation function already working on the aMouseInputBuffer buffer + // So we don't need to remove the data from aMouseInputBuffer incase if data send + // Successfully + EfiStatus = gMsInput->Send(gMsInput, &MouseData); + } else { + // Other Emulation drivers doesn't use the aMouseInputBuffer. + // So remove the data from aMouseInputBuffer if the data sent successfully. + EfiStatus = gMsInput->Send(gMsInput, &MouseData); + if (!EFI_ERROR(EfiStatus)) { + DummyData = USBMouse_GetFromMouseBuffer(); + DummyData = USBMouse_GetFromMouseBuffer(); + DummyData = USBMouse_GetFromMouseBuffer(); + } + } + + USBKeyRepeat(NULL, 2); // Enable Key repeat + + } else if(gUsbData->fpKBCScanCodeBufferPtr != gUsbData->aKBCScanCodeBufferStart ) { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } else { + USBKeyRepeat(NULL, 1); // Disable Key repeat + } +} + +static EFI_EMUL6064KBDINPUT_PROTOCOL theKbdInput = +{ +SYSKBC_KbdInput_Send, +SYSKBC_GetTranslation, +SYSKBC_UpdateLEDState +}; + +EFI_EMUL6064MSINPUT_PROTOCOL theMsInput = +{ + SYSKBC_MouseInput_Send +}; + +void InitSysKbc( + EFI_EMUL6064KBDINPUT_PROTOCOL** ppKbd, + EFI_EMUL6064MSINPUT_PROTOCOL** ppMouse ) +{ + *ppKbd = &theKbdInput; + *ppMouse = &theMsInput; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/sysnokbc.c b/Core/EM/usb/rt/sysnokbc.c new file mode 100644 index 0000000..d38812f --- /dev/null +++ b/Core/EM/usb/rt/sysnokbc.c @@ -0,0 +1,1146 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/sysnokbc.c 14 5/06/14 5:14a Ryanchou $ +// +// $Revision: 14 $ +// +// $Date: 5/06/14 5:14a $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/sysnokbc.c $ +// +// 14 5/06/14 5:14a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 13 4/29/14 7:54p Wilsonlee +// [TAG] EIP163828 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The mouses stop more than 4 seconds during TP 0xB4 when +// power on several times. +// [RootCause] The device sometime doesn't respond the set report +// command. +// [Solution] Change the timeout of set report command to 100 ms. +// [Files] syskbc.c, sysnokbc.c, usbhid.c, amiusb.h +// +// 12 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 +// +// 11 2/21/12 4:53a Rameshr +// [TAG] EIP67630 +// [Category] Improvement +// [Description] With the SCAN code matching , attribute also needs to +// be matched in AMIUSB driver for the Keymon support. +// [Files] sysnokbc.c +// +// 10 9/23/11 12:19a Rajeshms +// [TAG] EIP69580 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] NumLock is not working fine when pressed, while booting to +// windows XP in a KBC absent platform. +// [RootCause] The USB INT9 updates the LED state in BDA by checking +// 0x497 location which is not updated correctly in case of OS (which +// doesn't not use INT16h) +// [Solution] The LED state is compared with 0x417 location and if +// changed, 0x497 location is also updated and LED is glown based on the +// state. +// [Files] sysnokbc.c +// +// 9 4/30/10 3:39p Fredericko +// Fixed EIP:38028:USB AutoKeyRepeat is not working properly +// +// 8 2/01/10 1:29p Olegi +// EIP32867: added checking for the validity of KeyMon pointer. +// +// 7 9/24/08 10:21a Rameshraju +// KeymonFilter support added +// +// 6 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 4 10/26/07 11:10a Olegi +// Added Europe1 and Europe2 keys. +// +// 3 9/27/07 5:04p Olegi +// +// 2 9/27/07 4:12p Olegi +// +// 1 3/20/07 12:22p Olegi +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: SysNoKbc.c +// +// Description: AMI USB keyboard driver data conversion and presentation +// routines, KBC is not present +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" + +#if KEYMONFILTER_SUPPORT +#include <protocol\KeyMonPlatform.h> +#define KEYMON_MAP 0x108 +#define KEYMON_DATA_ADDRESS 0x10C +#endif + +VOID UpdateKeyMon(UINT8 KeyCode); + +extern LEGACY_USB_KEYBOARD mLegacyKeyboard; +extern USB_GLOBAL_DATA *gUsbData; +extern UINT8 aTypematicRateDelayTable[]; + +VOID UpdateLEDs(); + +// +// USB scan codes and the corresponding data that will be used during key translation +// +/* +0, //0 00 Reserved (no event indicated) +0, //1 01 Keyboard ErrorRollOver +0, //2 02 Keyboard POSTFail +0, //3 03 Keyboard ErrorUndefined +*/ +UINT8 aLetters[] = { + 0x1e, //4 04 Keyboard a and A + 0x30, //5 05 Keyboard b and B + 0x2e, //6 06 Keyboard c and C + 0x20, //7 07 Keyboard d and D + 0x12, //8 08 Keyboard e and E + 0x21, //9 09 Keyboard f and F + 0x22, //10 0A Keyboard g and G + 0x23, //11 0B Keyboard h and H + 0x17, //12 0C Keyboard i and I + 0x24, //13 0D Keyboard j and J + 0x25, //14 0E Keyboard k and K + 0x26, //15 0F Keyboard l and L + 0x32, //16 10 Keyboard m and M + 0x31, //17 11 Keyboard n and N + 0x18, //18 12 Keyboard o and O + 0x19, //19 13 Keyboard p and P + 0x10, //20 14 Keyboard q and Q + 0x13, //21 15 Keyboard r and R + 0x1f, //22 16 Keyboard s and S + 0x14, //23 17 Keyboard t and T + 0x16, //24 18 Keyboard u and U + 0x2f, //25 19 Keyboard v and V + 0x11, //26 1A Keyboard w and W + 0x2d, //27 1B Keyboard x and X + 0x15, //28 1C Keyboard y and Y + 0x2c, //29 1D Keyboard z and Z +}; + +struct TNumbers { + UINT8 NormalNumber; + UINT8 ShiftedNumber; +} aNumbers[] = { + 0x31, 0x21, //30 1E Keyboard 1 and ! + 0x32, 0x40, //31 1F Keyboard 2 and @ + 0x33, 0x23, //32 20 Keyboard 3 and # + 0x34, 0x24, //33 21 Keyboard 4 and $ + 0x35, 0x25, //34 22 Keyboard 5 and % + 0x36, 0x5e, //35 23 Keyboard 6 and ^ + 0x37, 0x26, //36 24 Keyboard 7 and & + 0x38, 0x2a, //37 25 Keyboard 8 and * + 0x39, 0x28, //38 26 Keyboard 9 and ( + 0x30, 0x29, //39 27 Keyboard 0 and ) +}; + +struct TBasicKeys { + UINT8 BasicKeyScancode; + UINT8 BasicKeyAsciiNormal; + UINT8 BasicKeyAsciiShifted; + UINT16 BasicKeyCodeCtrl; + UINT8 BasicKeyAsciiAlt; +} aBasicKey[] = { + 0x1c, 0x0d, 0x0d, 0x1c0a, 0xa6, //40 28 Keyboard Return (ENTER) + 0x01, 0x1b, 0x1b, 0x011b, 0x01, //41 29 Keyboard ESCAPE + 0x0e, 0x08, 0x08, 0x0e7f, 0x0e, //42 2A Keyboard DELETE (Backspace) + 0x0f, 0x09, 0x00, 0x9400, 0xa5, //43 2B Keyboard Tab + 0x00, 0x00, 0x00, 0x0000, 0x00, //44 2C Keyboard Spacebar, processed separately + 0x0c, 0x2d, 0x5f, 0x0c1f, 0x82, //45 2D Keyboard - and (underscore + 0x0d, 0x3d, 0x2b, 0x0000, 0x83, //46 2E Keyboard = and + + 0x1a, 0x5b, 0x7b, 0x1a1b, 0x1a, //47 2F Keyboard [ and { + 0x1b, 0x5d, 0x7d, 0x1b1d, 0x1b, //48 30 Keyboard ] and } + 0x2b, 0x5c, 0x7c, 0x2b1c, 0x26, //49 31 Keyboard \ and | + 0x2b, 0x5c, 0x7c, 0x2b1c, 0x26, //50 32 Keyboard Non-US # and ~ + 0x27, 0x3b, 0x3a, 0x0000, 0x27, //51 33 Keyboard ; and : + 0x28, 0x27, 0x22, 0x0000, 0x00, //52 34 Keyboard ` and " + 0x29, 0x60, 0x7e, 0x0000, 0x00, //53 35 Keyboard Grave Accent and Tilde + 0x33, 0x2c, 0x3c, 0x0000, 0x00, //54 36 Keyboard, and < + 0x34, 0x2e, 0x3e, 0x0000, 0x00, //55 37 Keyboard . and > + 0x35, 0x2f, 0x3f, 0x0000, 0x00, //56 38 Keyboard / and ? +}; +/* +//0x0000, //57 39 Keyboard Caps Lock +*/ +UINT8 aF1_10Key[] = { + 0x3b, //58 3A Keyboard F1 + 0x3c, //59 3B Keyboard F2 + 0x3d, //60 3C Keyboard F3 + 0x3e, //61 3D Keyboard F4 + 0x3f, //62 3E Keyboard F5 + 0x40, //63 3F Keyboard F6 + 0x41, //64 40 Keyboard F7 + 0x42, //65 41 Keyboard F8 + 0x43, //66 42 Keyboard F9 + 0x44, //67 43 Keyboard F10 +}; +/* +0x85, //68 44 Keyboard F11 +0x86, //69 45 Keyboard F12 + + +0x00, //70 46 Keyboard PrintScreen +0x00, //71 47 Keyboard Scroll Lock +0x00, //72 48 Keyboard Pause +*/ +/* apparently the PS/2's int9 implementation returns the same +scan/ascii for extended keys, keeping the table below for +reference only. +struct TExtKeys { + UINT8 NormalShiftedScanCode; + UINT8 ShiftedAsciiCode; + UINT8 wCtrlScanCode; + UINT8 wAltScanCode; +} aExtKeys[] = { + 0x52, 0x30, 0x92, 0xA2, //73 49 Keyboard Insert + 0x47, 0x37, 0x77, 0x97, //74 4A Keyboard Home + 0x49, 0x39, 0x84, 0x99, //75 4B Keyboard PageUp + 0x53, 0x2e, 0x93, 0xA3, //76 4C Keyboard Delete Forward + 0x4f, 0x31, 0x75, 0x9F, //77 4D Keyboard End + 0x51, 0x33, 0x76, 0xA1, //78 4E Keyboard PageDown + 0x4d, 0x36, 0x74, 0x9D, //79 4F Keyboard RightArrow + 0x4b, 0x34, 0x73, 0x9B, //80 50 Keyboard LeftArrow + 0x50, 0x32, 0x91, 0xA0, //81 51 Keyboard DownArrow + 0x48, 0x38, 0x8D, 0x98, //82 52 Keyboard UpArrow +}; +*/ +UINT8 aExtKeys[] = {0x52,0x47,0x49,0x53,0x4f,0x51,0x4d,0x4b,0x50,0x48,}; +/* +0x, //83 53 Keypad Num Lock and Clear +*/ + +UINT16 aKeypad1[] = { + 0x352f, //84 54 Keypad / + 0x372a, //85 55 Keypad * + 0x4a2d, //86 56 Keypad - + 0x4e2b, //87 57 Keypad + + 0x1c0d, //88 58 Keypad ENTER +}; + +struct TKeypadNumbers { + UINT8 NormalScanCode; // ascii code is 0 + UINT8 ShiftedAsciiCode; // altered by both NumLock and Shift + UINT8 CtrlScanCode; // ascii code is 0 + UINT8 AltScanCode; // ascii code is 0 +} aKeypad2[] = { + 0x4f, 0x31, 0x75, 0x9f, //89 59 Keypad 1 and End + 0x50, 0x32, 0x91, 0xa0, //90 5A Keypad 2 and Down Arrow + 0x51, 0x33, 0x76, 0xa1, //91 5B Keypad 3 and PageDn + 0x4b, 0x34, 0x73, 0x9b, //92 5C Keypad 4 and Left Arrow + 0x4c, 0x35, 0x8f, 0x00, //93 5D Keypad 5 (special, no code if lowercase) + 0x4d, 0x36, 0x74, 0x9d, //94 5E Keypad 6 and Right Arrow + 0x47, 0x37, 0x77, 0x97, //95 5F Keypad 7 and Home + 0x48, 0x38, 0x8d, 0x98, //96 60 Keypad 8 and Up Arrow + 0x49, 0x39, 0x84, 0x99, //97 61 Keypad 9 and PageUp + 0x52, 0x30, 0x92, 0xa2, //98 62 Keypad 0 and Insert + 0x53, 0x2e, 0x93, 0xa3, //99 63 Keypad . and Delete +}; +/* +0x, //100 64 Keyboard Non-US \ and | +0x, //101 65 Keyboard Application +*/ + +typedef UINT16 (*GETCODE_FUNC) (UINT8 usbcode); + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_Letter +// +// Description: Returns the scan/ascii code for letter charachters, USB +// code from 4 to 1D. +// Keys from 'A' to 'Z' are interpreted using the following logic: +// 1) first_keycode is 04 +// 2) last_keycode is 1D +// 3) scan_code = letters[key-first_keycode].scancode +// 4) ascii_code (normal) = 0x61+(key-first_keycode) +// 5) ascii_code (shifted) = 0x41+(key-first_keycode) +// 6) ascii_code (w/Ctrl) = key-first_keycode+1 +// +// Input: Key index (key code - 4) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_Letter(UINT8 usbcode) +{ + UINT8 scan_code = aLetters[usbcode]; + UINT8 ascii_code = 0x61 + usbcode; + BOOLEAN changecase = mLegacyKeyboard.KeyModifierState.CapsLock + || mLegacyKeyboard.KeyModifierState.Shift; + + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(scan_code); + + if (mLegacyKeyboard.KeyModifierState.CapsLock + && mLegacyKeyboard.KeyModifierState.Shift) changecase = FALSE; + if (changecase) ascii_code -= 0x20; + if (mLegacyKeyboard.KeyModifierState.Ctrl) ascii_code = usbcode+1; + return (UINT16)(scan_code << 8) + ascii_code; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_Number +// +// Description: Returns the scan/ascii code for numbers, USB code from 1E to 27. +// Keys from '1' to '0' are interpreted using the following logic: +// 1) first_keycode is 1E +// 2) last_keycode is 27 +// 3) scan_code = key-first_keycode + 2 +// 4) ascii_code (normal) = aNumbers[key-first_keycode].NormalNumber +// 5) ascii_code (shifted) = aNumbers[key-first_keycode].ShiftedNumber +// 6) scan_code (w/Alt) = key-first_keycode + 0x78 +// +// Input: Key index (key code - 1E) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_Number(UINT8 usbcode) +{ + UINT8 scan_code = usbcode+2; + UINT8 ascii_code = aNumbers[usbcode].NormalNumber; + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(scan_code); + if (mLegacyKeyboard.KeyModifierState.Shift) { + ascii_code = aNumbers[usbcode].ShiftedNumber; + } + if (mLegacyKeyboard.KeyModifierState.Ctrl) { + ascii_code = 0; scan_code = 0; + if (usbcode == 1) { // "2" + scan_code = 3; + } + if (usbcode == 5) { // "6" + scan_code = 7; + ascii_code = 0x1E; + } + } + if (mLegacyKeyboard.KeyModifierState.Alt) { + scan_code = usbcode + 0x78; + } + + return (UINT16)(scan_code << 8) + ascii_code; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_BasicKey +// +// Description: Returns the scan/ascii code for "basic keys" - not letters, not +// numbers (Enter, Escape, '[', '/', etc.); USB code from 28 to 38. +// +// Input: Key index (key code - 28) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_BasicKey(UINT8 usbcode) +{ + UINT8 scan_code = aBasicKey[usbcode].BasicKeyScancode; + UINT8 ascii_code = (mLegacyKeyboard.KeyModifierState.Shift)? + aBasicKey[usbcode].BasicKeyAsciiShifted : aBasicKey[usbcode].BasicKeyAsciiNormal; + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(scan_code); + if (mLegacyKeyboard.KeyModifierState.Ctrl) return aBasicKey[usbcode].BasicKeyCodeCtrl; + if (mLegacyKeyboard.KeyModifierState.Alt) { + ascii_code = aBasicKey[usbcode].BasicKeyAsciiAlt; + if (ascii_code == 0) scan_code = 0; + } + + return (UINT16)(scan_code << 8) + ascii_code; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_F1_10Key +// +// Description: Returns the scan/ascii code for functional keys F1..F10; +// USB code from 3A to 43. +// +// Input: Key index (key code - 3A) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_F1_10Key(UINT8 usbcode) +{ + UINT8 code = aF1_10Key[usbcode]; + // + // ASCII codes are 0s + // Scan codes: + // shifted = normal+0x19 + // w/Ctrl = normal+0x23 + // w/Alt = normal+0x2d + // + + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(code); + + if (mLegacyKeyboard.KeyModifierState.Shift) return (UINT16)(code+0x19) << 8; + if (mLegacyKeyboard.KeyModifierState.Ctrl) return (UINT16)(code+0x23) << 8; + if (mLegacyKeyboard.KeyModifierState.Alt) return (UINT16)(code+0x2d) << 8; + + return (UINT16)code << 8; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_F11F12Key +// +// Description: Returns the scan/ascii code for functional keys F11 and F12; +// USB code 44 and 45. +// +// Input: Key index (key code - 44) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_F11F12Key(UINT8 usbcode) +{ + UINT16 aF11_F12[2] = {0x8500, 0x8600}; + // + // ASCII codes are 0s + // Scan codes: Normal Shifted w/Ctrl w/Alt + // F11 0x85 0x87 0x89 0x8B + // F12 0x86 0x88 0x8A 0x8C + // + + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon((UINT8)(aF11_F12[usbcode] >> 8)); + + if (mLegacyKeyboard.KeyModifierState.Shift) return aF11_F12[usbcode]+0x200; + if (mLegacyKeyboard.KeyModifierState.Ctrl) return aF11_F12[usbcode]+0x400; + if (mLegacyKeyboard.KeyModifierState.Alt) return aF11_F12[usbcode]+0x600; + + return aF11_F12[usbcode]; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_ExtKey +// +// Description: Returns the scan/ascii code for extended keys such as Home, +// End, arrows, PgUp/Dn; USB code from 49 to 52. +// +// Input: Key index (key code - 49) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_ExtKey(UINT8 usbcode) +{ +/* UINT8 scan_code = aExtKeys[usbcode].NormalShiftedScanCode; + UINT8 ascii_code = 0; + + if (mLegacyKeyboard.KeyModifierState.Shift) { + ascii_code = aExtKeys[usbcode].ShiftedAsciiCode; + } else { + if (mLegacyKeyboard.KeyModifierState.Ctrl) { + scan_code = aExtKeys[usbcode].wCtrlScanCode; + } else { + if (mLegacyKeyboard.KeyModifierState.Alt) { + scan_code = aExtKeys[usbcode].wAltScanCode; + } + } + } + return ((UINT16)scan_code << 8) + ascii_code;*/ + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(aExtKeys[usbcode]); + + return (UINT16)aExtKeys[usbcode]<<8; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_Keypad1 +// +// Description: Returns the scan/ascii code for non-numeric part of the keypad, +// such as '/', '*', etc.; USB code from 54 to 58. +// +// Input: Key index (key code - 54) +// +// Output: scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_Keypad1(UINT8 usbcode) +{ + if (mLegacyKeyboard.KeyModifierState.Ctrl || mLegacyKeyboard.KeyModifierState.Alt) { + return 0; + } + + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon((UINT8)(aKeypad1[usbcode] >> 8)); + + return aKeypad1[usbcode]; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_Keypad2 +// +// Description: Returns the scan/ascii code for numeric part of the keypad; +// USB code from 59 to 63. +// +// Input: Key index (key code - 59) +// +// Output: scan code in upper byte, ascii code in lower byte +// +// Notes: The ascii_code is altered depending on the combination of +// Shift and NumLock. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_Keypad2(UINT8 usbcode) +{ + UINT8 scan_code = aKeypad2[usbcode].NormalScanCode; + UINT8 ascii_code = 0; + BOOLEAN changecase = mLegacyKeyboard.KeyModifierState.NumLock + || mLegacyKeyboard.KeyModifierState.Shift; + + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(scan_code); + + if (mLegacyKeyboard.KeyModifierState.NumLock + && mLegacyKeyboard.KeyModifierState.Shift) changecase = FALSE; + + if (changecase) ascii_code = aKeypad2[usbcode].ShiftedAsciiCode; + if (mLegacyKeyboard.KeyModifierState.Ctrl) { + return (UINT16)aKeypad2[usbcode].CtrlScanCode << 8; + } + if (mLegacyKeyboard.KeyModifierState.Alt) { + return (UINT16)aKeypad2[usbcode].AltScanCode << 8; + } + return ((UINT16)scan_code<<8) + ascii_code; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetCode_64 +// +// Description: Returns the scan/ascii code for USB Key 0x64, a.k.a. Europe2 +// Europe2 is typically in AT-101 Key Position 45, between Left +// Shift and Z keys. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 GetCode_64(UINT8 usbcode) +{ + // + // Check for Hot Key from the KeyMon driver + // + UpdateKeyMon(0x56); + + if (mLegacyKeyboard.KeyModifierState.Shift) return 0x567C; + return 0x565C; +} + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: TKEYGROUP +// +// Description: This structure describes the range of the USB keys and the +// function that is called if the USB key is found within this +// range. +// +// Fields: Name Type Description +//------------------------------------------------------------ +// first_keycode UINT8 first key code in the range +// last_keycode UINT8 last key code in the range +// GetCode GETCODE_FUNC function to call if the code is in the range +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + UINT8 first_keycode; + UINT8 last_keycode; + GETCODE_FUNC GetCode; +} TKEYGROUP; + +TKEYGROUP aGetKey[] = { + {0x04, 0x1d, GetCode_Letter}, + {0x1e, 0x27, GetCode_Number}, + {0x28, 0x38, GetCode_BasicKey}, + {0x3A, 0x43, GetCode_F1_10Key}, + {0x44, 0x45, GetCode_F11F12Key}, + {0x49, 0x52, GetCode_ExtKey}, + {0x54, 0x58, GetCode_Keypad1}, + {0x59, 0x63, GetCode_Keypad2}, + {0x64, 0x64, GetCode_64}, + {0, 0, 0} +}; + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SysNoKbcAutoRepeat +// +// Description: This function performs the key autorepeat +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SysNoKbcAutoRepeat() +{ + UINT8 i; + UINT8 bdaKbdLedFlags = *(UINT8*)0x417; + UINT8 ledstate; + + gUsbData->wRepeatCounter++; + if (gUsbData->wRepeatCounter >= gUsbData->wRepeatRate) { + + // + // Repeat rate is reached. + // Reload repeat delay counter with keyrepeat delay value; original + // type delay value will be restored in ProcessKeyboardData + // + gUsbData->wRepeatRate = aTypematicRateDelayTable[ + (gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_RATE_BIT_MASK) >> + KBC_TYPE_RATE_BIT_SHIFT]; + gUsbData->wRepeatCounter = 0; + + for (i=6; i>0; i--) if (mLegacyKeyboard.KeyCodeStorage[i-1] != 0) break; + + if (i != 0) { // Some keys to repeat + if (mLegacyKeyboard.KeyCodeStorage[i-1]==mLegacyKeyboard.KeyToRepeat) { + ProcessKeyCode(mLegacyKeyboard.KeyToRepeat); + } else { + mLegacyKeyboard.KeyToRepeat = mLegacyKeyboard.KeyCodeStorage[i-1]; + } + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + } + + // + // See if current NumLock/ScrlLock/CapsLock matches the 40:17 values; update + // the local data and LEDs accordingly. + // + ledstate = *(UINT8*)&mLegacyKeyboard.KeyModifierState & 7; + if (((bdaKbdLedFlags>>4) & 7) != ledstate) { // 7 is a mask for Scrl/Num/Caps locks + *(UINT8*)&mLegacyKeyboard.KeyModifierState &= 0xF8; + *(UINT8*)&mLegacyKeyboard.KeyModifierState |= ((bdaKbdLedFlags>>4) & 7); + UpdateLEDs(); // Turn on/off Ctrl, Alt, NumLock LEDs + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetAsciiScan +// +// Description: Calls the service routine for the given keycode. Returns the +// scan/ascii code. +// +// Input: Key code +// +// Output: scan code in upper byte, ascii code in lower byte +// +// Referrals: TKEYGROUP +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +GetAsciiScan(UINT8 keyCode) +{ + TKEYGROUP *KeyGroup; + UINT16 code; + + if (keyCode == 0x2C) return 0x3920; // Space Bar + for (KeyGroup = aGetKey; KeyGroup->GetCode != 0; KeyGroup++) { + if (keyCode >= KeyGroup->first_keycode && keyCode <= KeyGroup->last_keycode) { + code = KeyGroup->GetCode(keyCode-KeyGroup->first_keycode); + if (mLegacyKeyboard.KeyModifierState.Alt) code &= 0xFF00; + return code; + } + } + return 0; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UpdateKeyMon +// +// Description: This function takes the keyboard scan code and checks if it is present +// in the Key Monitor table. If found, it updates the corresponding bit in +// the Key Monitor map. +// Key monitor data structure pointer is at 9FC0:10C +// Key monitor map (32 bit) updated by this routine is at 9FC0:108 +// Map element is {BYTE, DWORD}; BYTE - scan code, DWORD - attribute +// +// Input: Key code +// +//Output Key monitor map is updated accordingly +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +UpdateKeyMon(UINT8 KeyCode) +{ + +#if KEYMONFILTER_SUPPORT + KEY_ELEMENT *KeyMonData; + UINT32 *KeyMonMap; + UINT16 EbdaSeg = *(UINT16*)0x40e; + UINTN i; + UINTN KeyMonSize; + + KeyMonMap=(UINT32 *)((EbdaSeg << 4)+ KEYMON_MAP); + // + //KeyMon data Seg is located in EBDA:10E and Offset is EBDA:0x10C + // + KeyMonData=(KEY_ELEMENT*)((*(UINT16 *)((EbdaSeg << 4) + KEYMON_DATA_ADDRESS + 2) << 4) + \ + *(UINT16 *)((EbdaSeg << 4) + KEYMON_DATA_ADDRESS)); + + if(KeyMonData == 0) { + // + //Nobody registerd the Hot key with KeyMon driver. + // + return; + } + + KeyMonSize=*(UINT32 *)KeyMonData; + (UINT8 *)KeyMonData+=4; + + for(i=0;i<=KeyMonSize;i++) { + if(KeyMonData[i].ScanCode == KeyCode && + KeyMonData[i].Keyattribute.ShiftKey == mLegacyKeyboard.KeyModifierState.Shift && + KeyMonData[i].Keyattribute.CtrlKey == mLegacyKeyboard.KeyModifierState.Ctrl && + KeyMonData[i].Keyattribute.AltKey == mLegacyKeyboard.KeyModifierState.Alt ) { + // + //Update the Keymon Map in the EBDA:0x108 area. + // + *KeyMonMap= (*KeyMonMap) | (1<< i); + } + + } + return; +#else + return; +#endif + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: InsertChar +// +// Description: Insert the given scan/ascii code in the BDA keyboard queue. +// Updates the necessary BDA pointers, head and tail. +// +// Input: Key code, scan code in upper byte, ascii code in lower byte +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +InsertChar(UINT16 keyCode) +{ + UINT16 bufHead = *(UINT16*)0x41a; + UINT16 bufTail = *(UINT16*)0x41c; + UINT16 bufStart = *(UINT16*)0x480; + UINT16 bufEnd = *(UINT16*)0x482; + + *(UINT16*)(UINTN)(0x400+bufTail) = keyCode; + bufTail+=2; + if (bufTail >= bufEnd) { + bufTail = bufStart; + } + + if (bufTail == bufHead) { + // + // Buffer overflow should be indicated here + // + return; + } + *(UINT16*)0x41c = bufTail; + + return; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UpdateLEDs +// +// Description: Updates USB keyboard(s) LEDs according to the value of +// mLegacyKeyboard.KeyModifierState. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UpdateLEDs( +) +{ + UINT8 i; + DEV_INFO *KbdDev; + UINT8 Rb; + + // + // Update LED status in every USB keyboard on the system + // + // BIT0 ScrlLock, BIT1 NumLock, BIT2 CapsLock + Rb = (mLegacyKeyboard.KeyModifierState.NumLock)? 1 : 0; + Rb = (mLegacyKeyboard.KeyModifierState.CapsLock)? Rb |2 : Rb; + Rb = (mLegacyKeyboard.KeyModifierState.ScrlLock)? Rb |4 : Rb; + // + // Update the LED status in BDA. + // + *(UINT8*)0x497 = ((*(UINT8*)0x497) & 0xF8 ) | ((mLegacyKeyboard.KeyModifierState.NumLock)? 2 : 0) + | ((mLegacyKeyboard.KeyModifierState.CapsLock)? 4:0) | ((mLegacyKeyboard.KeyModifierState.ScrlLock)? 1 : 0) ; + + for (i = 0; i < USB_DEV_HID_COUNT; i++) { + KbdDev = gUsbData->aUSBKBDeviceTable[i]; + if (KbdDev != NULL) { + UsbKbdSetLed(KbdDev, Rb); + } + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ProcessCtrlAltShift +// +// Description: Updates mLegacyKeyboard.KeyModifierState according to the value +// of the 1st byte of the USB keyboard data. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessCtrlAltShift( + UINT8 *usbKeys +) +{ + UINT8 i; + + mLegacyKeyboard.KeyModifierState.Ctrl = (usbKeys[0] & 0x11)? 1 : 0; + mLegacyKeyboard.KeyModifierState.Shift = (usbKeys[0] & 0x22)? 1 : 0; + mLegacyKeyboard.KeyModifierState.Alt = (usbKeys[0] & 0x44)? 1 : 0; + + // + // Process Ctrl-Alt-Del combination + // + if (mLegacyKeyboard.KeyModifierState.Ctrl + && mLegacyKeyboard.KeyModifierState.Alt) { + for (i=2; i<6;i++) { + if (usbKeys[i]==0x4C || usbKeys[i]==0x63) { + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + ASSERT(gRT); + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + } else { + ByteWriteIO(0xcf9, 6); + } + } + } + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ProcessLockKeys +// +// Description: Process the keys that alter NumLock/ScrollLock/CapsLock; updates +// mLegacyKeyboard.KeyModifierState and 0:417 accordingly. +// +// Input: USB key buffer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessLockKeys( + UINT8 *usbKeys +) +{ + UINT8 i; + + for (i=2; i<8; i++) { + switch (usbKeys[i]) { + case 0x53: // NumLock + *(UINT8*)0x417 ^= 0x20; // Toggle BIT5 + // *(UINT8*)0x497 ^= 0x02; // Toggle BIT1 + mLegacyKeyboard.KeyModifierState.NumLock ^= 1; // Toggle numlock state + break; + case 0x39: // CapsLock + *(UINT8*)0x417 ^= 0x40; // Toggle BIT6 + // *(UINT8*)0x497 ^= 0x04; // Toggle BIT2 + mLegacyKeyboard.KeyModifierState.CapsLock ^= 1; // Toggle capslock state + break; + case 0x47: // ScrlLock + *(UINT8*)0x417 ^= 0x10; // Toggle BIT4 + // *(UINT8*)0x497 ^= 0x01; // Toggle BIT0 + mLegacyKeyboard.KeyModifierState.ScrlLock ^= 1; // Toggle scrollock state + break; + } + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AdjustKeyBuffer +// +// Description: There is often the new key is pressed on a USB keyboard while +// the previous one is not quite released. In this case usbKeys +// buffer contains the old keys and the new ones. User, on the +// other hand, expects only the new ones to be processed. +// This requires the buffer data modification so that the "old" +// keys are removed. +// The only time we do not do this analysis is when the buffer +// is clear that indicates that all keys are released. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +AdjustKeyBuffer( + UINT8 *usbKeys +) +{ + UINT8 aData[6]; + UINT8 i, j; + + // Save the buffer + for (i=0; i<6; i++) aData[i]=usbKeys[i]; + + // Patch the buffer + for (j=0; j<6; j++) { + if (mLegacyKeyboard.KeyCodeStorage[j]==0) continue; + for (i=0; i<6; i++) { + if (usbKeys[i] == 0) continue; + if (usbKeys[i] == mLegacyKeyboard.KeyCodeStorage[j]) { + usbKeys[i] = 0; + } + } + } + // Store the original buffer + for (i=0; i<6; i++) mLegacyKeyboard.KeyCodeStorage[i] = aData[i]; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ProcessKeyCode +// +// Description: This routine converts USB code into UINT16 with ASCII code in the +// lower byte and PS/2 scan code in the upper byte and inserts this +// UINT16 in the legacy keyboard queue in BDA. +// +// Input: USB key +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ProcessKeyCode(UINT8 code) +{ + UINT16 ascii_scan; + ascii_scan = GetAsciiScan(code); + if (ascii_scan != 0) { + InsertChar(ascii_scan); + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKB_Int9 +// +// Description: This routine is called from when the new data from USB keyboard +// is transmitted and available for processing. The functionality is +// similar to legacy INT9 handler - data is converted into PS/2 +// ASCII/Scan codes and placed in BDA. +// +// Input: Buffer with USB keys +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKB_Int9( + UINT8 *usbKeys +) +{ + UINT8 *keyCode; + UINT8 i; + UINT8 ledstate; + UINT8 bdaKbdLedFlags = (*(UINT8*)0x417) >> 4; + + AdjustKeyBuffer(&usbKeys[2]); + + // + // See if current NumLock/ScrlLock/CapsLock matches the 40:17 values. + // ; update the local data and LEDs accordingly. + // + ledstate = *(UINT8*)&mLegacyKeyboard.KeyModifierState & 7; + if ((bdaKbdLedFlags & 7) != ledstate) { // 7 is a mask for Scrl/Num/Caps locks + *(UINT8*)&mLegacyKeyboard.KeyModifierState &= 0xF8; + *(UINT8*)&mLegacyKeyboard.KeyModifierState |= (bdaKbdLedFlags & 7); + UpdateLEDs(); // Turn on/off Ctrl, Alt, NumLock LEDs + // + // Update to current Ctrl, Alt, NumLock LEDs state. + // + ledstate = *(UINT8*)&mLegacyKeyboard.KeyModifierState & 7; + } + + ProcessLockKeys(usbKeys); + ProcessCtrlAltShift(usbKeys); + + for (keyCode=usbKeys+2, i=0; i<6; i++, keyCode++) { + if (*keyCode==0) continue; + ProcessKeyCode(*keyCode); + } + + if (ledstate != (*(UINT8*)&mLegacyKeyboard.KeyModifierState & 7)) { + UpdateLEDs(); // Turn on/off Ctrl, Alt, NumLock LEDs + } + + // + // Reload the typematic rate value + // + gUsbData->wRepeatRate = aTypematicRateDelayTable[ + (gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_DELAY_BIT_MASK) >> + KBC_TYPE_DELAY_BIT_SHIFT]; + gUsbData->wRepeatCounter = 0; + + // + // Buffer might be modified, original buffer is stored + // in mLegacyKeyboard.KeyCodeStorage + // + if (mLegacyKeyboard.KeyCodeStorage[0] == 0) { + USBKeyRepeat(NULL, 1); // Disable Key repeat + } else { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } +} + + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/uhci.c b/Core/EM/usb/rt/uhci.c new file mode 100644 index 0000000..f5f4664 --- /dev/null +++ b/Core/EM/usb/rt/uhci.c @@ -0,0 +1,3981 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/uhci.c 114 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 114 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/uhci.c $ +// +// 114 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 +// +// 113 7/22/16 3:50a 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 +// +// 112 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 +// +// 111 3/14/16 10:21p Wilsonlee +// [TAG] EIP257506 +// [Category] Improvement +// [Description] Add USB_KEYREPEAT_INTERVAL token to change the key +// repeat interval. +// [Files] usb.sdl, xhci.h, usbkbd.h, uhci.c, ohci.c, ehci.c +// +// 110 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 +// +// 109 12/03/15 1:48a Wilsonlee +// [TAG] EIP247625 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB hot-plug function is failed in external uhci +// controllers. +// [RootCause] We don't install UhciRootHubQhCallBack for external uhci +// controllers. +// [Solution] Handle the hot-plug function in the periodic timer smi +// handler if the uhci controller is external. +// [Files] uhci.c +// +// 108 4/10/15 3:11a 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 +// +// 107 3/08/15 10:49p Wilsonlee +// [TAG] EIP207774 +// [Category] Improvement +// [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and +// clear it if we don't start any HC. +// [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h +// +// 106 1/22/15 10:19p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 105 6/26/14 1:15a 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 +// +// 104 5/01/14 3:57a Ryanchou +// [TAG] EIP162589 +// [Category] Improvement +// [Description] Do not register external controller as key repeat +// controller. +// [Files] ehci.c, ohci.c, uhci.c +// +// 103 4/30/14 8:56a Ryanchou +// [TAG] EIP160289 +// [Category] Improvement +// [Description] Handle zero length of short packet. +// [Files] uhci.c +// +// 102 4/30/14 6:13a 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 +// +// 101 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 +// +// 100 9/24/13 5:39a Ryanchou +// [TAG] EIP132985 +// [Category] Improvement +// [Description] Clear the SMI enable bit if UHCI is not controlled by +// BIOS. +// [Files] uhci.c +// +// 99 8/16/13 2:15a Ryanchou +// +// 98 7/26/13 2:40a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 97 7/22/13 10:31p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 96 6/02/13 11:42p Wilsonlee +// [TAG] EIP123235 +// [Category] Improvement +// [Description] Stop the usb host controller at ExitBootService if it +// is an extend card or it doesn't support HW SMI. +// [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, +// uhcd.c +// +// 95 4/16/13 6:45a Ryanchou +// [TAG] EIP118912 +// [Category] Improvement +// [Description] Add VIA VT6212 EHCI controller support. +// [Files] ehci.c, uhci.c, usbdef.h, uhcd.c +// +// 94 3/19/13 3:58a 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 +// +// 93 3/18/13 4:49a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 92 2/24/13 9:00p Wilsonlee +// [TAG] EIP113541 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] System hangs at checkpoint 0xA2 when Win8 resume from S4. +// [RootCause] The "HCHalted" bit and "Port Change Detect" bit are set +// when the system S4 resume to Win8 OS. +// [Solution] We need to clear the interrupt status even if the +// "HCHalted" bit is set. +// [Files] ehci.c, ohci.c, uhci.c +// +// 91 12/06/12 12:39a Wilsonlee +// [TAG] EIP103186 +// [Category] Improvement +// [Description] Handle the error case "MEMIO was disabled" in USB +// driver. +// [Files] uhci.c, ohci.c, ehci.c, xhci.c +// +// 90 11/22/12 9:21p Wilsonlee +// [TAG] EIP106887 +// [Category] New Feature +// [Description] Support usb S5 wake up function for UHCI. +// [Files] usb.c, uhci.c, uhci.h +// +// 89 11/10/12 6:48a Ryanchou +// +// 88 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 +// +// 87 9/28/12 2:37a 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 +// +// 86 8/29/12 8:17a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 85 5/04/12 6:39a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 84 5/03/12 6:23a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 83 11/08/11 1:56a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 82 9/26/11 11:43p Roberthsu +// [TAG] EIP67230 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ntrig touch panel can not use on CedarTrail +// [RootCause] Because ntrig report data over than 512 byte.Control +// transfer check if over 512 than set length is 512. +// [Solution] Remove check transfer length. +// [Files] ohci.c,uhci.c,usbhid.c +// +// 81 8/08/11 6:59a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 80 8/08/11 5:15a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 79 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 78 7/13/11 4:09a Ryanchou +// [TAG] EIP59332 +// [Category] Improvement +// [Description] Modified the Stop function for UHCD and USBBUS to +// properly stop devices and uninstall the protocols. +// [Files] uhcd.c, uhcd.h, uhci.c, usbbus.c, UsbInt13.c, usbmisc.c +// +// 77 7/12/11 8:09a 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 +// +// 76 7/01/11 3:19a Ryanchou +// [TAG] EIP61385 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] USB devices can't detected. +// [RootCause] This is the side effect of EIP59663, the port status +// doesn't reflect connect status and connect status change. +// [Solution] Add 100 us delay. +// [Files] ehci.c, uhci.c +// +// 75 6/22/11 1:44a Ryanchou +// [TAG] EIP59738 +// [Category] Improvement +// [Description] Support Block size other than 512 bytes USB HDD in UEFI +// mode. +// [Files] efiusbmass.c, uhci.c, usb.c, usbdef.h, usbmass.c +// +// 74 5/03/11 10:09a Ryanchou +// [TAG] EIP54283 +// [Category] Improvement +// [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery +// endpoint halt. +// [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c +// +// 73 4/06/11 1:33a Ryanchou +// [TAG] EIP54782 +// [Category] Improvement +// [Description] Change polling data size of HID devices to max packet +// size of interrupt endpoint. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c +// +// 72 3/29/11 10:51p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 71 3/29/11 10:08a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 70 11/11/10 11:35p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 69 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 68 9/07/10 4:11a Tonylo +// Remove user tags for coding standard. +// +// 67 8/18/10 4:22p Olegi +// Klockwork related fixes; EIP37978 +// +// 66 4/30/10 3:36p Fredericko +// Fixed EIP : 38028: USB AutoKeyRepeat is not working properly +// +// 65 3/10/10 6:35p Olegi +// +// 64 3/10/10 10:51a Olegi +// Function headers corrected. +// +// 63 3/06/10 1:11p Olegi +// +// 62 2/26/10 4:23p Olegi +// +// 61 2/08/10 10:11a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 60 2/08/10 9:40a Olegi +// EIP34448: Changes in UHCIWaitForTransferComplete and transfer routines. +// +// 59 1/26/10 4:35p Olegi +// +// 55 12/23/09 11:59a Olegi +// +// 54 12/22/09 8:57a Olegi +// +// 53 12/10/09 10:06a Olegi +// Added timeout in UHCI_WaitForBulkTransferComplete, EIP32048. +// +// 52 11/13/09 12:37p Olegi +// +// 51 10/30/09 5:47p Olegi +// +// 50 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 49 9/15/09 10:21a Olegi +// Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. +// +// 48 8/26/09 11:41a Olegi +// Changes that prevent collision of keyboard activity and mass storage +// access. EIP#22808 +// +// 47 2/23/09 12:56p Olegi +// +// 46 2/20/09 4:43p Olegi +// +// 45 2/17/09 4:01p Olegi +// +// 44 2/17/09 8:58a Olegi +// +// 43 2/06/09 4:06p Olegi +// +// 42 1/16/09 3:50p Olegi +// Optimization in BulkTransfer scheduling. +// +// 41 10/06/08 3:33p Olegi +// EHCI change ownership testing in DOS fix (EIP#14855). +// +// 40 9/02/08 10:29a Olegi +// EIP14855 bugfix: change ownership request is not processed properly in +// case of multiple controllers of the same type. +// +// 39 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 38 2/05/08 3:13p Olegi +// Bugfix in BulkTdCallback that showed when data TD returns with stall +// condition. +// +// 37 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 36 10/15/07 5:13p Olegi +// ControlTransfer cleanup. +// +// 35 9/26/07 9:15a Olegi +// Added USB_FORCE_64BIT_ALIGNMENT flag as well as a call ty sync the LEDs +// between keyboards in DOS. +// +// 34 9/21/07 5:10p Davidd +// Allocation TDs is forced to be 64-bytes aligned. +// +// 33 9/06/07 6:12p Olegi +// +// 32 9/06/07 5:52p Olegi +// Tracker 27603 fix added. +// +// 31 8/14/07 11:56a Olegi +// Reverted buggy BulkTransfer changes to make floppy work. +// +// 30 8/14/07 10:59a Olegi +// +// 29 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 28 4/17/07 6:13p Fredericko +// Modified UHCI_EnableRootHub to preserve the Connect Status Change bit. +// +// 27 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 26 3/20/07 12:18p Olegi +// +// 25 1/26/07 2:52p Olegi +// Bugfix in UHCI_BulkTDCallback. +// +// 24 1/25/07 4:25p Olegi +// +// 23 1/25/07 10:19a Olegi +// +// 22 1/02/07 2:08p Olegi +// +// 21 12/28/06 5:27p Olegi +// +// 20 12/26/06 10:52a Olegi +// +// 19 12/20/06 2:30p Olegi +// +// 17 10/19/06 5:24p Andriyn +// +// 15 10/12/06 9:37p Andriyn +// Fix: unexpected plug-off hangs with endless TIMEOUTs +// +// 14 7/10/06 2:57p Andriyn +// Fix: double delocation of descriptors used for control transfer +// +// 13 6/29/06 11:54a Andriyn +// Removed commented code +// +// 12 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 11 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 10 3/06/06 6:23p Olegi +// +// 9 11/29/05 12:33p Andriyn +// +// 8 9/23/05 12:01p Olegi +// +// 7 9/23/05 11:58a Olegi +// +// 6 8/27/05 3:43p Andriyn +// Fix: lost mouse click when mouse is not moving +// +// 5 8/11/05 9:53a Olegi +// 60/64 port emulation related fixes for EMU6064 driver. +// +// 4 6/03/05 6:08p Olegi +// HW SMI registration change. +// +// 3 5/19/05 8:07p Olegi +// Aptio changes in driver 8.1 implementation. +// +// 2 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Uhci.c +// +// Description: AMI USB UHCI driver +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +extern VOID* USB_MemAlloc (UINT16); +extern UINT8 USB_MemFree (VOID _FAR_ *, UINT16); +extern UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); + +extern UINT32 ReadPCIConfig(UINT16, UINT8); +extern VOID WordWritePCIConfig(UINT16, UINT8, UINT16); +extern UINT8 ByteReadIO(UINT16); +extern VOID ByteWriteIO(UINT16, UINT8); +extern UINT16 WordReadIO(UINT16); +extern VOID WordWriteIO(UINT16, UINT16); +extern UINT32 DwordReadIO(UINT16); +extern VOID DwordWriteIO(UINT16, UINT32); +extern VOID FixedDelay(UINTN); +extern DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +extern UINT8 USBLogError(UINT16); +extern VOID USB_InitFrameList (HC_STRUC*, UINT32); +#if USB_DEV_KBD +extern VOID USBKBDPeriodicInterruptHandler(HC_STRUC*); +extern VOID USBKeyRepeat(HC_STRUC*, UINT8); +#endif + +UINT8 USB_DisconnectDevice (HC_STRUC*, UINT8, UINT8); +UINT8 UsbGetDataToggle(DEV_INFO*,UINT8); +VOID UsbUpdateDataToggle(DEV_INFO*, UINT8, UINT8); + +//--------------------------------------------------------------------------- + +// Public function declaration +UINT8 UHCI_Start (HC_STRUC*); +UINT8 UHCI_Stop (HC_STRUC*); +UINT8 UHCI_EnumeratePorts (HC_STRUC*); +UINT8 UHCI_DisableInterrupts (HC_STRUC*); +UINT8 UHCI_EnableInterrupts (HC_STRUC*); +UINT8 UHCI_ProcessInterrupt(HC_STRUC*); +UINT8 UHCI_GetRootHubStatus (HC_STRUC*,UINT8, BOOLEAN); +UINT8 UHCI_DisableRootHub (HC_STRUC*,UINT8); +UINT8 UHCI_EnableRootHub (HC_STRUC*,UINT8); +UINT8 UHCI_ResetRootHub (HC_STRUC*,UINT8); +UINT16 UHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); +UINT32 UHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); +UINT16 UHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); +UINT8 UHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 UHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 UHCI_DisableKeyRepeat (HC_STRUC*); +UINT8 UHCI_EnableKeyRepeat (HC_STRUC*); +UINT8 UHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) + +UINT8 UhciProcessQh (HC_STRUC*, UHCI_QH*); +UINT8 UhciProcessTd (HC_STRUC*, UHCI_TD*); +UINT8 UhciProcessFrameList (HC_STRUC*); + +UINT8 UHCI_DisableHCPorts (HC_STRUC*); +UINT8 UHCI_StartTDSchedule (HC_STRUC*); +UINT8 UHCI_StopTDSchedule (HC_STRUC*); +UINT8 UHCI_InterruptTDCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*); +UINT8 UhciAddQhToFrameList (HC_STRUC*, UHCI_QH*); +UINT8 UhciRemoveQhFromFrameList (HC_STRUC*, UHCI_QH*); +VOID UhciInitQh (UHCI_QH*); +BOOLEAN UhciIsHalted(HC_STRUC*); +UINT8 UhciTranslateInterval(UINT8); + +UHCI_TD* +UhciAllocGeneralTds ( + IN UINT8 DeviceAddr, + IN BOOLEAN LowSpeed, + IN UINT8 PacketId, + IN UINT8 EndpointAddr, + IN UINT16 MaxPacket, + IN BOOLEAN ShortPacket, + IN OUT UINTN *BufferAddr, + IN OUT UINT32 *Length, + IN OUT UINT8 *DataToggle +); + +VOID +UhciFreeTds ( + IN UHCI_TD *FirstTd +); + +VOID +UhciActivateTds ( + IN UHCI_TD *FirstTd, + IN UINT8 DataToggle +); + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +UINT8 UhciRootHubQhCallBack(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 UhciRepeatQhCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 UhciPollingQhCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_FillHCDEntries +// +// Description: +// This function fills the host controller driver routine pointers +// +// Input: +// fpHCDHeader Ptr to the host controller header structure +// +// Output: +// USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_FillHCDEntries(HCD_HEADER *fpHCDHeader) +{ + // + // Fill the routines here + // + fpHCDHeader->pfnHCDStart = UHCI_Start; + fpHCDHeader->pfnHCDStop = UHCI_Stop; + fpHCDHeader->pfnHCDEnumeratePorts = UHCI_EnumeratePorts; + fpHCDHeader->pfnHCDDisableInterrupts = UHCI_DisableInterrupts; + fpHCDHeader->pfnHCDEnableInterrupts = UHCI_EnableInterrupts; + fpHCDHeader->pfnHCDProcessInterrupt = UHCI_ProcessInterrupt; + fpHCDHeader->pfnHCDGetRootHubStatus = UHCI_GetRootHubStatus; + fpHCDHeader->pfnHCDDisableRootHub = UHCI_DisableRootHub; + fpHCDHeader->pfnHCDEnableRootHub = UHCI_EnableRootHub; + fpHCDHeader->pfnHCDControlTransfer = UHCI_ControlTransfer; + fpHCDHeader->pfnHCDBulkTransfer = UHCI_BulkTransfer; + fpHCDHeader->pfnHCDInterruptTransfer = UHCI_InterruptTransfer; + fpHCDHeader->pfnHCDDeactivatePolling = UHCI_DeactivatePolling; + fpHCDHeader->pfnHCDActivatePolling = UHCI_ActivatePolling; + fpHCDHeader->pfnHCDDisableKeyRepeat = UHCI_DisableKeyRepeat; + fpHCDHeader->pfnHCDEnableKeyRepeat = UHCI_EnableKeyRepeat; + fpHCDHeader->pfnHCDEnableEndpoints = USB_EnableEndpointsDummy; + fpHCDHeader->pfnHCDInitDeviceData = USB_InitDeviceDataDummy; + fpHCDHeader->pfnHCDDeinitDeviceData = USB_DeinitDeviceDataDummy; + fpHCDHeader->pfnHCDResetRootHub = UHCI_ResetRootHub; + fpHCDHeader->pfnHCDClearEndpointState = 0; //(EIP54283+) + fpHCDHeader->pfnHCDGlobalSuspend = UHCI_GlobalSuspend; //(EIP54018+) + + USB_InstallCallBackFunction(UhciPollingQhCallback); + USB_InstallCallBackFunction(UhciRepeatQhCallback); + USB_InstallCallBackFunction(UhciRootHubQhCallBack); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_Start +// +// Description: +// This API function is called to start a UHCI host controller. The input to the +// routine is the pointer to the HC structure that defines this host controller +// +// Input: +// fpHCStruc Ptr to the host controller structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_Start (HC_STRUC* fpHCStruc) +{ + UINT16 wIOAddr; + UINT16 LegSupReg; + UINT16 Index; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)fpHCStruc->fpFrameList, 0x1000); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + +/* +USB_DEBUG(DEBUG_LEVEL_3, "Enabling IO/BM for UHCI HC %02X\n", fpHCStruc->wBusDevFuncNum); + // + // Enable IO access and Bus Mastering + // + WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, 4, BIT0 + BIT2); +*/ + // + // Set number of root hub ports present + // + fpHCStruc->bNumPorts = 2; + + // + // Get the I/O base address for the host controller + // + wIOAddr = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_IO_BASE_ADDRESS); + + // + // Mask the low order two bits and store the value in HCStruc + // + wIOAddr = (UINT16)(wIOAddr & (~(BIT0+BIT1))); + USB_DEBUG(DEBUG_LEVEL_4, "HC I/O Address : %X\n", wIOAddr); + fpHCStruc->BaseAddress = wIOAddr; + + fpHCStruc->wAsyncListSize = UHCI_FRAME_LIST_SIZE; + + // + // Disable hardware interrupt generation by programming legacy registers + // + LegSupReg = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); + + // + // Disable generation of SMI/IRQ and clear status bits + // + LegSupReg = (UINT16)(LegSupReg & (~BIT4)); + WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); + + // + // Disable the interrupts (to aVOID spurious interrupts) + // + UHCI_DisableInterrupts(fpHCStruc); + + // + // Disable the host controller root hub ports + // + UHCI_DisableHCPorts(fpHCStruc); + + // + // Check whether HC is already stopped + // + if (!UhciIsHalted(fpHCStruc)) { + // + // HC is still running. Stop it by programming HC run bit + // + ByteWriteIO ((UINT16)(wIOAddr + UHCI_COMMAND_REG), + ByteReadIO((UINT16)(wIOAddr + UHCI_COMMAND_REG)) & ~UHC_HOST_CONTROLLER_RUN); + + // + // Check whether the host controller is halted (check for 50 ms) + // + for (Index = 0; Index < 500; Index++) { + if ((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED) { + break; + } + FixedDelay(100); // 100 us delay + } + } + ASSERT((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED); + if (!((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED)) { + return USB_ERROR; + } + + // + // Reset the host controller + // + ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), UHC_GLOBAL_RESET); + + FixedDelay(10 * 1000); // Recommended 10msec delay, UHCI Spec, p.12, GRESET description + + ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), 0); + + // + // Memory has been allocated in AMIUHCD + // + if (!fpHCStruc->fpFrameList) { + return USB_ERROR; + } + + USB_InitFrameList (fpHCStruc, UHCI_TERMINATE); + + // + // Program frame list pointer to the HC + // + USB_DEBUG(DEBUG_LEVEL_4, "Frame list pointer : %x\n", fpHCStruc->fpFrameList); + DwordWriteIO((UINT16)(wIOAddr + UHCI_FRAME_LIST_BASE), (UINT32)(UINTN)fpHCStruc->fpFrameList); + + USB_DEBUG(DEBUG_LEVEL_6, "UHCI_StartTDSchedule\n"); + + // + // Start the TD schedule + // + if (UHCI_StartTDSchedule(fpHCStruc) != USB_SUCCESS) + return USB_ERROR; + +#if USB_RUNTIME_DRIVER_IN_SMM + // + // Enable hardware interrupt generation by programming legacy registers + // + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + LegSupReg = (UINT16)ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); + // Enable generation of SMI/IRQ + LegSupReg = (UINT16)(LegSupReg | BIT4) & ~BIT13; + WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); + } +#endif + // + // Start the host controller by setting the run and configure bit + // + WordWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), + UHC_HOST_CONTROLLER_RUN | + UHC_CONFIGURE_FLAG | + UHC_MAX_PACKET_64_BYTE); + + // + // Enable interrupt generation + // +// WordWriteIO((UINT16)(wIOAddr + UHCI_INTERRUPT_ENABLE), (UHC_IOC_ENABLE | UHC_TIMEOUT_CRC_ENABLE)); + WordWriteIO((UINT16)(wIOAddr + UHCI_INTERRUPT_ENABLE), UHC_IOC_ENABLE); + + fpHCStruc->dHCFlag |= HC_STATE_RUNNING; + + // Set USB_FLAG_DRIVER_STARTED flag when HC is running. + if (!(gUsbData->dUSBStateFlag & USB_FLAG_DRIVER_STARTED)) { + gUsbData->dUSBStateFlag |= USB_FLAG_DRIVER_STARTED; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + // + // Register the USB HW SMI handler + // + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + UsbInstallHwSmiHandler(fpHCStruc); + } else { + USBSB_InstallUsbIntTimerHandler(); + } +#endif + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_Stop +// +// Description: +// This API function is called to stop the UHCI controller. The input to the +// routine is the pointer to the HC structure that defines this host controller. +// +// Input: +// fpHCStruc Ptr to the host controller structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_Stop (HC_STRUC* fpHCStruc) +{ + UINT16 wIOAddr = (UINT16)fpHCStruc->BaseAddress; + UINT16 LegSupReg; + UINT16 Index; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + // + // Disable hardware interrupt generation by programming legacy registers + // + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + LegSupReg = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); + + // + // Disable generation of SMI/IRQ and clear status bits + // + LegSupReg = (UINT16)(LegSupReg & ~(BIT4)); + WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); + } + + // + // Disable the host controller interrupt generation + // + UHCI_DisableInterrupts (fpHCStruc); + + // Disconnect all devices + USB_DisconnectDevice(fpHCStruc, fpHCStruc->bHCNumber | BIT7, 1); + USB_DisconnectDevice(fpHCStruc, fpHCStruc->bHCNumber | BIT7, 2); + + // + // Stop the host controller + // + if (!UhciIsHalted(fpHCStruc)) { + // + // Clear HC run bit + // + ByteWriteIO ((UINT16)(wIOAddr + UHCI_COMMAND_REG), + ByteReadIO((UINT16)(wIOAddr + UHCI_COMMAND_REG)) & ~(UHC_HOST_CONTROLLER_RUN)); + + // + // Check whether the host controller is halted (check for 50 ms) + // + for (Index = 0; Index < 500; Index++) { + if ((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED) { + break; + } + FixedDelay(100); // 100 us delay + } + } + ASSERT((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED); + + // Reset the host controller + ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), UHC_GLOBAL_RESET); + // Recommended 10msec delay, UHCI Spec, p.12, GRESET description + FixedDelay(10 * 1000); + ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), 0); + + // + // Clear the frame list pointers + // + USB_InitFrameList (fpHCStruc, UHCI_TERMINATE); + + // + // Disable and free the TD schedule data structures + // + UHCI_StopTDSchedule (fpHCStruc); + + // + // Set the HC state to stopped + // + fpHCStruc->dHCFlag &= ~(HC_STATE_RUNNING); + + CheckBiosOwnedHc(); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_EnumeratePorts +// +// Description: +// This API function is called to enumerate the root hub ports in the UHCI +// controller. The input to the routine is the pointer to the HC structure +// that defines this host controller +// +// Input: +// fpHCStruc Ptr to the host controller structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_EnumeratePorts(HC_STRUC* fpHCStruc) +{ + UINT8 bHCNumber; + UINT16 wIOAddr, wPortAddr; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + wIOAddr = (UINT16)fpHCStruc->BaseAddress; + +//(USB0061+)> + // + // Check whether USB host controllers are accessible to aVOID system + // hang in ports enumeration. + // + if (ByteReadIO(wIOAddr) == 0xFF) return USB_ERROR; +//<(USB0061+) + // + // Check whether enumeration is already began + // + if(gUsbData->bEnumFlag == TRUE) return USB_SUCCESS; + + gUsbData->bEnumFlag = TRUE; + bHCNumber = (UINT8)(fpHCStruc->bHCNumber | BIT7); + //(EIP61385)> + // + // Process Port#1 and clear Port#1 status bit + // + wPortAddr = wIOAddr + UHCI_PORT1_CONTROL; + if ((WordReadIO(wPortAddr) & (UHC_CONNECT_STATUS_CHANGE | + UHC_CONNECT_STATUS)) == UHC_CONNECT_STATUS_CHANGE) { + WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); + } + USBCheckPortChange(fpHCStruc, bHCNumber, 1); + WordWriteIO(wPortAddr, WordReadIO(wPortAddr)); + + // + // Process Port#2 and clear Port#2 status bit + // + wPortAddr = wIOAddr + UHCI_PORT2_CONTROL; + if ((WordReadIO(wPortAddr) & (UHC_CONNECT_STATUS_CHANGE | + UHC_CONNECT_STATUS)) == UHC_CONNECT_STATUS_CHANGE) { + WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); + } + USBCheckPortChange(fpHCStruc, bHCNumber, 2); + WordWriteIO(wPortAddr, WordReadIO(wPortAddr)); + //<(EIP61385) + gUsbData->bEnumFlag = FALSE; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_DisableInterrupts +// +// Description: +// This API function is called to disable the interrupts generated by the UHCI +// host controller. The input to the routine is the pointer to the HC structure +// that defines this host controller. +// +// Input: +// fpHCStruc Ptr to the host controller structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_DisableInterrupts (HC_STRUC* fpHCStruc) +{ + UINT8 IntEnReg; + UINT16 IoAddr = (UINT16)fpHCStruc->BaseAddress; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + IntEnReg = ByteReadIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE)); + IntEnReg &= ~(UHC_IOC_ENABLE); + ByteWriteIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE), IntEnReg); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_EnableInterrupts +// +// Description: +// This function enables the HC interrupts +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// +// Output: +// USB_SUCCESS of USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_EnableInterrupts (HC_STRUC* fpHCStruc) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_ProcessInterrupt +// +// Description: +// This function is called when the USB interrupt bit is set. This function +// will parse through the TDs and QHs to find out completed TDs and call +// their respective callback functions. +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// +// Output: +// USB_ERROR - Need more Interrupt processing +// USB_SUCCESS - No interrupts pending +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_ProcessInterrupt( + HC_STRUC *HcStruc +) +{ + UINT16 IoPort = (UINT16)HcStruc->BaseAddress; + UINT16 LegSupReg = 0; + UINT16 UsbSts = 0; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) { + LegSupReg = (UINT16)ReadPCIConfig(HcStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); + if (!(LegSupReg & BIT4)) { + return USB_ERROR; + } + } +#endif + + // + // Check whether the controller is still under BIOS control + // Read the frame list base address and compare with stored value + // + if (((UINTN)DwordReadIO(IoPort + UHCI_FRAME_LIST_BASE) & 0xFFFFF000) != + (UINTN)HcStruc->fpFrameList) { +#if USB_RUNTIME_DRIVER_IN_SMM + if (!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) { + // Disable the SMI on IRQ enable bit + WordWritePCIConfig(HcStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg & ~BIT4); + } +#endif + return USB_ERROR; // Control is not with us anymore + } + + UsbSts = WordReadIO(IoPort + UHCI_STATUS_REG); + + if (UsbSts & UHC_HC_HALTED) { + return USB_ERROR; + } + + if (UsbSts & UHC_USB_INTERRUPT) { + WordWriteIO(IoPort + UHCI_STATUS_REG, UsbSts); + UhciProcessFrameList(HcStruc); + } + + if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { + UhciRootHubQhCallBack(HcStruc, NULL, NULL, NULL, 0); + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_GetRootHubStatus +// +// Description: +// This function returns the port connect status for the root hub port +// +// Input: +// pHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC whose status is requested +// +// Output: +// NewPortNum Port in the HC that can possibly replace bPortNum +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_GetRootHubStatus( + HC_STRUC* fpHCStruc, + UINT8 bPortNum, + BOOLEAN ClearChangeBits +) +{ + UINT16 wPortAddr, wPortStatus, wPortTemp; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + wPortStatus = USB_PORT_STAT_DEV_OWNER; + wPortAddr = (UINT16)((bPortNum<<1)+UHCI_PORT1_CONTROL-2+fpHCStruc->BaseAddress); + + // + // Read the port status + // + wPortTemp = WordReadIO(wPortAddr); + USB_DEBUG(3, "UHCI port[%d] status: %04x\n", bPortNum, wPortTemp); + + // + // Check for port connect status + // + if (wPortTemp & UHC_CONNECT_STATUS) { + wPortStatus |= USB_PORT_STAT_DEV_CONNECTED; + + // + // Identify the speed of the device (full or low speed) + // + if (wPortTemp & UHC_LOW_SPEED_ATTACHED) { + wPortStatus |= USB_PORT_STAT_DEV_LOWSPEED; + } + else { + wPortStatus |= USB_PORT_STAT_DEV_FULLSPEED; + } + + if (wPortTemp & UHC_PORT_ENABLE) { + wPortStatus |= USB_PORT_STAT_DEV_ENABLED; + } + } + + // + // Check for connect status change + // + if (wPortTemp & UHC_CONNECT_STATUS_CHANGE) { + wPortStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + if (ClearChangeBits == TRUE) { + WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); //(EIP61385+) + } + } + + return (UINT8)wPortStatus; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_DisableRootHub +// +// Description: +// This function disables the root hub of the UHCI controller. +// +// Input: +// fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Root port to be disabled +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_DisableRootHub (HC_STRUC* fpHCStruc,UINT8 bPortNum) +{ + UINT16 wPortAddr = + (UINT16)(fpHCStruc->BaseAddress + (bPortNum << 1) + UHCI_PORT1_CONTROL - 2); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Reset the enable bit + // + WordWriteIO( + wPortAddr, + (UINT16)(WordReadIO(wPortAddr) & (~UHC_PORT_ENABLE))); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_EnableRootHub +// +// Description: +// This function enables the root hub port specified +// +// Input: +// fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Root port to be enabled +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_EnableRootHub ( + HC_STRUC *HcStruc, + UINT8 PortNum) +{ + UINT16 PortStatus; + UINT16 PortAddr = + (UINT16)(HcStruc->BaseAddress + (PortNum << 1) + UHCI_PORT1_CONTROL - 2); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + PortStatus = WordReadIO(PortAddr); + + // + // Set the enable & reset bit, preserve Connect Status Change bit + // + PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); + WordWriteIO(PortAddr, PortStatus | UHC_PORT_RESET); + + // + // Wait for 10ms + // + FixedDelay(10 * 1000); // 10msec delay + + // + // Clear the reset bit and set the enable, preserve Connect Status Change bit + // + PortStatus = WordReadIO(PortAddr); + PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); + WordWriteIO(PortAddr, PortStatus & (~UHC_PORT_RESET)); + + // Wait 1 ms for stabilize the port status + FixedDelay(1 * 1000); // 1 ms delay + + // Clear Connect Status Change bit and Port Enable Change bit + WordWriteIO(PortAddr, WordReadIO(PortAddr)); + + // + // Set the enable bit + // + PortStatus = WordReadIO(PortAddr); + PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); + WordWriteIO(PortAddr, PortStatus | UHC_PORT_ENABLE); + + // + // Wait for 100ms + // + //FixedDelay(gUsbData->UsbTimingPolicy.UhciPortEnable * 1000); // 100msec delay + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_ResetRootHub +// +// Description: +// This function resets the UHCI HC root hub port +// +// Input: +// HcStruc Pointer to HCStruc of the host controller +// PortNum Root port to be enabled +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_ResetRootHub ( + HC_STRUC* HcStruc, + UINT8 PortNum) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UHCI_GlobalSuspend +// +// Description: +// This function suspend the UHCI HC. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_GlobalSuspend( + HC_STRUC* HcStruc +) +{ + + UINT16 IoAddr = (UINT16)HcStruc->BaseAddress; + UINT16 UhciCommand; + UINT16 UhciStatus; + UINT32 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + UhciCommand = WordReadIO(IoAddr + UHCI_COMMAND_REG); + UhciCommand &= ~UHC_HOST_CONTROLLER_RUN; + WordWriteIO(IoAddr + UHCI_COMMAND_REG, UhciCommand); + for (i = 0; i < 1024; i++) { + UhciStatus = WordReadIO(IoAddr + UHCI_STATUS_REG); + if (UhciStatus & UHC_HC_HALTED) { + break; + } + FixedDelay(1 * 1000); + } + + WordWriteIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE), UHC_RESUME_ENABLE); + + UhciStatus = WordReadIO(IoAddr + UHCI_STATUS_REG); + UhciStatus |= 0x1F; + WordWriteIO(IoAddr + UHCI_STATUS_REG, UhciStatus); + + UhciCommand = WordReadIO(IoAddr + UHCI_COMMAND_REG); + UhciCommand |= UHC_ENTER_SUSPEND; + WordWriteIO(IoAddr + UHCI_COMMAND_REG, UhciCommand); + FixedDelay(50 * 1000); + + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + HcStruc->dHCFlag |= HC_STATE_SUSPEND; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciExecuteTransfer +// +// Description: +// This function execites a transfer and waits for the completion of +// the transfer, and returns the transfer results. +// +// Input: +// Pointers to the first data TD and last data TD in the TD list +// +// Output: +// Return value is the size of transferred data, Bytes +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +UhciExecuteTransfer ( + HC_STRUC *HcStruc, + UHCI_QH *TransferQh +) +{ + UINT32 Timeout = gUsbData->wTimeOutValue * 100; // *100, makes it number of 10 usec units + BOOLEAN InfiniteLoop = (Timeout == 0); + + TransferQh->ActiveFlag = TRUE; + UhciAddQhToFrameList(HcStruc, TransferQh); + + while (InfiniteLoop || Timeout--) { + UhciProcessQh(HcStruc, TransferQh); + if (TransferQh->ActiveFlag == FALSE) { + break; + } + + FixedDelay(10); // 10 microseconds + } + + UhciRemoveQhFromFrameList(HcStruc, TransferQh); + UhciProcessQh(HcStruc, TransferQh); + + if (TransferQh->ActiveFlag) { + USB_DEBUG (DEBUG_LEVEL_3, "UHCI Time-Out\n"); + } + + return TransferQh->BytesTransferred; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_ControlTransfer +// +// Description: +// This function executes a device request command transaction on the USB. One +// setup packet is generated containing the device request parameters supplied +// by the caller. The setup packet may be followed by data in or data out packets +// containing data sent from the host to the device or vice-versa. This function +// will not return until the request either completes successfully or completes in +// error (due to time out, etc.) +// +// Input: +// fpHCStruc Pointer to HCStruc of the host controller +// 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: Get Configuration, Set Address etc) +// 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 transferred: 0 - Failure, <>0 - Success +// +// +// Notes: +// Do not use USB_SUCCESS or USB_ERROR as returned values +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +UHCI_ControlTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT16 wRequest, + UINT16 wIndex, + UINT16 wValue, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT16 wTemp; + UINT32 dTemp; + UINT32 dValue; + + DEV_REQ *fpDevReq; + UHCI_TD *SetupTd = NULL; + UHCI_TD *DataTDs = NULL; + UHCI_TD *StatusTd = NULL; + UHCI_TD *LastTd = NULL; + UHCI_TD *CurrentTd = NULL; + UHCI_QH *CtrlQh; + UINT16 NumDataTDs = 0; + UINT16 BytesRemaining; + UINT16 BytesTransferred; + UINT8 DataToggle; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + if (wLength != 0) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Uhci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (UhciIsHalted(fpHCStruc)) { + return 0; + } + + if (!VALID_DEVINFO(fpDevInfo)) return 0; + + gUsbData->bLastCommandStatus &= ~( USB_CONTROL_STALLED ); + gUsbData->dLastCommandStatusExtended = 0; + + // + // Allocate TDs for control setup and control status packets + // + SetupTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + if(SetupTd == NULL) { + return 0; + } + + // + // Build the device request in the data area of the control setup TD + // + fpDevReq = (DEV_REQ*)SetupTd->aDataArea; + fpDevReq->wRequestType = wRequest; + fpDevReq->wValue = wValue; + fpDevReq->wIndex = wIndex; + fpDevReq->wDataLength = wLength; + + // + // dTemp will contain the device address and endpoint shifted and ready to go + // into the TDs' token field. + // 10:0] = Dev. Addr & Endpoint + // [18:8] = Dev. Addr & Endpoint + // + dTemp = ((UINT32)(fpDevInfo->bDeviceAddress)) << 8; + + // + // Fill in various fields in the control setup TD. + // The LinkPointer field will point to the control data TD if data will + // be sent/received or to the control status TD if no data is expected. + // The ControlStatus field will be set to active and interrupt on complete. + // The Token field will contain the packet size (size of DeviceRequest + // struc), the device address, endpoint, and a setup PID. + // The BufferPointer field will point to the TD's DataArea buffer which + // was just initialized to contain a DeviceRequest struc. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the UHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. + // + + // + // 11/01/10 for HI/LO/FULL + // + dValue = (((UINT32)fpDevInfo->bEndpointSpeed) & 1) << 26; + //(EIP34448)> + dValue |= (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); + //<(EIP34448) + + SetupTd->dControlStatus = dValue; + + dValue = dTemp | + ((UINT32)UHCI_TD_SETUP_PACKET | + ((UINT32)(sizeof(DEV_REQ) - 1) << 21)); + + // + // Set PID=Setup, and MaxLen + // + SetupTd->dToken = dValue; + SetupTd->pBufferPtr = (UINT32)(UINTN)SetupTd->aDataArea; + SetupTd->dCSReload = 0; + SetupTd->bActiveFlag = 1; + + LastTd = SetupTd; + // + // Fill in various fields in the control data TD. + // Enough control data TDs must be initialized to handle the amount of + // data expected. The length of the data transfer is currently in wLength. + // LinkPointer field will be set to the next data TD or the status TD. + // ControlStatus field will be se to active and interrupt on complete. + // Token field will contain the data transfer size (still in wLength), device + // address (in pDevInfo), endpoint (in dTemp), and an in or out PID + // (in wReqType). + // BufferPointer field will point to the data buffer passed in by the + // caller (currently in fpBuffer). + // CSReloadValue field will contain 0 because this is a "one shot" packet. + // pCallback will be set to point to the UHCI_ControlTDCallback routine. + // ActiveFlag field will be set to TRUE. + // + if(wLength) { + NumDataTDs = wLength / fpDevInfo->wEndp0MaxPacket; + if (wLength % fpDevInfo->wEndp0MaxPacket) { + NumDataTDs++; + } + + DataTDs = USB_MemAlloc(GET_MEM_BLK_COUNT(NumDataTDs * sizeof(UHCI_TD))); + if (DataTDs == NULL) { + USB_MemFree(SetupTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + return 0; + } + + CurrentTd = DataTDs; + + DataToggle = 1; + BytesRemaining = wLength; + + // + // Allocate one more TD to be used either for more data or for TD Status + // + do { + // + // 11/01/10 for HI/LO/FULL + // + dValue = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26); + dValue = dValue | + (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); + if(wRequest & BIT7) { + dValue |= UHCI_TD_SHORT_PACKET_DETECT; + } + CurrentTd->dControlStatus = dValue; + CurrentTd->pBufferPtr = (UINT32)(UINTN)fpBuffer; + wTemp = (UINT16)((BytesRemaining > (fpDevInfo->wEndp0MaxPacket)) ? + fpDevInfo->wEndp0MaxPacket : BytesRemaining); + // + // Packet size is valid + // + BytesRemaining = (UINT16)(BytesRemaining - wTemp); + fpBuffer = fpBuffer + wTemp; + --wTemp; + + // + // [18:8]=Dev. addr & endp + // + dValue = dTemp | (((UINT32)wTemp) << 21); + dValue = (dValue & 0xFFFFFF00) | UHCI_TD_OUT_PACKET; + + if(wRequest & BIT7) + { + dValue = (dValue & 0xFFFFFF00) | UHCI_TD_IN_PACKET; + } + if(DataToggle & 1) + { + dValue = dValue | UHCI_TD_DATA_TOGGLE; // Make packet into a data 1 + } + CurrentTd->dToken = dValue; + CurrentTd->dCSReload = 0; + CurrentTd->bActiveFlag = 1; + + LastTd->pLinkPtr = (UINT32)((UINTN)CurrentTd | UHCI_VERTICAL_FLAG); + LastTd = CurrentTd; + CurrentTd++; + + DataToggle ^= 1; + } while (BytesRemaining); // End the data TD list + } + // + // Fill in various fields in the TD control status. + // LinkPointer field will point to TERMINATE. + // ControlStatus field will be set to active and interrupt on complete. + // Token field will contain the packet size (0), the device address, + // endpoint, and a setup PID with opposite data direction as that defined + // in the request type (wReqType). + // BufferPointer field will point to the TD's DataArea buffer even though + // we are not expecting any data transfer. + // CSReloadValue field will contain 0 because this is a "one shot" packet. + // pCallback will be set to point to the UHCI_ControlTDCallback routine. + // ActiveFlag field will be set to TRUE. + // + StatusTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + if (StatusTd == NULL) { + return 0; + } + + LastTd->pLinkPtr = (UINT32)((UINTN)StatusTd | UHCI_VERTICAL_FLAG); + LastTd = StatusTd; + StatusTd->pLinkPtr = UHCI_TERMINATE; + dValue = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26); + //(EIP34448)> + dValue = dValue | (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); + //<(EIP34448) + StatusTd->dControlStatus = dValue; + dValue = dTemp; + dValue = (dValue & 0xFFFFFF00) | (UINT32)UHCI_TD_OUT_PACKET; + if((wRequest & BIT7) == 0) + { + dValue = (dValue & 0xFFFFFF00) | (UINT32)UHCI_TD_IN_PACKET; + } + dValue |= (UHCI_TD_DATA_TOGGLE | ((UINT32)UHCI_TD_ACTUAL_LENGTH << 21)); + StatusTd->dToken = dValue; + dValue = (UINT32)(UINTN)StatusTd->aDataArea; + StatusTd->pBufferPtr = dValue; + StatusTd->dCSReload = 0; + StatusTd->bActiveFlag = 1; + // + // Now put the control setup, data and status into the HC's schedule by + // pointing QhControl's link pointer to control setup TD. + // This will cause the HC to execute the transaction in the next active frame. + + CtrlQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + if (CtrlQh == NULL) { + return 0; + } + + UhciInitQh(CtrlQh); + CtrlQh->pElementPtr = (UINT32)(UINTN)SetupTd; + CtrlQh->CurrentTd = SetupTd; + CtrlQh->Type = Control; + CtrlQh->FirstTd = SetupTd; + + // Wait till transfer complete + BytesTransferred = UhciExecuteTransfer(fpHCStruc, CtrlQh); + + // Calculate the transferred length + BytesTransferred -= (((SetupTd->dControlStatus & UHCI_TD_ACTUAL_LENGTH) + 1) & 0x7FF); + + // Save error information in global variable + gUsbData->dLastCommandStatusExtended = + (CtrlQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; + + if (CtrlQh->CurrentTd->dControlStatus & UHCI_TD_STALLED ){ + gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; + BytesTransferred = 0; + } + + USB_MemFree(SetupTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + if (DataTDs) { + USB_MemFree(DataTDs, GET_MEM_BLK_COUNT(NumDataTDs * sizeof(UHCI_TD))); + } + USB_MemFree(StatusTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + USB_MemFree(CtrlQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + + return BytesTransferred; +} // UHCI_ControlTransfer + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_InitBulkTdCommon +// +// Description: +// This function creates a chain of two TDs for bulk data transfer. It fills +// in the following fields in TD: +// pLinkPtr - NextTd address +// dToken - All bits except length and data toggle +// +// Input: +// BulkDataTd0 1st TD in the chain +// BulkDataTd1 2nd TD in the chain +// TokenData Data for dToken +// NumBulkTds # of bulk TDs +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UHCI_InitBulkTdCommon ( + UHCI_TD *BulkDataTd0, + UINT32 TokenData, + UINT16 NumBulkTds +) +{ + UINT16 i; + UHCI_TD *Td0 = BulkDataTd0; + UHCI_TD *Td1 = Td0; + UINT16 NumTd = NumBulkTds*2; + + for (i=0; i<NumTd; i++) + { + Td0 = Td1; + Td0->dToken = TokenData; + Td1 = (UHCI_TD*)((UINTN)Td0 + sizeof(UHCI_TD)); + Td0->pLinkPtr = (UINT32)(UINTN)Td1 | UHCI_VERTICAL_FLAG; + } + // Terminated later in UHCI_InitBulkDataTds +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_InitBulkDataTds +// +// Description: +// This function initializes the fields in bulk data TD list that remain after +// UHCI_InitBulkTdCommon: +// - Data buffer pointer +// - Data length +// - Data toggle (DAT0/DAT1) +// +// Output: +// Pointer to the last TD in the chain +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UHCI_TD* +UHCI_InitBulkDataTds( + IN UHCI_TD *BulkDataTd, + IN UINT16 MaxPkt, + IN UINT32 EndpointSpeed, + IN OUT UINT32 *Address, + IN OUT UINT8 *DatToggle, + IN OUT UINT32 *BytesRemaining, + IN UINT16 NumBulkTds +) +{ + UINT16 i; + UINT32 Length = *BytesRemaining; + UHCI_TD *Td = BulkDataTd; + UINT32 Addr = *Address; + UINT8 Toggle = *DatToggle; + BOOLEAN TheLastTd = FALSE; + + for (i = 0; i < NumBulkTds; i++) + { + Length = *BytesRemaining; + + if (Length > (UINT32)MaxPkt) + { + Length = (UINT32)MaxPkt; + } + else + { + TheLastTd = TRUE; + } + Td->dToken &= 0x1FFFFF; + Td->dToken |= (Length - 1) << 21; + + Td->dToken &= ~UHCI_TD_DATA_TOGGLE; // Make packet go into DAT0 + if (Toggle == 1) + { + Td->dToken |= UHCI_TD_DATA_TOGGLE; // Make packet go into DAT1 + } + + Td->dControlStatus = EndpointSpeed | + (UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); + if ((Td->dToken & UHCI_TD_PACKET_ID) == UHCI_TD_IN_PACKET) { + Td->dControlStatus |= UHCI_TD_SHORT_PACKET_DETECT; + } + + Td->pBufferPtr = Addr; + Addr += MaxPkt; + Toggle ^= 1; + Td = (UHCI_TD*)((UINTN)Td + sizeof(UHCI_TD)); + *BytesRemaining -= Length; + + if (TheLastTd) break; + } + + Td = (UHCI_TD*)((UINTN)Td - sizeof(UHCI_TD)); + Td->pLinkPtr = UHCI_TERMINATE; + + *Address = Addr; + *DatToggle = Toggle; + + return Td; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_BulkTransfer +// +// 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.) +// +// Input: +// HcStruc Pointer to HCStruc of the host controller +// DevInfo DeviceInfo structure (if available else 0) +// XferDir Transfer direction +// Bit 7: Data direction +// 0 Host sending data to device +// 1 Device sending data to host +// Bit 6-0 : Reserved +// Buffer Buffer containing data to be sent to the device or buffer to be +// used to receive data value in Segment:Offset format +// Length 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 +UHCI_BulkTransfer ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 XferDir, + UINT8 *Buffer, + UINT32 Length +) +{ + UINT16 MaxPkt; + UINT8 Endp; + UINT32 Data; + UINT8 DatToggle; + UINT32 TransferError; + UHCI_QH *BulkQh; + UHCI_TD *BulkDataTd; + UHCI_TD *NextBulkDataTd; + UHCI_TD *BulkDataTd0; + UHCI_TD *BulkDataTd1; + UHCI_TD *LastTd; + UHCI_TD *NextLastTd; + UINT16 NumAllocTDs; + UINT16 NumBulkTDs; + UINT32 BytesRemaining; + UINT32 BytesTransferred; + UINT32 BytesTransferredNow; + UINT32 Address; + UINT32 Eps; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Buffer, Length); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Uhci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (UhciIsHalted(HcStruc)) { + return 0; + } + + if ( !VALID_DEVINFO( DevInfo) ) return 0; + + if (Length == 0) return 0; + + // Clear HW source of error + gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED | USB_BULK_TIMEDOUT ); + gUsbData->dLastCommandStatusExtended = 0; + // + // Get Bulk IN/OUT enpoint number, data sync value & max packet size + // Store the appropriate max packet size and endpoint number + // in the local variables + // + MaxPkt = (XferDir & BIT7)? DevInfo->wBulkInMaxPkt : DevInfo->wBulkOutMaxPkt; + + if (MaxPkt == 0) return 0; + + Endp = (XferDir & BIT7)? DevInfo->bBulkInEndpoint : DevInfo->bBulkOutEndpoint; + + // + // For multiple LUN devices toggle is maintained by LUN0 + // + DatToggle = UsbGetDataToggle(DevInfo, Endp | XferDir); + + // + // Form TD token data, less the transfer length and toggle information + // + Data = (UINT32)Endp << 7; + Data = (Data | DevInfo->bDeviceAddress) << 8; + Data = (XferDir & BIT7)? Data | UHCI_TD_IN_PACKET : Data | UHCI_TD_OUT_PACKET; + + BulkQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + if (BulkQh == NULL) return 0; + + BulkQh->Type = Bulk; + + // Allocate data TDs. + NumBulkTDs = FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME/MaxPkt; + ASSERT(NumBulkTDs != 0); + + NumAllocTDs = NumBulkTDs*2; + + BulkDataTd0 = (UHCI_TD*)USB_MemAlloc(GET_MEM_BLK_COUNT(NumAllocTDs * sizeof(UHCI_TD))); + ASSERT(BulkDataTd0 != NULL); + + UHCI_InitBulkTdCommon (BulkDataTd0, Data, NumBulkTDs); + + BulkDataTd1 = (UHCI_TD*)((UINTN)BulkDataTd0 + (NumBulkTDs * sizeof(UHCI_TD))); + + BulkDataTd = BulkDataTd0; + NextBulkDataTd = BulkDataTd1; + BytesRemaining = Length; + BytesTransferred = 0; + BytesTransferredNow = 0; + Address = (UINT32)(UINTN)Buffer; + TransferError = 0; + Eps = ((UINT32)(DevInfo->bEndpointSpeed) & 1) << 26; + + LastTd = UHCI_InitBulkDataTds( + BulkDataTd, MaxPkt, Eps, &Address, &DatToggle, &BytesRemaining, NumBulkTDs); + NextLastTd = LastTd; + + do { + // Start the transfer by adding TD in the bulk queue head + UhciInitQh(BulkQh); + BulkQh->pElementPtr = (UINT32)(UINTN)BulkDataTd; + BulkQh->CurrentTd = BulkDataTd; + BulkQh->FirstTd = BulkDataTd; + + // Initialize the next TD block and wait for the current one to complete. + // In case MaxPkt is 64 Bytes, we have approx. NumBulkTDs*50mcs for this. + if (BytesRemaining != 0) { + NextLastTd = UHCI_InitBulkDataTds( + NextBulkDataTd, MaxPkt, Eps, &Address, &DatToggle, &BytesRemaining, NumBulkTDs); + } + + // Wait til BulkDataTd is complete, check for errors + BytesTransferredNow = UhciExecuteTransfer(HcStruc, BulkQh); + + DatToggle = BulkQh->DataToggle; + TransferError = (BulkQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; + if (TransferError) { + break; + } + BytesTransferred += BytesTransferredNow; + + NextBulkDataTd = BulkDataTd; + LastTd = NextLastTd; + BulkDataTd = (BulkDataTd == BulkDataTd0)? BulkDataTd1 : BulkDataTd0; + + } while ((BytesTransferred < Length) && !BulkQh->ShortPacketDetected); + + UsbUpdateDataToggle(DevInfo, Endp | XferDir, DatToggle); + gUsbData->dLastCommandStatusExtended = TransferError; + if (BulkQh->CurrentTd->dControlStatus & UHCI_TD_STALLED){ + gUsbData->bLastCommandStatus |= USB_BULK_STALLED; + } + if (BulkQh->CurrentTd->dControlStatus & UHCI_TD_ACTIVE) { + gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; + } + // + // Deallocate memory and return the transferred data size + // + USB_MemFree(BulkDataTd0, GET_MEM_BLK_COUNT(NumAllocTDs * sizeof(UHCI_TD))); + USB_MemFree(BulkQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + + return BytesTransferred; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_InterruptTransfer +// +// Description: +// This function executes an interrupt transaction on the USB. The data transfer +// direction is always DATA_IN. This function wil not return until the request +// either completes successfully or completes in error (due to time out, etc.) +// +// Input: +// fpHCStruc Pointer to HCStruc of the host controller +// fpDevInfo DeviceInfo structure (if available else 0) +// EndpointAddress The destination USB device endpoint to which the device request +// is being sent. +// MaxPktSize Indicates the maximum packet size the target endpoint is capable +// of sending or receiving. +// 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 +// +// Output: +// Number of bytes transferred +// +// +// Notes: +// DO NOT TOUCH THE LINK POINTER OF THE TDInterruptData. It is statically allocated +// and linked with other items in the 1ms schedule +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +UHCI_InterruptTransfer( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT8 bEndp; + UINT8 DataToggle; + UINT32 dTemp, dValue; + UHCI_QH *IntQh; + UHCI_TD *IntTd; + UINT32 BytesTransferred; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Uhci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (UhciIsHalted(fpHCStruc)) { + return 0; + } + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + + gUsbData->dLastCommandStatusExtended = 0; + + // + // Check for 0 length transfer (if so, exit) + // + if(wLength == 0) { + return 0; + } + + // + // Store the descriptor pointer in a local variable + // + IntTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + if (IntTd == NULL) { + return 0; + } + + IntTd->pLinkPtr = UHCI_TERMINATE; + + // + // It is an interrupt IN transaction get appropriate size + // + bEndp = EndpointAddress & 0xF; + DataToggle = UsbGetDataToggle(fpDevInfo, EndpointAddress); + + // + // Form device address and endpoint in proper order and bit position + // + dTemp = (UINT32)bEndp << 7; + dTemp = (dTemp | (fpDevInfo->bDeviceAddress)) << 8; //[10:0] = Dev. Addr & Endpoint + //[18:8] = Dev. Addr & Endpoint + // + // Fill in various fields in the interrupt data TD + // + IntTd->dControlStatus = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26) | + UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE; + // + // Set the buffer pointer. Note that currently UHCI Interrupt Transfer + // implementation assumes IN packet; the direction is not passed here as + // parameter. Should this change in future, make a branch to use + // UHCI_TD_OUT_PACKET while constructing dToken. + // + IntTd->pBufferPtr = (UINT32)(UINTN)fpBuffer; + dValue = (UINT32)(wLength - 1); + dValue = ((dValue << 21) | dTemp) & 0xffffff00; + dValue |= EndpointAddress & BIT7 ? UHCI_TD_IN_PACKET : + UHCI_TD_OUT_PACKET; + + if(DataToggle & 1) { + dValue |= UHCI_TD_DATA_TOGGLE; // Make packet into a data 1 + } + + IntTd->dToken = dValue; + IntTd->dCSReload = 0; + IntTd->bActiveFlag = 1; + + IntQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + if (IntQh == NULL) { + return 0; + } + + UhciInitQh(IntQh); + IntQh->pElementPtr = (UINT32)(UINTN)IntTd; + IntQh->CurrentTd = IntTd; + IntQh->Type = Interrupt; + IntQh->FirstTd = IntTd; + IntQh->Interval = UhciTranslateInterval(fpDevInfo->bPollInterval); + + BytesTransferred = UhciExecuteTransfer(fpHCStruc, IntQh); + + gUsbData->dLastCommandStatusExtended = + (IntQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; + + UsbUpdateDataToggle(fpDevInfo, EndpointAddress, IntQh->DataToggle); + + USB_MemFree(IntTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); + USB_MemFree(IntQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + + return (UINT16)BytesTransferred; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_DeactivatePolling +// +// Description: +// This function de-activates the polling TD for the requested device. The +// device may be a USB keyboard or USB hub +// +// Input: +// fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_DeactivatePolling ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo +) +{ + UHCI_QH *PollQh; + UINT8 DataToggle; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + if (DevInfo->fpPollTDPtr == NULL) { + return USB_ERROR; + } + + PollQh = (UHCI_QH*)DevInfo->fpPollTDPtr; + + UhciRemoveQhFromFrameList(HcStruc, PollQh); + + DataToggle = (PollQh->FirstTd->dToken & UHCI_TD_DATA_TOGGLE)? 1 : 0; + if (!(PollQh->FirstTd->dControlStatus & UHCI_TD_STATUS_FIELD)) { + UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, DataToggle ^ 1); + } + + UhciFreeTds(PollQh->FirstTd); + USB_MemFree(PollQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + DevInfo->fpPollTDPtr = NULL; + + if (DevInfo->fpPollDataBuffer) { + USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + DevInfo->fpPollDataBuffer = NULL; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_ActivatePolling +// +// Description: +// This function activates the polling TD for the requested device. The device +// may be a USB keyboard or USB hub +// +// Input: +// fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +// Notes: +// For the keyboard device this routine allocates TDRepeat also, if it is not +// already allocated. This routine allocate a polling TD and schedule it to 8ms +// schedule for keyboards and to 1024ms schedule for hubs. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_ActivatePolling ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo) +{ + UHCI_TD *PollTd; + UHCI_QH *PollQh; + BOOLEAN LowSpeed; + UINT8 PacketId; + UINTN BufferAddr; + UINT32 DataLen; + UINT8 DataToggle; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + if( !VALID_DEVINFO(DevInfo) ) + return USB_ERROR; + + DevInfo->fpPollDataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + if (DevInfo->fpPollDataBuffer == NULL) { + return USB_ERROR; + } + + LowSpeed = (DevInfo->bEndpointSpeed & 1) != 0; + PacketId = DevInfo->IntInEndpoint & BIT7 ? UHCI_TD_IN_PACKET : UHCI_TD_OUT_PACKET; + BufferAddr = (UINTN)DevInfo->fpPollDataBuffer; + DataLen = DevInfo->PollingLength; + DataToggle = UsbGetDataToggle(DevInfo, DevInfo->IntInEndpoint); + + PollTd = UhciAllocGeneralTds(DevInfo->bDeviceAddress, LowSpeed, PacketId, + DevInfo->IntInEndpoint & 0xF, DevInfo->IntInMaxPkt, TRUE, + &BufferAddr, &DataLen, &DataToggle); + if (PollTd == NULL) { + USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + return USB_ERROR; + } + + PollQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); + if (PollQh == NULL) { + USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + UhciFreeTds(PollTd); + return USB_ERROR; + } + + DevInfo->fpPollTDPtr = (UINT8*)PollQh; + + UhciInitQh(PollQh); + PollQh->pElementPtr = (UINT32)(UINTN)PollTd; + PollQh->CurrentTd = PollTd; + PollQh->Type = Interrupt; + PollQh->FirstTd = PollTd; + PollQh->Interval = UhciTranslateInterval(DevInfo->bPollInterval); + PollQh->CallBackIndex = USB_InstallCallBackFunction(UhciPollingQhCallback); + PollQh->DevInfoPtr = DevInfo; + PollQh->ActiveFlag = TRUE; + + UhciAddQhToFrameList(HcStruc, PollQh); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_DisableKeyRepeat +// +// Description: +// This function disables the keyboard repeat rate logic +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_DisableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + UHCI_DESC_PTRS *UhicDescPtrs; + UHCI_QH *Qh; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + UhicDescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; + + if (UhicDescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)UhicDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(UhicDescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + Qh = UhicDescPtrs->RepeatQh; + + if (Qh == NULL) { + return USB_ERROR; + } + + if (((UINT8*)Qh < gUsbData->fpMemBlockStart) || + ((UINT8*)(Qh + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)Qh->FirstTd < gUsbData->fpMemBlockStart) || + ((UINT8*)(Qh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + Qh->FirstTd->dCSReload = UHCI_TD_ONE_ERROR; + Qh->FirstTd->dControlStatus= UHCI_TD_ONE_ERROR; + Qh->FirstTd->bActiveFlag = 0; + Qh->ActiveFlag = FALSE; + Qh->pElementPtr = UHCI_TERMINATE; + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_EnableKeyRepeat +// +// Description: +// This function enables the keyboard repeat rate logic +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_EnableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + UHCI_DESC_PTRS *UhicDescPtrs; + UHCI_QH *Qh; + EFI_STATUS EfiStatus; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (UhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + UhicDescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; + + if (UhicDescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)UhicDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(UhicDescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + Qh = UhicDescPtrs->RepeatQh; + + if (((UINT8*)Qh < gUsbData->fpMemBlockStart) || + ((UINT8*)(Qh + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)Qh->FirstTd < gUsbData->fpMemBlockStart) || + ((UINT8*)(Qh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + Qh->FirstTd->dCSReload = (UHCI_TD_INTERRUPT_ON_COMPLETE | + UHCI_TD_ONE_ERROR | UHCI_TD_ACTIVE); + Qh->FirstTd->dControlStatus = Qh->FirstTd->dCSReload; + Qh->FirstTd->bActiveFlag = 1; + Qh->pElementPtr = (UINT32)(UINTN)Qh->FirstTd; + Qh->CurrentTd = Qh->FirstTd; + Qh->ActiveFlag = TRUE; + + return USB_SUCCESS; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_DisableHCPorts (fpHCStruc) +// +// Description: +// This routine disables the UHCI HC root hub ports +// +// Input: +// fpHCStruc Ptr to the host controller structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_DisableHCPorts (HC_STRUC* fpHCStruc) +{ + UINT16 wIOAddr = (UINT16)fpHCStruc->BaseAddress; + + // + // Disable the root hub port 1 + // + ByteWriteIO((UINT16)(wIOAddr+UHCI_PORT1_CONTROL), + (UINT8)(ByteReadIO( + (UINT16)(wIOAddr+UHCI_PORT1_CONTROL)) & (~UHC_PORT_ENABLE))); + // + // Disable the root hub port 2 + // + ByteWriteIO((UINT16)(wIOAddr+UHCI_PORT2_CONTROL), + (UINT8)(ByteReadIO( + (UINT16)(wIOAddr+UHCI_PORT2_CONTROL)) & (~UHC_PORT_ENABLE))); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciAddQhToFrameList +// +// Description: +// This routine will add the particular QH into the frame list +// +// Input: +// HcStruc Pointerr to the host controller structure +// NewQh Address of the QH to be linked +// +// Output: +// USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciAddQhToFrameList ( + HC_STRUC *HcStruc, + UHCI_QH *NewQh +) +{ + UINT16 Index; + UINT32 *PrevPtr; + UINT32 LinkPtr; + UHCI_QH *Qh; + BOOLEAN ByInterval = FALSE; + EFI_STATUS Status = EFI_SUCCESS; + + if (NewQh == NULL) { + return USB_ERROR; + } + + switch (NewQh->Type) { + case Control: + case Bulk: + ByInterval = FALSE; + break; + case Interrupt: + ByInterval = TRUE; + break; + case Isochronous: + ASSERT(FALSE); + default: + return USB_ERROR; + } + + if (ByInterval && NewQh->Interval == 0) { + return USB_ERROR; + } + + for (Index = 0; Index < HcStruc->wAsyncListSize; + ByInterval ? Index += NewQh->Interval : Index++) { + PrevPtr = &HcStruc->fpFrameList[Index]; + LinkPtr = *PrevPtr; + + while (!(LinkPtr & UHCI_TERMINATE)) { + Qh = (UHCI_QH*)(LinkPtr & UHCI_POINTER_MASK); +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(UHCI_QH)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Qh->Type <= NewQh->Type) { + if (ByInterval == FALSE || + Qh->Interval <= NewQh->Interval) { + break; + } + } + PrevPtr = &Qh->pLinkPtr; + LinkPtr = *PrevPtr; + } + if (Qh == NewQh) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + NewQh->pLinkPtr = *PrevPtr; + *PrevPtr = (UINT32)((UINTN)NewQh | UHCI_QUEUE_HEAD); + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciRemoveQhFromFrameList +// +// Description: +// This routine will remove a QH from the the frame list +// +// Input: +// HcStruc Pointerr to the host controller structure +// RetiredQh Address of the QH to be removed +// +// Output: +// USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciRemoveQhFromFrameList ( + HC_STRUC *HcStruc, + UHCI_QH *RetiredQh +) +{ + UINT16 Index; + UINT32 *PrevPtr; + UINT32 LinkPtr; + UHCI_QH *Qh; + BOOLEAN ByInterval = FALSE; + EFI_STATUS Status = EFI_SUCCESS; + + if (RetiredQh == NULL) { + return USB_ERROR; + } + + switch (RetiredQh->Type) { + case Control: + case Bulk: + ByInterval = FALSE; + break; + case Interrupt: + ByInterval = TRUE; + break; + case Isochronous: + ASSERT(FALSE); + default: + return USB_ERROR; + } + + if (ByInterval && RetiredQh->Interval == 0) { + return USB_ERROR; + } + + RetiredQh->pElementPtr = UHCI_TERMINATE; + + for (Index = 0; Index < HcStruc->wAsyncListSize; + ByInterval ? Index += RetiredQh->Interval : Index++) { + PrevPtr = &HcStruc->fpFrameList[Index]; + LinkPtr = *PrevPtr; + + while (!(LinkPtr & UHCI_TERMINATE)) { + Qh = (UHCI_QH*)(LinkPtr & UHCI_POINTER_MASK); +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(UHCI_QH)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Qh == RetiredQh) { + break; + } + PrevPtr = &Qh->pLinkPtr; + LinkPtr = *PrevPtr; + } + + if (LinkPtr & UHCI_TERMINATE) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = RetiredQh->pLinkPtr; + } + + RetiredQh->pLinkPtr = UHCI_TERMINATE; + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_StartTDSchedule (fpHCStruc) +// +// Description: +// This routine will start the TD schedule for the UHCI controller. After this +// routine TD's can be scheduled for execution. +// +// Input: +// fpHCStruc Pointer to the HC information structure +// +// Output: +// USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_StartTDSchedule ( + HC_STRUC *HcStruc +) +{ + UHCI_DESC_PTRS *DescPtr; + UHCI_TD *Td; + + // + // Allocate the UHCI descriptor pointer structure + // + DescPtr = (UHCI_DESC_PTRS*) USB_MemAlloc (GET_MEM_BLK_COUNT_STRUC(UHCI_DESC_PTRS)); + if (DescPtr == NULL) { + USB_DEBUG(DEBUG_LEVEL_4, "UHCI Descriptor struc alloc failed.\n"); + return USB_ERROR; + } + + // + // Save the value in the HC struc + // + HcStruc->stDescPtrs.fpUHCIDescPtrs = DescPtr; + + DescPtr->StaticQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH))); + if (DescPtr->StaticQh == NULL) { + return USB_ERROR; + } + + UhciInitQh(DescPtr->StaticQh); + DescPtr->StaticQh->Type = Interrupt; + DescPtr->StaticQh->Interval = 1; + UhciAddQhToFrameList(HcStruc, DescPtr->StaticQh); + + if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { + return USB_SUCCESS; + } + + DescPtr->RepeatQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH) + + 1 * sizeof(UHCI_TD))); + if(DescPtr->RepeatQh == NULL) { + return USB_ERROR; + } + + Td = (UHCI_TD*)((UINTN)DescPtr->RepeatQh + sizeof (UHCI_QH)); + + // + // Initialize the body of TdRepeat. It will run a interrupt transaction + // to a non-existant dummy device. This will have the effect of generating + // a periodic interrupt used to generate keyboard repeat. This TD is normally + // inactive, and is only activated when a key is pressed. TdRepeat will be + // set to timeout after two attempts. Since the TD is in the schedule + // at 16ms intervals, this will generate an interrupt at intervals of 32ms + // (when the TD is active). This 32ms periodic interrupt may then + // approximate the fastest keyboard repeat rate of 30 characters per second. + // + Td->pLinkPtr = UHCI_TERMINATE; + Td->dControlStatus = UHCI_TD_ONE_ERROR; + Td->dToken = (UHCI_TD_IN_PACKET | + ((UINT32)DUMMY_DEVICE_ADDR << 8) | + ((UINT32)(DEFAULT_PACKET_LENGTH - 1) << 21)); + Td->pBufferPtr = (UINT32)(UINTN)Td->aDataArea; + Td->dCSReload = UHCI_TD_ONE_ERROR; + Td->bActiveFlag = 0; + + UhciInitQh(DescPtr->RepeatQh); + DescPtr->RepeatQh->Type = Interrupt; + DescPtr->RepeatQh->FirstTd = Td; + DescPtr->RepeatQh->Interval = REPEAT_INTERVAL; + DescPtr->RepeatQh->CallBackIndex = USB_InstallCallBackFunction(UhciRepeatQhCallback); + DescPtr->RepeatQh->ActiveFlag = FALSE; + + // + // Schedule the TDRepeat to 8ms schedule + // + UhciAddQhToFrameList(HcStruc, DescPtr->RepeatQh); + + // + // Inform the common code that key repeat is implemented + // + USBKeyRepeat(HcStruc, 0); + + // + // Initialize the body of root hub TD. It will run a interrupt + // transaction to a nonexistent dummy device. This will have the effect + // of generating a periodic interrupt for the purpose of checking for + // attach/detach on the root hub's ports + // This initialization is done only once for the first HC + // + DescPtr->RootHubQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH) + + 1 * sizeof(UHCI_TD))); + ASSERT(DescPtr->RootHubQh != NULL); + if (DescPtr->RootHubQh == NULL) { + return USB_ERROR; + } + + Td = (UHCI_TD*)((UINTN)DescPtr->RootHubQh + sizeof (UHCI_QH)); + + Td->pLinkPtr = UHCI_TERMINATE; + Td->dControlStatus = 0; + Td->dToken = + (UHCI_TD_IN_PACKET | ((UINT32)DUMMY_DEVICE_ADDR << 8) | + ((UINT32)(DEFAULT_PACKET_LENGTH - 1) << 21)); + Td->pBufferPtr = (UINT32)(UINTN)Td->aDataArea; + Td->dCSReload = 0; + Td->bActiveFlag = 0; + + UhciInitQh(DescPtr->RootHubQh); + DescPtr->RootHubQh->Type = Interrupt; + DescPtr->RootHubQh->FirstTd = Td; + DescPtr->RootHubQh->Interval = 128; + DescPtr->RootHubQh->CallBackIndex = USB_InstallCallBackFunction(UhciRootHubQhCallBack); + DescPtr->RootHubQh->ActiveFlag = FALSE; + + // + // Schedule the root hub TD to 256ms schedule + // + UhciAddQhToFrameList(HcStruc, DescPtr->RootHubQh); + + if (gUsbData->RootHubHcStruc == NULL) { + Td->dCSReload = + UHCI_TD_INTERRUPT_ON_COMPLETE | + UHCI_TD_ONE_ERROR | + UHCI_TD_ACTIVE; + Td->bActiveFlag = 1; + Td->dControlStatus = Td->dCSReload; + DescPtr->RootHubQh->pElementPtr = (UINT32)(UINTN)Td; + DescPtr->RootHubQh->CurrentTd = Td; + DescPtr->RootHubQh->ActiveFlag = TRUE;; + gUsbData->RootHubHcStruc = HcStruc; + } + + USB_DEBUG(DEBUG_LEVEL_4, "TD's are scheduled\n"); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_StopTDSchedule (fpHCStruc) +// +// Description: +// This routine will stop the TD schedules and frees the data structures +// +// Input: +// fpHCStruc Pointer to the HC information structure +// +// Output: +// USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UHCI_StopTDSchedule ( + HC_STRUC *HcStruc +) +{ + UINT8 i; + UHCI_DESC_PTRS *DescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + // + // Free all the TD/QH data structures + // + if (DescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->StaticQh < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->StaticQh + sizeof(UHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->RootHubQh < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->RootHubQh + sizeof(UHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->RepeatQh < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->RepeatQh + sizeof(UHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } + + USB_MemFree (DescPtrs->StaticQh, GET_MEM_BLK_COUNT(sizeof(UHCI_QH))); + if (DescPtrs->RootHubQh) { + USB_MemFree (DescPtrs->RootHubQh, + GET_MEM_BLK_COUNT(sizeof(UHCI_QH) + sizeof(UHCI_TD))); + } + if (DescPtrs->RepeatQh) { + USB_MemFree (DescPtrs->RepeatQh, + GET_MEM_BLK_COUNT(sizeof(UHCI_QH) + sizeof(UHCI_TD))); + } + + // + // Finally free the descriptor pointer + // + USB_MemFree (DescPtrs, GET_MEM_BLK_COUNT_STRUC(UHCI_DESC_PTRS)); + + USBKeyRepeat(HcStruc, 3); + + if (gUsbData->RootHubHcStruc == HcStruc) { + gUsbData->RootHubHcStruc = NULL; + for (i = 0; i < gUsbData->HcTableCount; i++) { + if (gUsbData->HcTable[i] == NULL) { + continue; + } + if ((gUsbData->HcTable[i]->bHCNumber) && + (gUsbData->HcTable[i]->bHCType == USB_HC_UHCI) && + (gUsbData->HcTable[i]->dHCFlag & HC_STATE_RUNNING) && + (HcStruc != gUsbData->HcTable[i])) { + + DescPtrs = gUsbData->HcTable[i]->stDescPtrs.fpUHCIDescPtrs; + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + if (((UINT8*)DescPtrs->RootHubQh < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->RootHubQh + sizeof(UHCI_QH)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->RootHubQh->FirstTd < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->RootHubQh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->RootHubQh->CurrentTd < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->RootHubQh->CurrentTd + sizeof(UHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->RootHubQh->FirstTd->dCSReload = + UHCI_TD_INTERRUPT_ON_COMPLETE | + UHCI_TD_ONE_ERROR | + UHCI_TD_ACTIVE; + DescPtrs->RootHubQh->FirstTd->bActiveFlag = 1; + DescPtrs->RootHubQh->FirstTd->dControlStatus = + DescPtrs->RootHubQh->FirstTd->dCSReload; + DescPtrs->RootHubQh->pElementPtr = + (UINT32)(UINTN)DescPtrs->RootHubQh->FirstTd; + DescPtrs->RootHubQh->CurrentTd = + DescPtrs->RootHubQh->FirstTd; + DescPtrs->RootHubQh->ActiveFlag = TRUE;; + gUsbData->RootHubHcStruc = gUsbData->HcTable[i]; + } + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciProcessQh +// +// Description: +// This function will check whether the QH is completed if so, it will call +// the call back routine associated with the TDs present in the QH +// +// Input: +// HcStruc HCStruc structure +// Qh Pointer to the QH +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciProcessQh( + HC_STRUC *HcStruc, + UHCI_QH *Qh +) +{ + UHCI_TD *Td; + UINT16 Length; + EFI_STATUS Status; + + if (Qh == NULL) { + return USB_ERROR; + } + + if (Qh->ActiveFlag == FALSE) { + return USB_SUCCESS; + } + + if (Qh->FirstTd == NULL) { + return USB_SUCCESS; + } + + if (Qh->CurrentTd == NULL) { + Qh->CurrentTd = Qh->FirstTd; + } + + Td = Qh->CurrentTd; + while (Td) { + Qh->CurrentTd = Td; + Qh->DataToggle = Td->dToken & UHCI_TD_DATA_TOGGLE ? 1 : 0; + + if (Td->dControlStatus & UHCI_TD_ACTIVE) { + return USB_ERROR; + } + + Length = (UINT16)((Td->dControlStatus + 1) & UHCI_TD_ACTUAL_LENGTH); + Qh->BytesTransferred += Length; + + if (Td->dControlStatus & UHCI_TD_STATUS_FIELD) { + break; + } + + Qh->DataToggle ^= 1; + Qh->ShortPacketDetected = (Length < (((Td->dToken >> 21) + 1) & 0x7FF)); + + if (Qh->ShortPacketDetected) { + if (Qh->Type == Control) { + while (!(Td->pLinkPtr & UHCI_TERMINATE)) { + Td = (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); + } + Qh->pElementPtr = (UINT32)(UINTN)Td; + continue; + } + break; + } + + Td = Td->pLinkPtr & UHCI_TERMINATE ? + NULL : (UHCI_TD*)(Td->pLinkPtr & UHCI_POINTER_MASK); + } + + Qh->ActiveFlag = FALSE; + if (Qh->CallBackIndex == 0) { + return USB_SUCCESS; + } + + if ((Qh->CallBackIndex) && (Qh->CallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1]) { + if ((gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1] != UhciRepeatQhCallback) && + (gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1] != UhciRootHubQhCallBack)) { + Status = UsbDevInfoValidation(Qh->DevInfoPtr); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } + } + (*gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1])( + HcStruc, + (DEV_INFO*)Qh->DevInfoPtr, + (UINT8*)Qh, + 0, + 0); + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciProcessTd +// +// Description: +// This function will check whether the TD is completed if so, it will call +// the call back routine associated with this TD +// +// Input: +// HcStruc HCStruc structure +// Td Pointer to the TD +// +// Output: +// USB_SUCCESS or USB_ERROR +// +// Notes: +// For any TD whose ActiveFlag is TRUE and its ControlStatus bit 23 is clear +// (completed), process the TD by calling its callback routine, if one is present. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciProcessTd( + HC_STRUC *HcStruc, + UHCI_TD *Td +) +{ + UINT8 DevAddr; + DEV_INFO *DevInfo; + + if (Td == NULL) { // Check for NULL + return USB_ERROR; + } + + if (Td->bActiveFlag == 0) { + return USB_SUCCESS; + } + + if (Td->dControlStatus & UHCI_TD_ACTIVE) { + return USB_ERROR; + } + + Td->bActiveFlag = 0; + if ((Td->bCallBackIndex) && (Td->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + // + // Get the device address from the completed TD + // + DevAddr = (UINT8)(((Td->dToken) >> 8) & 0x7F); + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, 0, + DevAddr, HcStruc); + + if (gUsbData->aCallBackFunctionTable[Td->bCallBackIndex - 1]) { + (*gUsbData->aCallBackFunctionTable[Td->bCallBackIndex - 1])( + HcStruc, + DevInfo, + (UINT8*)Td, + 0, + 0); + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UhciProcessFrameList +// +// Description: +// This function will parse through frame list to find completed QH/TD +// and invoke corresponding call back routine +// +// Input: +// HcStruc HCStruc structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +// Notes: +// For any TD whose ActiveFlag is TRUE and its ControlStatus bit 23 is clear +// (completed), process the TD by calling its call back routine, if one is present. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciProcessFrameList ( + HC_STRUC *HcStruc +) +{ + UINT32 ListPtr; + EFI_STATUS Status = EFI_SUCCESS; + + ListPtr = HcStruc->fpFrameList[0]; + + while (!(ListPtr & UHCI_TERMINATE)) { + if (ListPtr & UHCI_QUEUE_HEAD) { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)ListPtr, sizeof(UHCI_QH)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + UhciProcessQh(HcStruc, (UHCI_QH*)(ListPtr & UHCI_POINTER_MASK)); + ListPtr = ((UHCI_QH*)(ListPtr & UHCI_POINTER_MASK))->pLinkPtr; + } else { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)ListPtr, sizeof(UHCI_TD)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + UhciProcessTd(HcStruc, (UHCI_TD*)(ListPtr & UHCI_POINTER_MASK)); + ListPtr = ((UHCI_TD*)(ListPtr & UHCI_POINTER_MASK))->pLinkPtr; + } + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_RootHubTDCallBack +// +// Description: +// This function is called when TD256ms completes a transaction. This TD runs +// a dummy interrupt transaction to a non-existant device address for the +// purpose of generating a periodic timeout interrupt. This periodic interrupt +// may be used to check for new devices on the root hub etc. +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciRootHubQhCallBack( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Qh, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UINT8 Index; + HC_STRUC *Hc; + UINT16 IoPort; + UINT16 PortAddr; + UHCI_QH *RootHubQh; + + // + // First deactivate the TDRootHub so this callback function will not get + // reentered. + // + if (Qh != NULL) { + RootHubQh = (UHCI_QH*)Qh; + RootHubQh->FirstTd->bActiveFlag = 0; + } + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + Hc = gUsbData->HcTable[Index]; + if (Hc == NULL) { + continue; + } + + if (Hc->bHCType != USB_HC_UHCI) { // Process for UHCI only + continue; + } + + if (!(Hc->dHCFlag & HC_STATE_RUNNING)) { + continue; + } + + // + // Check whether the controller is still under BIOS control + // Read the frame list base address and compare with stored value + // + IoPort = (UINT16)Hc->BaseAddress; + if ((DwordReadIO(IoPort + UHCI_FRAME_LIST_BASE) & 0xFFFFF000) + != (UINT32)Hc->fpFrameList) { + continue; + } + + // + // Check whether USB host controllers are accessible to aVOID system + // hang in ports enumeration. + // + if (ByteReadIO(IoPort) == 0xFF) { + continue; + } + + // + // Check whether enumeration is already began + // + if(gUsbData->bEnumFlag == FALSE) { + gUsbData->bEnumFlag = TRUE; + + // + // Mask the Host Controller interrupt so the ISR does not get re-entered due + // to an IOC interrupt from any TDs that complete in frames while we are + // configuring a new device that has just been plugged in. + // + // Disable IOC, timeout & CRC interrupt + // + WordWriteIO((UINT16)(IoPort + UHCI_INTERRUPT_ENABLE), 0); + + // + // Process Port#1 and clear Port#1 status bit + // + PortAddr = IoPort + UHCI_PORT1_CONTROL; + if (WordReadIO(PortAddr) & UHC_CONNECT_STATUS_CHANGE) { + USBCheckPortChange(Hc, Hc->bHCNumber | BIT7, 1); + WordWriteIO(PortAddr, WordReadIO(PortAddr)); + } + + // + // Process Port#2 and clear Port#2 status bit + // + PortAddr = IoPort + UHCI_PORT2_CONTROL; + if (WordReadIO(PortAddr) & UHC_CONNECT_STATUS_CHANGE) { + USBCheckPortChange(Hc, Hc->bHCNumber | BIT7, 2); + WordWriteIO(PortAddr, WordReadIO(PortAddr)); + } + + // + // Renable interrupts from the host controller + // Enable IOC, timeout & CRC interrupt + // + WordWriteIO((UINT16)(IoPort + UHCI_INTERRUPT_ENABLE), (UINT16)(UHC_IOC_ENABLE)); + + gUsbData->bEnumFlag = FALSE; + } + } + + // + // Reactivate the TdRootHub + // + if (Qh != NULL) { + RootHubQh->FirstTd->dControlStatus = RootHubQh->FirstTd->dCSReload; + RootHubQh->FirstTd->bActiveFlag = 1; + RootHubQh->pElementPtr = (UINT32)(UINTN)RootHubQh->FirstTd; + RootHubQh->CurrentTd = RootHubQh->FirstTd; + RootHubQh->ActiveFlag = TRUE; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_RepeatTDCallback +// +// Description: +// This function is called when TdRepeat completes a transaction. This TD +// runs a dummy interrupt transaction to a non-existant device address for +// the purpose of generating a periodic timeout interrupt which in turn is +// used to generate keyboard repeat. +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciRepeatQhCallback( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Qh, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UHCI_QH *RepeatQh = (UHCI_QH*)Qh; + + USB_DEBUG(DEBUG_LEVEL_8, "Processing Repeat TD ...\n"); + // + // First deactivate the TdRepeat so this callback function will not get + // re-entered. + // + RepeatQh->FirstTd->bActiveFlag = 0; + +#if USB_DEV_KBD + USBKBDPeriodicInterruptHandler(HcStruc); +#endif + // + // Reactivate the TdRepeat + // + if (RepeatQh->FirstTd->dCSReload & UHCI_TD_ACTIVE) { + RepeatQh->FirstTd->dControlStatus = RepeatQh->FirstTd->dCSReload; + RepeatQh->FirstTd->bActiveFlag = 1; + RepeatQh->pElementPtr = (UINT32)(UINTN)RepeatQh->FirstTd; + RepeatQh->CurrentTd = RepeatQh->FirstTd; + RepeatQh->ActiveFlag = TRUE; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UHCI_PollingTDCallback +// +// Description: +// This function is called when a polling TD from the TD pool completes an +// interrupt transaction to its assigned device. +// This routine should process any data in the TD's data buffer, handle any +// errors, and then copy the TD's CSReloadValue field into its control status +// field to put the TD back into service. +// +// Input: +// fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciPollingQhCallback( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Qh, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UHCI_QH *PollQh = (UHCI_QH*)Qh; + + USB_DEBUG(DEBUG_LEVEL_8, "Processing polling TD ...\n"); + + UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, + PollQh->DataToggle); + + if ((PollQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) == 0) { + if ((DevInfo->bCallBackIndex) && (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex - 1]) { + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1])( + HcStruc, + DevInfo, + Qh, + DevInfo->fpPollDataBuffer, + PollQh->BytesTransferred); + } + } + } + + UhciActivateTds(PollQh->FirstTd, PollQh->DataToggle); + + PollQh->pElementPtr = (UINT32)(UINTN)PollQh->FirstTd; + PollQh->CurrentTd = PollQh->FirstTd; + PollQh->BytesTransferred = 0; + PollQh->ActiveFlag = TRUE; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciInitQh +// +// Description: This function check whether HC is halted. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UhciInitQh ( + UHCI_QH *Qh +) +{ + Qh->pLinkPtr = UHCI_TERMINATE; + Qh->pElementPtr = UHCI_TERMINATE; + Qh->CurrentTd = NULL; + Qh->DataToggle = 0; + Qh->BytesTransferred = 0; + Qh->ShortPacketDetected = FALSE; + Qh->FirstTd = NULL; + Qh->Interval = 0; + Qh->CallBackIndex = 0; + Qh->ActiveFlag = FALSE; + Qh->DevInfoPtr = NULL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciIsHalted +// +// Description: This function check whether HC is halted. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +UhciIsHalted ( + HC_STRUC *HcStruc +) +{ + return (ByteReadIO((UINT16)(HcStruc->BaseAddress + UHCI_STATUS_REG)) & UHC_HC_HALTED) == UHC_HC_HALTED; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciTranslateInterval +// +// Description: This function calculates the polling rate. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UhciTranslateInterval( + UINT8 Interval +) +{ + UINT8 BitCount = 0; + + // The Interval value should be from 1 to 255 + ASSERT(Interval >= 1 && Interval <= 255); + + for (BitCount = 0; Interval != 0; BitCount++) { + Interval >>= 1; + } + return (1 << (BitCount - 1)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciAllocGeneralTds +// +// Description: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UHCI_TD* +UhciAllocGeneralTds ( + IN UINT8 DeviceAddr, + IN BOOLEAN LowSpeed, + IN UINT8 PacketId, + IN UINT8 EndpointAddr, + IN UINT16 MaxPacket, + IN BOOLEAN ShortPacket, + IN OUT UINTN *BufferAddr, + IN OUT UINT32 *Length, + IN OUT UINT8 *DataToggle +) +{ + UINT16 NumTds = 0; + UHCI_TD *FirstTd = NULL; + UHCI_TD *Td = NULL; + UINTN Address = *BufferAddr; + UINT32 BytesRemaining = *Length; + UINT8 Toggle = *DataToggle; + UINT16 MaxLen = 0; + + if (BytesRemaining == 0) { + return NULL; + } + + NumTds = BytesRemaining / MaxPacket; + if (BytesRemaining % MaxPacket) { + NumTds++; + } + + FirstTd = USB_MemAlloc(GET_MEM_BLK_COUNT(NumTds * sizeof(UHCI_TD))); + if (FirstTd == NULL) { + return NULL; + } + + for (Td = FirstTd;;) { + MaxLen = BytesRemaining > MaxPacket ? MaxPacket : BytesRemaining; + + Td->pLinkPtr = UHCI_TERMINATE; + Td->dToken = (UINT32)PacketId | ((UINT32)DeviceAddr << 8) | + ((UINT32)EndpointAddr << 15) | ((MaxLen - 1) << 21); + if (Toggle) { + Td->dToken |= UHCI_TD_DATA_TOGGLE; + } + + Td->pBufferPtr = (UINT32)Address; + Td->dCSReload = UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE; + if (LowSpeed) { + Td->dCSReload |= UHCI_TD_LOW_SPEED_DEVICE; + } + if (ShortPacket) { + Td->dCSReload |= UHCI_TD_SHORT_PACKET_DETECT; + } + Td->dControlStatus = Td->dCSReload; + Td->bActiveFlag = 1; + + BytesRemaining -= MaxLen; + Address += MaxLen; + Toggle ^= 1; + + if (BytesRemaining == 0) { + break; + } + + Td->pLinkPtr = (UINT32)(((UINTN)Td + sizeof(UHCI_TD)) | UHCI_VERTICAL_FLAG); + Td = (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); + } + + Td->dCSReload |= UHCI_TD_INTERRUPT_ON_COMPLETE; + Td->dControlStatus = Td->dCSReload; + + *Length = BytesRemaining; + *BufferAddr = Address; + *DataToggle = Toggle; + + return FirstTd; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciFreeTds +// +// Description: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UhciFreeTds ( + IN UHCI_TD *FirstTd +) +{ + UHCI_TD *Td = FirstTd; + UINT16 NumTds = 0; + + if (FirstTd == NULL) { + return; + } + + while (Td) { + NumTds++; + Td = Td->pLinkPtr & UHCI_TERMINATE ? + NULL : (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); + } + + USB_MemFree(FirstTd, GET_MEM_BLK_COUNT(NumTds * sizeof(UHCI_TD))); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: UhciActivateTds +// +// Description: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UhciActivateTds ( + IN UHCI_TD *FirstTd, + IN UINT8 DataToggle +) +{ + UHCI_TD *Td = FirstTd; + UINT8 Toogle = DataToggle; + + if (FirstTd == NULL) { + return; + } + + while (Td) { + Td->dToken &= ~UHCI_TD_DATA_TOGGLE; + if (Toogle) { + Td->dToken |= UHCI_TD_DATA_TOGGLE; + } + Td->dControlStatus = Td->dCSReload; + Td->bActiveFlag = 1; + + Toogle ^= 1; + Td = Td->pLinkPtr & UHCI_TERMINATE ? + NULL : (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); + } +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/uhci.h b/Core/EM/usb/rt/uhci.h new file mode 100644 index 0000000..445c8a3 --- /dev/null +++ b/Core/EM/usb/rt/uhci.h @@ -0,0 +1,271 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/uhci.h 11 7/26/13 2:40a Ryanchou $ +// +// $Revision: 11 $ +// +// $Date: 7/26/13 2:40a $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/uhci.h $ +// +// 11 7/26/13 2:40a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 10 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 9 11/22/12 9:21p Wilsonlee +// [TAG] EIP106887 +// [Category] New Feature +// [Description] Support usb S5 wake up function for UHCI. +// [Files] usb.c, uhci.c, uhci.h +// +// 8 5/04/12 6:39a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 7 5/04/12 5:26a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 6 1/04/10 9:20a Olegi +// EIP32956: Polling rate for the keyboards has been changed from 8 ms to +// 32 ms. +// +// 5 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 4 3/20/07 12:20p Olegi +// +// 2 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Uhci.h +// +// Description: AMI USB UHCI header file +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// Avoid including multiple instance of this file +#ifndef __UHCI_H +#define __UHCI_H + +#define UHCI_DATA_AREA_SIZE 0x1000 +#define UHCI_FRAME_LIST_SIZE 1024 + +#define USB_UHCI_REG_LEGSUP 0xC0 + +//--------------------------------------------------------------------------- +// UHCI I/O register read access definitions +//--------------------------------------------------------------------------- + +// Equates for UHCI I/O mapped registers (offsets from base address) + +#define UHCI_COMMAND_REG 0x00 +#define UHCI_STATUS_REG 0x02 +#define UHCI_INTERRUPT_ENABLE 0x04 +#define UHCI_FRAME_NUM 0x06 +#define UHCI_FRAME_LIST_BASE 0x08 +#define UHCI_SOF_MODIFY 0x0C +#define UHCI_PORT1_CONTROL 0x10 +#define UHCI_PORT2_CONTROL 0x12 + +// Bit definitions for UHCI command register + +#define UHC_HOST_CONTROLLER_RUN BIT0 +#define UHC_HOST_CONTROLLER_RESET BIT1 +#define UHC_GLOBAL_RESET BIT2 +#define UHC_ENTER_SUSPEND BIT3 +#define UHC_FORCE_RESUME BIT4 +#define UHC_CONFIGURE_FLAG BIT6 +#define UHC_MAX_PACKET_64_BYTE BIT7 + +// Bit definitions for UHCI status register + +#define UHC_USB_INTERRUPT BIT0 +#define UHC_USB_ERROR_INTERRUPT BIT1 +#define UHC_RESUME_RECEIVED BIT2 +#define UHC_PCI_BUS_ERROR BIT3 +#define UHC_HC_PROCESS_ERROR BIT4 +#define UHC_HC_HALTED BIT5 + +// Bit definitions for USB interrupt enable register + +#define UHC_TIMEOUT_CRC_ENABLE BIT0 +#define UHC_RESUME_ENABLE BIT1 +#define UHC_IOC_ENABLE BIT2 +#define UHC_SHORT_PACKET_ENABLE BIT3 + +// Bit definitions for Port Status and Control + +#define UHC_CONNECT_STATUS BIT0 +#define UHC_CONNECT_STATUS_CHANGE BIT1 +#define UHC_PORT_ENABLE BIT2 +#define UHC_PORT_ENABLE_CHANGE BIT3 +#define UHC_LINE_STATUS 0x30 +#define UHC_LINE_STATUS_CHANGE BIT6 +#define UHC_LOW_SPEED_ATTACHED BIT8 +#define UHC_PORT_RESET BIT9 +#define UHC_PORT_SUSPEND BIT12 + +//--------------------------------------------------------------------------- +// UHCI Controller Port 60/64h trapping flags +//--------------------------------------------------------------------------- +#define UHCI_TRAP_PORT_60h_READ BIT0 +#define UHCI_TRAP_PORT_60h_WRITE BIT1 +#define UHCI_TRAP_PORT_64h_READ BIT2 +#define UHCI_TRAP_PORT_64h_WRITE BIT3 +#define UHCI_SMI_ON_USB_INTERRUPT BIT4 +#define UHCI_TRAP_FLAG (UHCI_SMI_ON_USB_INTERRUPT) + +//--------------------------------------------------------------------------- +// Bit definitions for a generic pointer +//--------------------------------------------------------------------------- +#define UHCI_TERMINATE BIT0 +#define UHCI_QUEUE_HEAD BIT1 +#define UHCI_VERTICAL_FLAG BIT2 +#define UHCI_POINTER_MASK 0xFFFFFFF0 + +//--------------------------------------------------------------------------- +// Bit definitions for transfer descriptor control and status +//--------------------------------------------------------------------------- + +#define UHCI_TD_ACTUAL_LENGTH 0x7FF +#define UHCI_TD_STATUS_FIELD 0xFE0000 +#define UHCI_TD_BITSTUFF_ERROR 0x20000 +#define UHCI_TD_CRC_TIMEOUT_ERROR 0x40000 +#define UHCI_TD_NAK_RECEIVED 0x80000 +#define UHCI_TD_BABBLE_DETECTED 0x100000 +#define UHCI_TD_DATA_BUFFER_ERROR 0x200000 +#define UHCI_TD_STALLED 0x400000 +#define UHCI_TD_ACTIVE 0x800000 +#define UHCI_TD_INTERRUPT_ON_COMPLETE 0x1000000 +#define UHCI_TD_ISOCHRONOUS_SELECT 0x2000000 +#define UHCI_TD_LOW_SPEED_DEVICE 0x4000000 +#define UHCI_TD_ERROR_COUNTER 0x18000000 +#define UHCI_TD_ONE_ERROR 0x8000000 +#define UHCI_TD_TWO_ERRORS 0x10000000 +#define UHCI_TD_THREE_ERRORS 0x18000000 +#define UHCI_TD_SHORT_PACKET_DETECT 0x20000000 + +//--------------------------------------------------------------------------- +// Bit definitions for transfer descriptor token +//--------------------------------------------------------------------------- +#define UHCI_TD_PACKET_ID 0xFF +#define UHCI_TD_IN_PACKET 0x69 +#define UHCI_TD_OUT_PACKET 0xE1 +#define UHCI_TD_SETUP_PACKET 0x2D +#define UHCI_TD_DEVICE_ADDRESS 0x7F00 +#define UHCI_TD_ENDPOINT 0x78000 +#define UHCI_TD_DATA_TOGGLE 0x80000 +#define UHCI_TD_MAX_LENGTH 0xFFE00000 + +typedef enum { + Control = 1, + Bulk = 0, + Interrupt = 2, + Isochronous = 3 +} XFER_TYPE; + +#pragma pack(push, 1) + +// UHCI TD structure +typedef struct { + UINT32 pLinkPtr; + UINT32 dControlStatus; + UINT32 dToken; + UINT32 pBufferPtr; + +// AMI defined fields + UINT32 dCSReload; // Control status reload value + UINT8 bCallBackIndex; + UINT8 bActiveFlag; + UINT16 wReserved; + UINT8 aDataArea[8]; +} UHCI_TD; + +typedef struct { + UINT32 pLinkPtr; + UINT32 pElementPtr; + UHCI_TD *CurrentTd; + UINT8 DataToggle; + UINT32 BytesTransferred; + BOOLEAN ShortPacketDetected; + XFER_TYPE Type; + UHCI_TD *FirstTd; + UINT8 Interval; + UINT8 CallBackIndex; + BOOLEAN ActiveFlag; + VOID *DevInfoPtr; + UINT8 aReserved[47 - 3 * sizeof(VOID*) - sizeof(XFER_TYPE)]; +} UHCI_QH; + +#pragma pack(pop) + +typedef struct { + UHCI_QH *StaticQh; + UHCI_QH *RootHubQh; + UHCI_QH *RepeatQh; +} UHCI_DESC_PTRS; + +#endif // __UHCI_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usb.c b/Core/EM/usb/rt/usb.c new file mode 100644 index 0000000..b1baa4a --- /dev/null +++ b/Core/EM/usb/rt/usb.c @@ -0,0 +1,5300 @@ +#pragma warning(disable: 4001) +#pragma warning(disable: 4127) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usb.c 183 10/21/16 1:48a Wilsonlee $ +// +// $Revision: 183 $ +// +// $Date: 10/21/16 1:48a $ +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usb.c $ +// +// 183 10/21/16 1:48a Wilsonlee +// Fixed Cppcheck error. +// +// 182 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 +// +// 181 7/28/16 4:56a Wilsonlee +// [TAG] EIP264662 +// [Category] Improvement +// [Description] Don't install usb hw smi after reconnecting usb +// controllers. +// [Files] uhcd.c, usb.c, ohci.c, amiusb.c, amiusbhc.c +// +// 180 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 +// +// 179 11/04/15 9:51p Wilsonlee +// [TAG] EIP241067 +// [Category] Improvement +// [Description] Add the device descriptor to the DEV_INFO structure. +// [Files] usb.c, usbdef.h, xhci.c, usbbus.c, AmiUsbController.h +// +// 178 9/01/15 10:17p Wilsonlee +// [TAG] EIP235482 +// [Category] Improvement +// [Description] Select this alternate setting for multiple TTs hubs. +// [Files] usbhub.c, usb.c, amiusb.h, usbdef.h +// +// 177 7/24/15 3:30a Wilsonlee +// [TAG] EIP229294 +// [Category] Improvement +// [Description] If the device descriptor returns with a value in its +// length field that is greater 18, it is valid and we should ignore the +// extra bytes. +// [Files] usb.c +// +// 176 5/28/15 4:29a Wilsonlee +// [TAG] EIP219785 +// [Category] Improvement +// [Description] Suspend usb devices which are connected to Hubs. +// [Files] usb.c, usbdef.h +// +// 175 4/29/15 11:26p Wilsonlee +// [TAG] EIP215031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Transcend USB 3.0 HDD is disappeared in the setup menu by +// cold boot. +// [RootCause] We only can get SerialNumber string descriptor before +// setting configuration for this device, otherwise it is failed at +// getting this descriptor and inquiry command is also failed. +// [Solution] Retry inquiry command. +// [Files] usb.c, usbmass.c, efiusbmass.c, usbbus.c, usbdef.h +// +// 174 4/27/15 2:25a Wilsonlee +// [TAG] EIP211855 +// [Category] Improvement +// [Description] Set the default interface if the device has alternate +// setting for the interface. +// [Files] usb.c, usbdef.h +// +// 173 4/07/15 4:03a Wilsonlee +// [TAG] EIP211598 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Keyboard/Mouse sometimes cannot work when connected to USB +// 3.0 HUB. +// [RootCause] It's failed at setting device address. +// [Solution] Wait 10 ms for stable before we set device address. +// [Files] usb.c +// +// 172 3/08/15 10:49p Wilsonlee +// [TAG] EIP207774 +// [Category] Improvement +// [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and +// clear it if we don't start any HC. +// [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h +// +// 171 2/16/15 2:44a Wilsonlee +// [TAG] EIP205373 +// [Category] Improvement +// [Description] Cppcheck errors in Usb module. +// [Files] usb.c, usbport.c, uhcd.c, usbCCID.c +// +// 170 1/22/15 10:19p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 169 12/15/14 2:16a Wilsonlee +// [TAG] EIP194720 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System shutdown delay when connect with cardreader. +// [RootCause] When we reenumerate devices, we still reserve the +// original device info, then we will use the wrong info to send command +// and the device may not respond. +// [Solution] Remove the present flag of devices before we reenumerate. +// [Files] usb.c +// +// 168 11/23/14 10:09p Wilsonlee +// [TAG] EIP189293 +// [Category] Improvement +// [Description] Implement XHCI key repeat function. +// [Files] usb.c, xhci.c , xhci.h, amiusb.c +// +// 167 9/29/14 11:35p Wilsonlee +// [TAG] EIP181169 +// [Category] Improvement +// [Description] Support XHCI 1.1/USB 3.1. +// [Files] xhci.c, xhci.h, usb.c, usbbus.c, usbdef.h, UsbHc.h +// +// 166 9/02/14 3:53a Wilsonlee +// [TAG] EIP182567 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] POST B4h sometimes stays about 30 sec if using special +// KB/Ms. +// [RootCause] t's timeout in getting config or report descriptor +// commands. +// [Solution] Set the timeout to 500 ms. +// [Files] usb.c, usbhid.c, usbdef.h +// +// 165 7/30/14 5:17a Wilsonlee +// [TAG] EIP176293 +// [Category] Improvement +// [Description] The changes are for DisplayLink USB Network driver. +// [Files] usbbus.c, usb.c +// +// 164 7/28/14 7:39a Wilsonlee +// [TAG] EIP176070 +// [Category] Improvement +// [Description] Add 100 microseconds before we send get configuration +// descriptor command if the device is full speed. +// [Files] usb.c +// +// 163 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 +// +// 162 6/20/14 2:11a Wilsonlee +// [TAG] EIP174589 +// [Category] Improvement +// [Description] Fix build error if USB_HID_KEYREPEAT_USE_SETIDLE is 1. +// [Files] usb.c +// +// 161 5/12/14 4:29a Wilsonlee +// [TAG] EIP168515 +// [Category] New Feature +// [Description] Add the token "USB_CONTROLLERS_INITIAL_DELAY_LIST" if +// usb controllers need to delay for stabilization. +// [Files] usb.sdl, usb.c +// +// 160 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 159 4/29/14 8:30p Wilsonlee +// [TAG] EIP164772 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System would auto wake up if USB hot-plug in S5 state via +// USB hub. +// [RootCause] The usb hubs have connnect / disconnect wakeup function +// if we send remote wakeup command +// [Solution] Don't send remote wakeup command to the usb hubs. +// [Files] usb.c +// +// 158 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 +// +// 157 11/26/13 1:23a Wilsonlee +// [TAG] EIP143251 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] The usb mouse lost if it behinds TI TUSB8040A1 hub under +// BIOS. +// [RootCause] The device may connect later, then we clear connect +// change without setting the device is connected. +// [Solution] Don't get port status again before we clear the changes. +// [Files] usb.c, usbhub.c +// +// 156 11/04/13 3:26a Wilsonlee +// [TAG] EIP139714 +// [Category] Improvement +// [Description] Improve the UsbIoPortReset function to support the xhci +// controller. +// [Files] usb.c +// +// 155 9/04/13 5:46a Wilsonlee +// [TAG] EIP134478 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The devices which behind the hub don't install successfully +// in shell. +// [RootCause] Find the wrong root hub port. +// [Solution] Check DEV_INFO_VALID_STRUC and DEV_INFO_DEV_PRESENT flag +// to find the root hub port. +// [Files] usb.c, xhci.c, usbbus.c +// +// 154 8/16/13 4:17a Ryanchou +// +// 153 8/02/13 6:16a Ryanchou +// +// 152 7/29/13 5:19a Roberthsu +// [TAG] EIP126741 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Cannot boot to uefi usb device with Sophos software. +// [RootCause] When boot into tool. Ownership to os event occur.Usb +// will disconnect device.And record this disconnect event. Then ownership +// to bios,bios will connect all device.Run legacy to efi function. Bios +// run disconnect event first.Then reconnect device.Because usb key behind +// hub. So usb key disconnect also. +// [Solution] Check device when device reconnect.If device and port +// number the same.Use the same device info. +// [Files] usb.c,usbmass.c,efiusbmass.c,uhcd.c +// +// 151 7/22/13 10:31p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 150 7/17/13 4:14a Roberthsu +// [TAG] EIP126319 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] TEAC floppy can not detect when cold boot. +// [RootCause] Device need more delay after get config descriptor. +// [Solution] Add delay to 1ms. +// [Files] usb.c +// +// 149 6/26/13 3:36a Roberthsu +// [TAG] EIP125792 +// [Category] Bug Fix +// [Severity:] Normal +// [Symptom:] Keep function not work +// [Root Cause] When check port change. We can not get baseclass. +// [Solution] Add Vaild base class flag. +// [Files] UsbPort.c,Usb.c +// +// 148 5/01/13 9:54p Wilsonlee +// [TAG] EIP121643 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Cannot detect the usb floppy. +// [RootCause] This device doesn't return data when we sned +// get-config-descriptor command. +// [Solution] We retry to send get-config-descriptor command if there is +// no data. +// [Files] usb.c, ehci.c +// +// 147 4/19/13 12:44a Wilsonlee +// Fix build error if token USB_S5_WAKEUP_SUPPORT is enabled. +// +// 146 4/18/13 11:22a Ryanchou +// Fix build error if token x64_BUILD is 0. +// +// 145 3/19/13 3:58a 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 +// +// 144 3/15/13 5:57a Ryanchou +// +// 143 3/15/13 4:59a Ryanchou +// [TAG] EIP117211 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB Memory Allocation Failure for Sizes Above 4k +// [RootCause] The variable count will be reset when across a page +// boundary. +// [Solution] Only reset the variable Count if the allocated blocks less +// than a page. +// [Files] usb.c +// +// 142 3/07/13 9:25p Wilsonlee +// [TAG] EIP116044 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] TEAC FDD is not recognized after hot plugging under DOS. +// [RootCause] Setting the device configuration is failed. +// [Solution] This device configure successfully by that we set the +// device address after sending the first get-device-descriptor command. +// [Files] usb.c +// +// 141 3/07/13 8:52a Ryanchou +// [TAG] EIP113218 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB keyboard cannot work after ownership change back to +// BIOS +// [RootCause] The key repeat SMI does not generated because the HC is +// stopped. +// [Solution] Use the other HC to generate key repeat SMI +// [Files] usb.c, usbhid.c, usbkbd.c +// +// 140 1/23/13 8:33p Wilsonlee +// [TAG] EIP108891 +// [Category] Improvement +// [Description] For usb wakp up function, we need to add some delay to +// wait the usb devces connect. +// [Files] usb.c +// +// 139 1/22/13 2:38a Wilsonlee +// [TAG] EIP110305 +// [Category] Improvement +// [Description] Set the device address after we send the first +// get-device-descriptor command. +// [Files] usbmass.c, usb.c, usbdef.h, usbbus.c, efiusbmass.c, uhcd.c, +// usbport.c +// +// 138 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 137 12/05/12 4:23a Roberthsu +// [TAG] EIP96616 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] When Legacy to EFI, USB KB can't be used. +// [RootCause] Usb device driver content incorrect driver entry.Legacy +// insert a devicet,when legacy to efi,device does not install efi driver. +// [Solution] When legacy to efi, scan device info table and put it +// to smiqueue. +// [Files] usb.sdl,uhcd.c,usb.c +// +// 136 11/29/12 7:47a Ryanchou +// [TAG] EIP107586 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Unplug USB keyboard does not uninstall EFI USB keyboard +// driver properly +// [RootCause] The EIP99431 changes clear DEV_INFO.bSubDeviceType in +// runtime keyboard driver, that cause EFI keyboard driver does not know +// what type of the device is. +// [Solution] Do not clear DEV_INFO.bSubDeviceType in runtime keyboard +// driver. +// [Files] usb.c, usbhid.c, efiusbhid.c +// +// 135 11/22/12 9:20p Wilsonlee +// [TAG] EIP106887 +// [Category] New Feature +// [Description] Support usb S5 wake up function for UHCI. +// [Files] usb.c, uhci.c, uhci.h +// +// 134 11/13/12 7:11a Wilsonlee +// [TAG] EIP82553 +// [Category] New Feature +// [Description] Support usb S5 wake up function for XHCI. +// [Files] usb.c, ehci.c, ohci.c, xhci.c, xhci.h +// +// 133 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 +// +// 132 10/25/12 4:14a Wilsonlee +// [TAG] EIP82354 +// [Category] New Feature +// [Description] Support usb S5 wake up function for OHCI. +// [Files] usb.c, ehci.c, ohci.c +// +// 131 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 +// +// 130 9/03/12 4:55a Roberthsu +// [TAG] EIP98145 +// [Category] Improvement +// [Description] Add skip function message. +// [Files] usb.c,usbsrc.sdl +// +// 129 8/29/12 9:32a Ryanchou +// [TAG] EIP88307 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Key repeat cannot be stopped if the keyboard is connected +// to xHCI. +// [RootCause] Periodic timer SMI stop generating when USB SMI and +// periodic timer SMI is generated frequently. +// [Solution] Reduces the key repeat rate to avoid this issue. +// [Files] ehci.c, usb.c, usb.sdl +// +// 128 8/29/12 8:18a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 127 8/22/12 4:59a Wilsonlee +// [TAG] EIP98230 +// [Category] Improvement +// [Description] Set the default of the MaxPacket for endpoint 0 by the +// device speed. +// [Files] usb.c +// +// 126 6/13/12 2:39a Roberthsu +// [TAG] EIP90124 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Insert barcode when pxe option rom running.Barcode will not +// work under dos. +// [RootCause] Because pxe option under legacy mode.Back to efi mode +// barcode after reinit will fail under dos. +// [Solution] In function USB_ReConfigDevice check device initial done. +// [Files] usb.c +// +// 125 5/22/12 10:04a Ryanchou +// [TAG] EIP90154 +// [Category] Improvement +// [Description] Remove the USBSB_EnableSmmPeriodicSmi and +// USBSB_DisableSmmPeriodicSmi hooks. +// [Files] amidef.h, amiusb.c, usb.c, usbsb.c +// +// 124 5/22/12 4:48a Wilsonlee +// [TAG] EIP89641 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB Keyboard driver overwrites INT0 vector (address 0:0) +// [RootCause] The Queue Head cross the page boundary. +// [Solution] Added page alignment restriction into memory allocation +// routine. +// [Files] usb.c +// +// 123 5/04/12 6:40a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 122 5/04/12 5:27a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 121 4/24/12 3:36a Wilsonlee +// [TAG] EIP81761 +// [Category] Improvement +// [Description] Determine the limit of devices after checking whether +// this device is reconnected. +// [Files] usb.c +// +// 120 2/16/12 8:53p Wilsonlee +// [TAG] EIP81612 +// [Category] Spec Update +// [Severity] Minor +// [Description] Add EFI_USB_SPEED_SUPER in EFI_USB2_HC_PROTOCOL +// according to UEFI 2.3.1 spec +// [Files] usb.c, usbbus.c, amiusbhc.c +// +// 119 1/13/12 4:24a Ryanchou +// [TAG] EIP47348 +// [Category] New Feature +// [Description] Support for USB Port Reset function. +// [Files] amiusb.c, amiusb.h, amiusbhc.c, uhci.c, usb.c, usbbus.c, +// usbbus.h, usbmass.c +// +// 118 1/04/12 6:23a Ryanchou +// +// 117 1/04/12 6:22a Ryanchou +// [TAG] EIP78861 +// [Category] Improvement +// [Description] Some device will be disconnected after port +// reset, and reconnected for a while, added 100 ms delay in this case. +// [Files] usb.c +// +// 116 12/26/11 2:24a Roberthsu +// [TAG] EIP74609 +// [Category] Improvement +// [Description] Add check oemskiplist at check port change. +// [Files] usbport.c,usb.c,AmiUsbController.h +// +// 115 12/08/11 1:46a Ryanchou +// [TAG] EIP75441 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hangs at 0xB4 after restart from Win7 +// [RootCause] The device does not use standard BOT protocol under +// Windows. +// [Solution] Add the device into bad device table. +// [Files] usb.c usbport.c +// +// 114 11/28/11 8:36p Wilsonlee +// [TAG] EIP73803 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The mouse can't work under setup after hot-plug. +// [RootCause] The device may fail at the get device descriptor or set +// device configuration. +// [Solution] Add 10 msec delay before getting device descriptor if the +// device is low or full speed and add 2 msec delay after setting the +// device's address. +// [Files] usb.c +// +// 113 11/08/11 8:21a Wilsonlee +// [TAG] EIP74876 +// [Category] New Feature +// [Description] Add USB API for shutdown single USB controller. +// [Files] amiusb.c, amiusb.h, usb.c, usbdef.h, uhcd.c, uhcd.h, +// AmiUsbController.h +// +// 112 11/05/11 7:36a Wilsonlee +// [TAG] EIP64781 +// [Category] New Feature +// [Description] Added SDL token +// SKIP_CARD_READER_CONNECT_BEEP_IF_NO_MEDIA that skip the connect beep if +// no media present in USB card reader. +// [Files] usbport.c, usbmass.c, usb.c, usbdef.h, uhcd.c, usbsrc.sdl +// +// 111 10/25/11 8:23a Wilsonlee +// [TAG] EIP71750 +// [Category] New Feature +// [Description] Support extraUSB device driver hook by elink. +// +// 110 10/25/11 3:51a Ryanchou +// [TAG] EIP70933 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System hangs at checkpoint 0x98 when webcam plugged +// [RootCause] The webcam return invalid data in configuration +// descriptor. +// [Solution] Get the configuration descriptor twice, the first time is +// to receive the returned configure descriptor to get the total length +// and the second time is to feed the length to the function again. +// [Files] usb.c, usbdef.h +// +// 109 8/08/11 6:59a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 108 8/08/11 5:17a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 107 8/05/11 6:18a Ryanchou +// [TAG] EIP60706 +// [Category] Improvement +// [Description] Move gUsbBadDeviceTable into SMRAM. +// [Files] usbport.c, amiusb.c, usb.c, uhcd.c, AmiUsbController.h +// +// 106 7/22/11 5:37a Ryanchou +// [TAG] EIP65385 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB mouse can not be detected. +// [RootCause] The device is connected in disconnect progress, port +// reset is not issued. +// [Solution] Remove the code that check device connection in disconnect +// progress. +// [Files] usb.c +// +// 105 7/19/11 5:17a Ryanchou +// [TAG] EIP64498 +// [Category] New Feature +// [Description] Implement EHCI key repeat function. +// [Files] ehci.c, ehci.h, usb.c, usbdef.h +// +// 104 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 103 7/13/11 2:47a Ryanchou +// [TAG] EIP60460 +// [Category] Improvement +// [Description] Adds a flag when device disconnected during data +// transfer, BIOS will not issue a transfer to the devicce if this flag is +// set. This change is for Fresco USB 3.0 controller. +// [Files] usb.c, usbdef.h, xhci.c, xhci.h +// +// 102 7/12/11 8:09a 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 +// +// 101 6/22/11 9:36a Ryanchou +// [TAG] EIP60640 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Logitec USB keyboard has no function in DOS. +// [RootCause] The USB keybaord may stall get configuration descriptor +// request or set address request. +// [Solution] Retry five times when the device stalls these request. +// [Files] usb.c, usbbus.c +// +// 100 6/22/11 1:44a Ryanchou +// [TAG] EIP59738 +// [Category] Improvement +// [Description] Support Block size other than 512 bytes USB HDD in UEFI +// mode. +// [Files] efiusbmass.c, uhci.c, usb.c, usbdef.h, usbmass.c +// +// 99 6/21/11 9:33a Ryanchou +// [TAG] EIP59601 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB devices can't be detected if webcam is connected. +// [RootCause] The configuration descriptor length is greater than +// buffer length, the causes the last descriptor is invalid. +// [Solution] If the next descriptor cross the buffer boundary, skip the +// descriptor. +// [Files] usb.c +// +// 98 4/06/11 5:27a Tonylo +// [TAG] EIP52339 +// [Category] New Feature +// [Description] USB changes of USB host safe disabling solution. +// +// 97 4/06/11 1:33a Ryanchou +// [TAG] EIP54782 +// [Category] Improvement +// [Description] Change polling data size of HID devices to max packet +// size of interrupt endpoint. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c +// +// 96 4/06/11 12:49a Ryanchou +// [TAG] EIP51653 +// [Category] New Feature +// [Description] Added an interface that skips specific port +// enumeration. +// [Files] AmiUsbController.h, uhcd.c, uhcd.h, usb.c, usbdef.h, +// usbport.c +// +// 95 3/30/11 8:13a Ryanchou +// [TAG] EIP54126 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Sometimes system hangs at checkpoint 0xB4. +// [RootCause] The bLength field of configuration descriptor is zero. +// [Solution] Check wether bLength field is zero before paring next +// descriptor. +// [Files] usb.c, usbbus.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c +// +// 94 3/29/11 10:52p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 93 3/29/11 10:08a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 92 1/17/11 3:51a Ryanchou +// [TAG] EIP50361 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Hot plug USB 3.0 flash drive in setup will cause system +// hang. +// [RootCause] The memory may be destroyed if the Address Device command +// fails. +// [Solution] Check the memory has been allocated when free the memory. +// [Files] usb.c xhci.c xhci.h +// +// 91 11/11/10 11:36p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 90 10/28/10 12:34a Ryanchou +// EIP46865: Comment out unnecessary ASSERT macro. +// +// 89 10/28/10 12:24a Ryanchou +// EIP45643: Fixed system hangs when hot plug USB mass storage quickly on +// USB 3.0 port. +// +// 88 10/21/10 10:12a Ryanchou +// EIP45121: Added xHCI Supported Protocol Capability and fix the problem +// that USB 3.0 device can't be detected. +// +// 87 10/20/10 10:24a Ryanchou +// EIP44702: Added USB 3.0 hub support. +// +// 86 10/20/10 12:55a Ryanchou +// EIP45828: If the flag DEV_INFO_MASS_DEV_REGD is set, check if the +// controller type is difference between old DevInfo and new one. +// +// 85 9/16/10 9:22a Ryanchou +// EIP44149: Disable slot if the Address Device command was unsuccessful. +// +// 84 9/07/10 4:12a Tonylo +// Remove user tags for coding standard. +// +// 83 8/18/10 4:23p Olegi +// Klockwork related fixes; EIP37978 +// +// 82 8/13/10 4:10p Olegi +// Bugfix in CheckDeviceLimit function. EIP41442 +// +// 81 7/15/10 4:39a Tonylo +// EIP15489 - Add USB HandOff function for shurdown/init USB legacy +// through USB API function. +// +// 80 7/13/10 5:09a Ryanchou +// EIP39838: Fixed configure USB hub fail. +// +// 79 7/02/10 1:59a Ryanchou +// Update DevMiscInfo field when hot plug USB mass storage. +// +// 78 6/22/10 9:29a Ryanchou +// EIP39374: Fixed USB mass storage hot plug issue. +// +// 77 6/11/10 1:43a Ryanchou +// EIP36720: Fixed USB keyboard hot plug in setup issue. +// +// 76 5/11/10 11:02a Olegi +// Bugfix in USB_InitDeviceDataDummy; EIP37974 +// +// 75 3/19/10 10:05a Olegi +// +// 74 3/11/10 9:42a Olegi +// +// 73 3/10/10 6:36p Olegi +// +// 72 3/10/10 6:35p Olegi +// +// 71 3/06/10 1:11p Olegi +// +// 70 2/27/10 11:58a Olegi +// Change in the arguments of pfnHCDInitDeviceData function. +// +// 69 2/26/10 4:23p Olegi +// +// 68 2/23/10 1:20p Olegi +// Work around Klockwork issues. EIP34370 +// +// 67 2/08/10 9:38a Olegi +// EIP34448: Bugfix in prepareForLegacyOS. +// +// 66 1/13/10 3:20p Olegi +// Correction in CheckDeviceLimit routine, EIP32804. +// +// 65 12/31/09 9:53a Olegi +// +// 64 12/10/09 10:12a Olegi +// Added UsbControlTimeout setup selection. EIP30079. +// +// 63 11/12/09 6:09p Olegi +// +// 62 11/09/09 5:40p Olegi +// +// 61 10/30/09 5:47p Olegi +// +// 60 10/13/09 8:55a Olegi +// EIP28323: Change in USBGetProperDeviceInfoStructure: +// - Undo the checking for DEV_INFO_DEV_BUS so that in device structure +// re-used. +// +// 59 10/09/09 5:57p Olegi +// +// 58 10/08/09 10:18a Olegi +// EIP28031: USB_SmiQueuePut must not be called after OS booted as it +// modifies the BS memory. +// +// 57 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 56 10/02/09 10:49a Olegi +// Code cleanup. +// +// 55 9/15/09 12:21p Olegi +// Added KEY_REPEAT_LOGIC functionality. EIP#25841 +// +// 54 8/26/09 11:41a Olegi +// Changes that prevent collision of keyboard activity and mass storage +// access. EIP#22808 +// +// 53 8/18/09 2:36p Rameshr +// Symptom: When the system is inside the Option rom, connect uSb keyboard +// and it doesn't work. +// Rootcause: In post only EFI driver configure the USB keyboard. So Once +// comes out from option rom Usbkeyboard works. +// Solution: When you are inside the option rom configure the newly +// connected USB keyboard and notify EFI driver. +// +// 52 8/06/09 4:15p Olegi +// Changes related to EIP#23335: connect status change is not maintained +// properly when device is disconnected while connection is in progress. +// +// 51 6/11/09 5:29p Olegi +// Increased the default timeout value to 20 sec. Thermlake external HDD +// is not responding to the first READ_10 command for 14 seconds. +// +// 50 6/04/09 3:42p Olegi +// USB_ConfigureDevice: for the existing devices copy the information +// about the parent controller/hub/port# into the new device structure. +// +// 49 6/01/09 2:48p Olegi +// EIP#22046: while detecting the new device we get the configuration +// descriptor, assuming it is followed by the interface descriptor; if it +// is not an interface descriptor, we used to think it is not the first +// one, so we never send set address and configuration request. +// +// 47 5/08/09 8:56a Olegi +// Increased the timeout value from 5 sec to 10 sec. Several types of +// external USB HDDs require this change to be properly enumerated. +// +// 46 1/29/09 2:32p Olegi +// Added the check for device limit before device is configured. +// +// 44 9/05/08 4:21p Olegi +// fpCallbackNotify4 is replaced with the local function. +// +// 42 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 39 10/30/07 12:07p Olegi +// Set configuration one more time: it was found that for some devices +// SET_CONFIGURATION must be the executed right before issuing device +// specific commands. Example is USB Netac Key (VID 0x0644 DID 0x0000). +// +// 38 10/15/07 5:20p Olegi +// Modified USB_on_identifyDev() routine. +// +// 37 9/26/07 9:15a Olegi +// Added USB_FORCE_64BIT_ALIGNMENT flag. +// +// 36 9/06/07 5:59p Olegi +// Added support for 64-byte pool allocation byte alignment. +// +// 35 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 32 5/05/07 1:54p Olegi +// Persistent DOS drives. +// +// 31 4/17/07 8:43a Michaela +// Bugfix in USB_DetectNewDevice function. +// +// 30 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 24 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 17 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 16 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 14 3/06/06 6:24p Olegi +// Lun devices support modifications: supported using the index in +// DEV_INFO table, not through dedicated massLun table. +// +// 13 3/01/06 3:50p Olegi +// USB_FLAG_RUNNING_UNDER_OS flag added. +// +// 11 1/11/06 11:51a Olegi +// Multi-functional devices handling changed. +// +// 10 12/19/05 10:17a Olegi +// USB_StopHostControllers modified to control the sequence of stopping +// (EHCI first, others follow). +// +// 9 11/03/05 6:31p Andriyn +// LUN Support changes +// +// 7 6/20/05 8:55a Olegi +// .NET compiler with highest warning level and warning-as-error +// modification. +// +// 6 6/16/05 12:19p Andriyn +// Fix usb device lost after boot to legacy OS: don't disable port even if +// device is not +// supported by USBRT: there could be another device at the same address +// +// 5 6/15/05 1:59p Andriyn +// Comments were changed +// +// 4 6/01/05 5:34p Olegi +// Bugfix in USB_DetectNewDevice. +// +// 3 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 2 5/10/05 4:11p Andriyn +// USBBUS implementation +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Usb.c +// +// Description: AMI USB main wrapper +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <Token.h> +#include "amidef.h" +#include "usbdef.h" + +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#include <AmiUsbSmmGlobalDataValidationLib.h> +#endif + +#include <PCI.h> //(EIP54018+) + +BOOLEAN gKeyRepeatStatus = FALSE; +extern BOOLEAN gCheckUsbApiParameter; + +BOOLEAN OEMSkipList(UINT8,UINT8,UINT16,UINT8,UINT8); //(EIP74609+) + +#if USB_DEV_HUB +UINT8 USBHub_EnablePort(HC_STRUC*, UINT8, UINT8); +UINT8 USBHub_DisablePort(HC_STRUC*, UINT8, UINT8); +UINT8 USBHub_ResetPort(HC_STRUC*, UINT8, UINT8); +//VOID USBHubFillDriverEntries (DEV_DRIVER*); //(EIP71750-) +UINT8 USBHub_GetPortStatus (HC_STRUC*, UINT8, UINT8, BOOLEAN); +#endif + +VOID SpeakerBeep (UINT8, UINT16, HC_STRUC*); +VOID FixedDelay(UINTN); +//VOID BusFillDriverEntries(DEV_DRIVER*); //(EIP71750-) + //(EIP38434+)> +//#if USB_DEV_KBD +//VOID USBKBDFillDriverEntries (DEV_DRIVER*); +//#endif +//#if USB_DEV_MOUSE +//VOID USBMSFillDriverEntries (DEV_DRIVER*); +//#endif + //(EIP71750-)> +//VOID USBHIDFillDriverEntries (DEV_DRIVER*); + //<(EIP38434+) +//#if USB_DEV_MASS +//VOID USBMassFillDriverEntries (DEV_DRIVER*); +//#endif +//#if USB_DEV_CCID +//VOID USBCCIDFillDriverEntries (DEV_DRIVER*); +//#endif + //<(EIP71750-) +VOID MemFill (UINT8*, UINT32, UINT8); +VOID MemCopy (UINT8*, UINT8*, UINT32); + +VOID USBAPI_CheckDevicePresence (URP_STRUC*); + +extern USB_BADDEV_STRUC gUsbBadDeviceTable[]; //(EIP60706) + +DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); //(EIP98145) +VOID* USB_MemAlloc(UINT16); +UINT8 USB_MemFree (VOID*, UINT16); +UINT8* USB_GetDescriptor (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT8 , UINT8); +UINT8 USB_SetAddress(HC_STRUC*,DEV_INFO*, UINT8); +DEV_INFO* USBIdentifyAndConfigureDevice (HC_STRUC* , DEV_INFO* , UINT8* , UINT16 ,UINT16 ); +UINT8 USB_DisconnectDevice (HC_STRUC*, UINT8, UINT8 ); +VOID USB_InitFrameList (HC_STRUC*, UINT32); +DEV_DRIVER* UsbFindDeviceDriverEntry(DEV_DRIVER*); + +UINT8 USB_MemInit (VOID); +UINT8 USBInitHostController(UINT16 *, UINT8); +UINT8 USB_EnumerateRootHubPorts(UINT8); +UINT8 USBLogError(UINT16); +BOOLEAN CheckDeviceLimit(UINT8); +VOID USB_SmiQueuePutMsg(QUEUE_T*, VOID*, int); + + //(EIP54018+)> +UINT32 ReadPCIConfig(UINT16, UINT8); +#if USB_S5_WAKEUP_SUPPORT +VOID DwordWritePCIConfig(UINT16, UINT8, UINT32); +VOID WordWritePCIConfig(UINT16, UINT8, UINT16); +VOID ByteWritePCIConfig(UINT16, UINT8, UINT8); +VOID UsbSbEnablePme(VOID); +#endif + //<(EIP54018+) + +extern USB_GLOBAL_DATA *gUsbData; // Defined in AMIUHCD + +#ifdef USB_CONTROLLERS_INITIAL_DELAY_LIST +typedef struct { + UINT16 Vid; + UINT16 Did; + UINT16 DelayTime; +} CONTROLLERS_INITIAL_DELAY_LIST; + +CONTROLLERS_INITIAL_DELAY_LIST gControllersInitialDelayList[] = {USB_CONTROLLERS_INITIAL_DELAY_LIST}; +#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_StartHostControllers +// +// Description: This function initializes the USB host controllers and +// enumerate the root hub ports for possible USB devices. +// +// Output: fpGlobalDataArea Far pointer to the global data area +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_StartHostControllers(UINT8* fpGlobalDataArea) +{ + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: StopControllerType +// +// Description: This function stops all USB host controllers of a given type +// +// Output: HC type +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +StopControllerType( + UINT8 hc_type +) +{ + UINT8 i; + HC_STRUC* fpHCStruc; + + USB_DEBUG(DEBUG_LEVEL_3, "stopping all HC type %x:", hc_type); + for (i = 0; i < gUsbData->HcTableCount; i++) { + fpHCStruc = gUsbData->HcTable[i]; + if (fpHCStruc == NULL) { + continue; + } + if ((fpHCStruc->bHCType == hc_type) && + (fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDStop)(fpHCStruc); + USB_DEBUG(DEBUG_LEVEL_3, "."); + } + } + USB_DEBUG(DEBUG_LEVEL_3, "\n"); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: StartControllerType +// +// Description: This function start all USB host controllers of a given type +// +// Output: HC type +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +StartControllerType( + UINT8 hc_type +) +{ + UINT8 i; + HC_STRUC* fpHCStruc; + + USB_DEBUG(DEBUG_LEVEL_3, "starting all HC type %x:", hc_type); + for (i=0; i<gUsbData->HcTableCount; i++) { + fpHCStruc = gUsbData->HcTable[i]; + if (fpHCStruc == NULL) { + continue; + } + if (!(fpHCStruc->dHCFlag & HC_STATE_USED)) { + continue; + } + if ((fpHCStruc->bHCType == hc_type) ) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDStart)(fpHCStruc); + USB_DEBUG(DEBUG_LEVEL_3, "."); + } + } + USB_DEBUG(DEBUG_LEVEL_3, "\n"); +} + + //(EIP74876+)> +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: StopControllerBdf +// +// Description: This function stops the USB host controllers of a given Bus Dev Function +// +// Input: BusDevFuncNum +// +// Output: None +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +StopControllerBdf( + UINT16 BusDevFuncNum +) +{ + UINT8 i; + HC_STRUC* HcStruc; + + for (i = 0; i < gUsbData->HcTableCount; i++) { + HcStruc = gUsbData->HcTable[i]; + if (HcStruc == NULL) { + continue; + } + if ((HcStruc->wBusDevFuncNum == BusDevFuncNum) && + (HcStruc->dHCFlag & HC_STATE_RUNNING)) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDStop)(HcStruc); + break; + } + } +} + //<(EIP74876+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_StopHostControllers +// +// Description: This function stops the USB host controllers and +// frees the data structures associated with the host controllers +// In case of USB2.0 first stop USB1.1 controllers, then USB2.0. +// +// Output: None +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_StopHostControllers (VOID) +{ + // Suppress disconnect beeps as they might be confusing + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + + StopControllerType(USB_HC_XHCI); //(EIP52339+) + StopControllerType(USB_HC_UHCI); + StopControllerType(USB_HC_OHCI); + StopControllerType(USB_HC_EHCI); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: UsbHcStart +// +// Description: This function initializes the USB host controller and +// enumerate the root hub ports for possible USB devices. +// +// Input: HcStruc HC struc pointer +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHcStart(HC_STRUC* HcStruc) +{ + UINT8 Index = 0; + + USB_DEBUG(DEBUG_LEVEL_3, "Starting HC %X, HCNum %d, type %x\n", + HcStruc->wBusDevFuncNum, HcStruc->bHCNumber, HcStruc->bHCType); + + // Execute start routine of the host controller driver + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDStart)(HcStruc); + + // Check if the HC is running + if ((HcStruc->dHCFlag & HC_STATE_RUNNING) == 0) { + return USB_ERROR; + } + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + if (gUsbData->HcTable[Index] == NULL) { + continue; + } + if (HcStruc == gUsbData->HcTable[Index]) { + continue; + } + if (HcStruc->BaseAddress == gUsbData->HcTable[Index]->BaseAddress) { + break; + } + if (HcStruc->fpFrameList != NULL) { + if (HcStruc->fpFrameList == gUsbData->HcTable[Index]->fpFrameList) { + break; + } + } + if (HcStruc->usbbus_data != NULL) { + if (HcStruc->usbbus_data == gUsbData->HcTable[Index]->usbbus_data) { + break; + } + } +#if USB_RUNTIME_DRIVER_IN_SMM + if (HcStruc->wBusDevFuncNum == gUsbData->HcTable[Index]->wBusDevFuncNum) { + break; + } +#endif + } + + if (Index != gUsbData->HcTableCount) { + HcStruc->dHCFlag &= ~HC_STATE_RUNNING; + return USB_ERROR; + } + + HcStruc->dHCFlag |= HC_STATE_INITIALIZED; + +#if USB_RUNTIME_DRIVER_IN_SMM +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A)&&(CORE_COMBINED_VERSION >= 0x4028B) + UpdateAmiUsbSmmGlobalDataCrc32(gUsbData); +#endif +#endif + +#ifdef USB_CONTROLLERS_INITIAL_DELAY_LIST + for (Index = 0; Index < COUNTOF(gControllersInitialDelayList); Index++) { + if ((gControllersInitialDelayList[Index].Vid == HcStruc->Vid) && + (gControllersInitialDelayList[Index].Did == HcStruc->Did)) { + if (gControllersInitialDelayList[Index].DelayTime) { + FixedDelay(gControllersInitialDelayList[Index].DelayTime * 1000); + } + break; + } + } +#endif + + USB_DEBUG(DEBUG_LEVEL_3, "Enumerating HC#%d, type 0x%x\n", HcStruc->bHCNumber, HcStruc->bHCType); + // Issue enumerate call for this HC + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDEnumeratePorts)(HcStruc); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: UsbHcStop +// +// Description: This function stops the USB host controller. +// +// Input: HcStruc HC struc pointer +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHcStop(HC_STRUC* HcStruc) +{ + if ((HcStruc->dHCFlag & HC_STATE_RUNNING) == 0) { + return USB_ERROR; + } + + USB_DEBUG(DEBUG_LEVEL_3, "Stopping HC %X, HCNum %d, type %x\n", + HcStruc->wBusDevFuncNum, HcStruc->bHCNumber, HcStruc->bHCType); + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDStop)(HcStruc); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: CheckBiosOwnedHc +// +// Description: This function checks bios owned hc. +// Clear USB_FLAG_DRIVER_STARTED if we don't start +// any host controller. +// +// Input: None +// +// Output: None +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +CheckBiosOwnedHc( + VOID +) +{ + UINT8 Index; + HC_STRUC *HcStruc; + + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + HcStruc = gUsbData->HcTable[Index]; + if (HcStruc == NULL) { + continue; + } + if (HcStruc->dHCFlag & HC_STATE_RUNNING) { + return; + } + } + + gUsbData->dUSBStateFlag &= ~(USB_FLAG_DRIVER_STARTED); + + return; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_EnmumerateRootHubPorts +// +// Description: This function enumerates the root hub ports of the all +// selected type HCs +// +// +// Output: bType - HC type +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_EnumerateRootHubPorts (UINT8 bType) +{ + UINT8 Index; + HC_STRUC* fpHCStruc; + + USB_DEBUG(DEBUG_LEVEL_4, "Enumerating HC Ports.\n"); + for (Index = 0; Index < gUsbData->HcTableCount; Index++) { + // + // Get the HCStruc pointer associated with this controller + // + fpHCStruc = gUsbData->HcTable[Index]; + if (fpHCStruc == NULL) { + continue; + } + + if((fpHCStruc->bHCType) == bType && (fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + USB_DEBUG(DEBUG_LEVEL_3, "Enumerating HC#%d, type 0x%x\n", fpHCStruc->bHCNumber, bType); + // + // Issue enumerate call for this HC + // + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(bType)].pfnHCDEnumeratePorts)(fpHCStruc); + } + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_InitHostControllers +// +// Description: This function initializes the specified type of the HC +// from the provided list of host controller PCI addresses +// +// Output: pHCPCIAddrList Pointer to table of HC PCI addresses in the system +// bHCType Type of HC to be initialized (EHCI, OHCI etc) +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBInitHostController( + UINT16 * pHCPCIAddrList, + UINT8 bHCType) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_GetHubPortStatus +// +// Description: This function returns the hub port status +// +// Input: HcStruc HC struc pointer +// HubAddr USB device address of the hub or HC number +// BIT7 = 1/0 Roothub/Hub +// PortNum Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_GetHubPortStatus ( + HC_STRUC* HcStruc, + UINT8 HubAddr, + UINT8 PortNum, + BOOLEAN ClearChangeBits +) +{ + // + // Check whether the request is for root hub or generic hub + // + if (HubAddr & BIT7) { + // Root hub + return (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDGetRootHubStatus)( + HcStruc, PortNum, ClearChangeBits); + } else { + #if USB_DEV_HUB + return USBHub_GetPortStatus (HcStruc, HubAddr, PortNum, ClearChangeBits); + #else + return 0; + #endif + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_DisableHubPort +// +// Description: This function disables the hub port +// +// Output: fpHCStruc HC struc pointer +// bHubAddr USB device address of the hub or HC number +// BIT7 = 1/0 Roothub/Hub +// bPortNum Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_DisableHubPort( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bPortNum) +{ + // + // Check whether the request is for root hub or generic hub + // + if (bHubAddr & BIT7) { + // + // Issue the disable root hub call to disable the hub port + // + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDisableRootHub)( + fpHCStruc, + bPortNum); +#if USB_DEV_HUB + } + else { + USBHub_DisablePort (fpHCStruc, bHubAddr, bPortNum); +#endif + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_EnableHubPort +// +// Description: This function enables the hub port +// +// Output: fpHCStruc HC struc pointer +// bHubAddr USB device address of the hub or HC number +// BIT7 = 1/0 Roothub/Hub +// bPortNum Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_EnableHubPort ( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bPortNum) +{ + // + // Check whether the request is for root hub or generic hub + // + if (bHubAddr & BIT7) { + // + // Root hub + // Issue the disable root hub call to disable the hub port + // + return (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDEnableRootHub)(fpHCStruc, bPortNum); + } else { + #if USB_DEV_HUB + return USBHub_EnablePort (fpHCStruc, bHubAddr, bPortNum); + #else + return USB_ERROR; // Only root hub could be successfully enabled + #endif + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_ResetHubPort +// +// Description: This function resets the hub port +// +// Input: HcStruc HC struc pointer +// HubAddr USB device address of the hub or HC number +// BIT7 = 1/0 Roothub/Hub +// PortNum Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_ResetHubPort ( + HC_STRUC* HcStruc, + UINT8 HubAddr, + UINT8 PortNum) +{ + // + // Check whether the request is for root hub or generic hub + // + if (HubAddr & BIT7) { + // + // Root hub + // Issue the reset root hub call to reset the hub port + // + return (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDResetRootHub)(HcStruc, PortNum); + } else { + #if USB_DEV_HUB + return USBHub_ResetPort (HcStruc, HubAddr, PortNum); + #else + return USB_ERROR; // Only root hub could be successfully reset + #endif + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_DetectNewDevice +// +// Description: This function checks the port status provided and depending +// on the status it invokes device connect/disconnect routine +// +// Output: fpHCStruc Pointer to HCStruc +// bHubAddr For root port this is the host controller index +// in gUsbData->aHCStrucTable combined with BIT7; +// For devices connected to a hub this is parent +// hub USB address +// bHubPort Parent hub port number +// bPortStatus Port status read +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USB_DetectNewDevice( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bHubPort, + UINT8 bPortStatus +) +{ + UINT8 bErrorFlag = 0; + UINT16 wDescLength; + UINT8 bDevConfigured; + UINTN ConfigLevel = 0; + UINT16 wTotalLength; + UINT8 *fpBuffer = NULL; + DEV_INFO *fpDevInfo, + *fPointer; + DEV_DESC *fpDevDesc; + CNFG_DESC *fpCnfgDesc; + INTRF_DESC *fpIntrfDesc; + UINT8 *DevMiscInfo; + UINT8 Status; + BOOLEAN SkipConnectBeep = FALSE; //(EIP64781+) + UINT16 OrgTimeOutValue; //(EIP75441+) + UINT8 DeviceAddress; + + // + // Get the temporary device info structure pointer (index 0) + // + fpDevInfo = gUsbData->aDevInfoTable; + + // + // Fill the necessary entries in the device info + // + fpDevInfo->Flag = DEV_INFO_VALID_STRUC; + fpDevInfo->bDeviceAddress = 0; + //fpDevInfo->wEndp0MaxPacket = 0x40; //(EIP98230-) + fpDevInfo->bDeviceType = 0; + fpDevInfo->wIncompatFlags = 0; + fpDevInfo->DevMiscInfo = NULL; + + // + // Fill the hub/host controller information + // + fpDevInfo->bHubDeviceNumber = bHubAddr; + fpDevInfo->bHubPortNumber = bHubPort; + + // + // Fill the device speed + // +USB_DEBUG(DEBUG_LEVEL_3, "USB_DetectNewDevice: wPS = %x\n", bPortStatus); + fpDevInfo->bEndpointSpeed = (bPortStatus & USB_PORT_STAT_DEV_SPEED_MASK) >> + USB_PORT_STAT_DEV_SPEED_MASK_SHIFT; + + //(EIP98145+)> +#if SHOW_SKIP_PORT_INFORMATION +{ + UINT8 i; + DEV_INFO *tmpDevInfo; + tmpDevInfo = fpDevInfo; + USB_DEBUG(3, "==== SHOW_SKIP_PORT_INFORMATION ==== \n"); + USB_DEBUG(DEBUG_LEVEL_3, "BDF %x \nRoutePath = ",fpHCStruc->wBusDevFuncNum); + for(i=0;i<5;i++) + { + if(tmpDevInfo->bHubDeviceNumber & BIT7) + { + USB_DEBUG(3, "\nRootPort %x \n",tmpDevInfo->bHubPortNumber); + break; + } + USB_DEBUG(3, "%x ",tmpDevInfo->bHubPortNumber); + tmpDevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, 0, tmpDevInfo->bHubDeviceNumber, 0); + if(tmpDevInfo == NULL) break; + } + USB_DEBUG(3, "==== SHOW_SKIP_PORT_INFORMATION ==== \n"); +} +#endif + //<(EIP98145+) + //(EIP98230+)> + switch (fpDevInfo->bEndpointSpeed) { + case USB_DEV_SPEED_SUPER_PLUS: + case USB_DEV_SPEED_SUPER: + fpDevInfo->wEndp0MaxPacket = 0x200; + break; + case USB_DEV_SPEED_HIGH: + fpDevInfo->wEndp0MaxPacket = 0x40; + break; + case USB_DEV_SPEED_FULL: + case USB_DEV_SPEED_LOW: + fpDevInfo->wEndp0MaxPacket = 0x08; + break; + } + //<(EIP98230+) + + // + // Fill the HC struc index value + // + fpDevInfo->bHCNumber = fpHCStruc->bHCNumber; + + bErrorFlag = TRUE; // Assume as error + bDevConfigured = FALSE; // No device configured + + // + // Allocate memory for device requests + // + ConfigLevel = USB_ERR_DEV_INIT_MEM_ALLOC; // For proper error handling + fpBuffer = USB_MemAlloc (GET_MEM_BLK_COUNT(MAX_CONTROL_DATA_SIZE)); + if (fpBuffer == NULL) { + SpeakerBeep(8, 0x2000, fpHCStruc); + return (DEV_INFO*)ConfigLevel; + } + ConfigLevel = USB_ERR_DEV_INIT_GET_DESC_8; + + // Initialize HC specific data before device configuration + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDInitDeviceData)( + fpHCStruc, fpDevInfo, bPortStatus, &DevMiscInfo); + if(Status != USB_SUCCESS) { + USB_MemFree(fpBuffer, (UINT8)(MAX_CONTROL_DATA_SIZE / sizeof(MEM_BLK))); + SpeakerBeep(8, 0x2000, fpHCStruc); + return (DEV_INFO*)ConfigLevel; + } + fpDevInfo->DevMiscInfo = (VOID*)DevMiscInfo; + +// +// Next send a GetDescriptor command to the device to get its Device +// Descriptor. Assume a MaxPacket size of 64 bytes (the device will use 8, +// 16, 32, or 64). Regardless of the packet size used by te device we can +// always get the real MaxPacket size that the device is using, because +// this piece of information is at offset 7 in the device descriptor. +// + OrgTimeOutValue = gUsbData->wTimeOutValue; //(EIP75441+) + gUsbData->wTimeOutValue = 1000; //(EIP75441+) + + fpDevDesc = (DEV_DESC*)USB_GetDescriptor( + fpHCStruc, + fpDevInfo, + fpBuffer, + 8, + DESC_TYPE_DEVICE, + 0); + + gUsbData->wTimeOutValue = OrgTimeOutValue; //(EIP75441+) + if(fpDevDesc == NULL) { + goto detection_complete; + } + + // + // Get and store the endpoint 0 max packet size + // + ConfigLevel = USB_ERR_DEV_INIT_SET_ADDR; + // + // Endpoint 0 max packet size check. + // CyQ've USB modem(Model:MQ4UFM560) return invalid device descriptor after + // warm reset. + // + //(EIP81612)> + if (fpDevDesc->BcdUsb >= 0x0300) { + fpDevInfo->wEndp0MaxPacket = (UINT16)1 << fpDevDesc->MaxPacketSize0; + } else { + fpDevInfo->wEndp0MaxPacket = (fpDevDesc->MaxPacketSize0)? + (UINT16)fpDevDesc->MaxPacketSize0 : 0x40; + } + //<(EIP81612) + //(EIP73803)> + if((fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_LOW) || + (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_FULL) || + (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_HIGH)){ + FixedDelay(10 * 1000); // 10msec delay + } + //<(EIP73803) + + //To assign an address to a USB device, the USB device transitions the state + //from the Default to the Address state. + for (DeviceAddress = 1; DeviceAddress < 64; DeviceAddress++) { + if (gUsbData->DeviceAddressMap & Shl64(1, DeviceAddress)) { + break; + } + } + + if (DeviceAddress == 64) { + goto detection_complete; + } + Status = USB_SetAddress(fpHCStruc, fpDevInfo, DeviceAddress); + if (Status == USB_ERROR) { + goto detection_complete; + } + gUsbData->DeviceAddressMap &= ~(Shl64(1, DeviceAddress)); + fpDevInfo->bDeviceAddress = DeviceAddress; + FixedDelay(2 * 1000); + + // + // Now send a GetDescriptor command to the device to get its device descriptor. + // + fpDevDesc = (DEV_DESC*)USB_GetDescriptor( + fpHCStruc, + fpDevInfo, + fpBuffer, + 18, + DESC_TYPE_DEVICE, + 0); + + //ASSERT(fpDevDesc != NULL); + if (fpDevDesc == NULL) { + goto detection_complete; + } + // If a descriptor returns with a value in its length field that is + // less than defined by USB specification, the descriptor is invalid. + if (fpDevDesc->DescLength < 18) { + goto detection_complete; + } + if (fpDevDesc->NumConfigs == 0) { + fpDevDesc->NumConfigs = 1; + } + + MemCopy((UINT8*)fpDevDesc, (UINT8*)&fpDevInfo->DevDesc, sizeof(DEV_DESC)); + + ConfigLevel = USB_ERR_DEV_INIT_GET_DESC_200; + // + // Get the relevant information from the descriptor and store it in + // device information struture + // + fpDevInfo->wVendorId = fpDevDesc->VendorId; + fpDevInfo->wDeviceId = fpDevDesc->DeviceId; +// +// Look at each of the device's ConfigDescriptors and InterfaceDescriptors +// until an InterfaceDescriptor is found with BaseClass, SubClass, and +// Protocol fields indicating boot keyboard, mouse, hub or storage support. +// + fpDevInfo->bConfigNum = 0; + + if (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_FULL) { + FixedDelay(100); + } + + do { // For processing multiple configurations + //(EIP70933+)> + fpCnfgDesc = (CNFG_DESC*)USB_GetDescriptor( + fpHCStruc, + fpDevInfo, + fpBuffer, + 0xFF, + DESC_TYPE_CONFIG, + fpDevInfo->bConfigNum); + if(fpCnfgDesc == NULL) { + break; + } + wTotalLength = fpCnfgDesc->wTotalLength; + if (wTotalLength > 0xFF) { + if(wTotalLength > (MAX_CONTROL_DATA_SIZE - 1)) { + wTotalLength = MAX_CONTROL_DATA_SIZE - 1; + } + fpCnfgDesc = (CNFG_DESC*)USB_GetDescriptor( + fpHCStruc, + fpDevInfo, + fpBuffer, + wTotalLength, + DESC_TYPE_CONFIG, + fpDevInfo->bConfigNum); + //<(EIP70933+) + if(fpCnfgDesc == NULL) { + break; + } + } + if (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_FULL) { + FixedDelay(100); + } +// +// fpCnfgDesc should now point to a ConfigDescriptor. Verify this and +// then get some fields out of it. Then point to the next descriptor. +// + if(fpCnfgDesc->bDescType == DESC_TYPE_CONFIG) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDEnableEndpoints)( + fpHCStruc, fpDevInfo, (UINT8*)fpCnfgDesc); + + //wTotalLength = fpCnfgDesc->wTotalLength; //(EIP70933-) + wDescLength = (UINT8)fpCnfgDesc->bDescLength; + fpDevInfo->bConfigNum = fpCnfgDesc->bConfigValue; + + //(EIP70933-)> +/* + if(wTotalLength > (MAX_CONTROL_DATA_SIZE - 1)) { + wTotalLength = MAX_CONTROL_DATA_SIZE - 1; + } +*/ + //<(EIP70933-) + + // Check if the device has alternate setting for the interface. + for (;wDescLength < wTotalLength;) { + // + // fpIntrfDesc should now point to an InterfaceDescriptor. Verify this + // and then check its BaseClass, SubClass, and Protocol fields for + // usable devices. + // + fpIntrfDesc = (INTRF_DESC*)((UINT8*)fpCnfgDesc + wDescLength); + //(EIP59601+)> + if ((fpIntrfDesc->bDescLength == 0) || + ((fpIntrfDesc->bDescLength + wDescLength) > wTotalLength)) { + break; + } + if ((fpIntrfDesc->bDescType == DESC_TYPE_INTERFACE) && (fpIntrfDesc->bAltSettingNum != 0)) { + fpDevInfo->Flag |= DEV_INFO_ALT_SETTING_IF; + break; + } + if (fpIntrfDesc->bDescLength) { + wDescLength += (UINT16)fpIntrfDesc->bDescLength; + } else { + break; + } + } + + wDescLength = (UINT8)fpCnfgDesc->bDescLength; + + for (;wDescLength < wTotalLength;) { + // + // fpIntrfDesc should now point to an InterfaceDescriptor. Verify this + // and then check its BaseClass, SubClass, and Protocol fields for + // usable devices. + // + fpIntrfDesc = (INTRF_DESC*)((UINT8*)fpCnfgDesc + wDescLength); + //(EIP59601+)> + if ((fpIntrfDesc->bDescLength == 0) || + ((fpIntrfDesc->bDescLength + wDescLength) > wTotalLength)) { + break; + } + //<(EIP59601+) + if ((fpIntrfDesc->bDescType == DESC_TYPE_INTERFACE) && (fpIntrfDesc->bAltSettingNum == 0)) { + fpDevInfo->bInterfaceNum = fpIntrfDesc->bInterfaceNum; + fpDevInfo->bAltSettingNum = 0; + //USB_DEBUG(DEBUG_LEVEL_6, "USBIdentifyAndConfigureDevice::fpIntrfDesc %lx\n",fpIntrfDesc); + USB_DEBUG(DEBUG_LEVEL_3, "USBIdentifyAndConfigureDevice:: %04x/%04x Intrf %d, AltSetting %d\n", + fpDevInfo->wVendorId, fpDevInfo->wDeviceId, fpIntrfDesc->bInterfaceNum, fpIntrfDesc->bAltSettingNum); + USB_DEBUG(3, "fpCnfgDesc %x, wDescLength 0x%x, wTotalLength 0x%x\n", fpCnfgDesc, wDescLength, wTotalLength); + fPointer = USBIdentifyAndConfigureDevice( + fpHCStruc, + fpDevInfo, + (UINT8*)fpCnfgDesc, + wDescLength, + wTotalLength); + if(fPointer != NULL) { + fpDevInfo = fPointer; + bDevConfigured = TRUE; // At-least one device is configured + //(EIP64781+)> + if(gUsbData->dUSBStateFlag & USB_FLAG_SKIP_CARD_READER_CONNECT_BEEP) { + if(fpDevInfo->bBaseClass == BASE_CLASS_MASS_STORAGE) { + SkipConnectBeep = TRUE; + } + } + //<(EIP64781+) + } + //(EIP22046+)> + // + // There is one more config. Set device info structure entry 0 for it + // + if ((fpCnfgDesc->bNumInterfaces > 1) && bDevConfigured) { + gUsbData->aDevInfoTable[0].Flag |= DEV_INFO_MULTI_IF; + } + //<(EIP22046+) + } + if (fpIntrfDesc->bDescLength && + !(fpIntrfDesc->bDescType == DESC_TYPE_INTERFACE && + fpIntrfDesc->bBaseClass == BASE_CLASS_HUB)) { + wDescLength += (UINT16)fpIntrfDesc->bDescLength; + if (wDescLength < wTotalLength) { + //(EIP22046-)> + // + // There is one more config. Set device info structure entry 0 for it + // + /* + if (fpDevInfo->bInterfaceNum > 0) { + fpDevInfo->Flag |= DEV_INFO_MULTI_IF; + } + gUsbData->aDevInfoTable[0].Flag |= DEV_INFO_MULTI_IF; + */ + //<(EIP22046-) + fpDevInfo = gUsbData->aDevInfoTable; + } + } else { + break; // fpIntrfDesc->bDescLength == 0 + } + } // while () + } // if + // + // Check if we have at least one usable device + // + if (bDevConfigured) { + bErrorFlag = FALSE; // Device successfully configured + ConfigLevel = (UINTN)gUsbData->aDevInfoTable; + goto detection_complete; + } + else { + fpDevInfo->bConfigNum++; + } + } while (fpDevInfo->bConfigNum < fpDevInfo->DevDesc.NumConfigs); // while + +detection_complete: + // + // At this point, if bErrorFlag is FALSE then we successfully configured + // atleast a device. + // If bErrorFlag is TRUE then there is error in configuring the device + // + if (bErrorFlag) { + USBLogError((UINT16)ConfigLevel); // Log configuration level + + SpeakerBeep(8, 0x2000, fpHCStruc); + + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDeinitDeviceData) + (fpHCStruc, fpDevInfo); + if(ConfigLevel != USB_ERR_DEV_INIT_GET_DESC_8) { + // + // Disable the hub port + // + USB_DisableHubPort( + fpHCStruc, + fpDevInfo->bHubDeviceNumber, + fpDevInfo->bHubPortNumber); + ConfigLevel = 0; + } + if (fpDevInfo->bDeviceAddress) { + gUsbData->DeviceAddressMap |= Shl64(1, fpDevInfo->bDeviceAddress); + } + } + else { + //(EIP64781+)> + if(!SkipConnectBeep) { + SpeakerBeep(4, 0x1000, fpHCStruc); + } + //<(EIP64781+) + } + USB_MemFree(fpBuffer, (UINT8)(MAX_CONTROL_DATA_SIZE / sizeof(MEM_BLK))); + + return (DEV_INFO*)ConfigLevel; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_StopDevice +// +// Description: This function stops the device: +// - calls its disconnect function if available +// - stops polling the device's interrupt endpoint +// - updates device address memory map +// +// +// Output: fpHCStruc Pointer to HCStruc +// bHCNubAddr Hub address +// bHCPort Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_StopDevice( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bHCPort) +{ + UINT8 bCount; + DEV_DRIVER* fpDevDriver; + DEV_INFO* fpDevice; + UINT8 Status; + + Status = USB_ERROR; + // + // Find the device entry that would match the input. + // + for (bCount = 1; bCount < MAX_DEVICES; bCount++) + { + fpDevice = &gUsbData->aDevInfoTable[bCount]; + if((fpDevice->Flag & (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_DUMMY)) == + DEV_INFO_VALID_STRUC) { + if((fpDevice->bHubDeviceNumber == bHubAddr) && + (fpDevice->bHubPortNumber == bHCPort)) + { + // + // Device found - issue disconnect call for the device + // + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + if (!(fpDevice->Flag & DEV_INFO_IN_QUEUE)) { + USB_SmiQueuePut(fpDevice); + fpDevice->Flag |= DEV_INFO_IN_QUEUE; + } + } + + fpDevDriver = UsbFindDeviceDriverEntry(fpDevice->fpDeviceDriver); + // + // Check disconnect function is valid, if yes - execute it + // + if (fpDevDriver && fpDevDriver->pfnDisconnectDevice) + { + fpDevDriver->pfnDisconnectDevice(fpDevice); + fpDevice->fpDeviceDriver = NULL; + } else { + // + // Stop polling the device's interrupt endpoint + // + if (fpDevice->IntInEndpoint) { + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDeactivatePolling) + (fpHCStruc, fpDevice); + fpDevice->IntInEndpoint = 0; + } + } + + // HC device removal call + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDeinitDeviceData) + (fpHCStruc, fpDevice); + + // Reset the disconnecting flag + fpDevice->Flag &= ~DEV_INFO_DEV_DISCONNECTING; + + // + // Update Device Address Map, preserving the address for registered devices + // + gUsbData->DeviceAddressMap |= Shl64(1, fpDevice->bDeviceAddress); + fpDevice->Flag &= ~DEV_INFO_DEV_PRESENT; + if (!(fpDevice->Flag & (DEV_INFO_DEV_BUS | DEV_INFO_MASS_DEV_REGD))) { + // Reset the device info structure validity ~flag + fpDevice->Flag &= ~DEV_INFO_VALID_STRUC; + } + USB_DEBUG(3, "Release Dev[%d]: %x, flag %x\n", bCount, fpDevice, fpDevice->Flag); + } + } + } + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_DisconnectDevice +// +// Description: This function is called when a device disconnect is +// detected. This routine disables the hub port and stops the +// device and its children by calling another routine. +// +// Output: fpHCStruc Far pointer to HCStruc of the host controller +// bHubAddr USB device address of the hub whose status +// has changed +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// bPortNum Port number +// +// Output: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_DisconnectDevice( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bHCPort) +{ + // + // A device has been disconnected from the USB. First disable the hub port + // that the device was plugged into. Then free up the device's entry in the + // DeviceTable. If there an error occurs while disabling the port, assume + // that the device is still present an leave its DeviceTable entry in place. + // + USB_DisableHubPort(fpHCStruc, bHubAddr, bHCPort); + + USB_StopDevice(fpHCStruc, bHubAddr, bHCPort); + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: USBCheckPortChange +// +// Description: This routine processes the port status change (like connect, +// disconnect, etc.) for the root hub and external hubs. +// +// Output: HcStruc Pointer to Host Controller structure +// HubAddr Device address of the hub whose status +// has changed: +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// PortNum Hub port number +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBCheckPortChange ( + HC_STRUC *HcStruc, + UINT8 HubAddr, + UINT8 PortNum +) +{ + UINT8 PortStatus; + DEV_INFO *Dev; + UINT8 Count; + + for (Count = 0; Count < 5; Count++) { + PortStatus = USB_GetHubPortStatus(HcStruc, HubAddr, PortNum, TRUE); + + // + // Check the obtained port status + // + if (PortStatus == USB_ERROR) { + return USB_ERROR; + } + if (!(PortStatus & USB_PORT_STAT_DEV_OWNER)) { + return USB_SUCCESS; + } + if (OEMSkipList(HubAddr,PortNum,HcStruc->wBusDevFuncNum,0,0)) { + USB_DEBUG(3, "Match the skip table ; skipping this device.\n"); //(EIP98145) + return USB_SUCCESS; + } + if (!Count && !(PortStatus & USB_PORT_STAT_DEV_CONNECT_CHANGED)) { + return USB_SUCCESS; + } + + if (PortStatus & USB_PORT_STAT_DEV_CONNECTED) { + if (gUsbData->bHandOverInProgress) { + USB_DisableHubPort(HcStruc, HubAddr, PortNum); + return USB_SUCCESS; + } + if ((Count != 0) || !(PortStatus & USB_PORT_STAT_DEV_ENABLED)) { + // Reset and enable the port + USB_ResetHubPort(HcStruc, HubAddr, PortNum); + USB_EnableHubPort(HcStruc, HubAddr, PortNum); + PortStatus = USB_GetHubPortStatus(HcStruc, HubAddr, PortNum, TRUE); + + if (PortStatus == USB_ERROR) { + return USB_ERROR; + } + if (!(PortStatus & USB_PORT_STAT_DEV_OWNER)) { + return USB_SUCCESS; + } + if (!(PortStatus & USB_PORT_STAT_DEV_CONNECTED)) { + // Some device will be disconnected after + // port reset, and reconnected for a while. + FixedDelay(100 * 1000); + continue; + } + // Check whether port is enabled + if (!(PortStatus & USB_PORT_STAT_DEV_ENABLED)) { + FixedDelay(100 * 1000); // 100msec delay + continue; + } + } + Dev = USB_DetectNewDevice(HcStruc, HubAddr, PortNum, PortStatus); + if ((UINTN)Dev == USB_ERR_DEV_INIT_GET_DESC_8) { + FixedDelay(100 * 1000); // 100msec delay + continue; + } + if ((UINTN)Dev == 0) { + return USB_ERROR; + } + if ((UINTN)Dev > USB_ERR_DEV_INIT_GET_DESC_200) { + return USB_SUCCESS; + } + SpeakerBeep(16, 0x4000, HcStruc); // Issue error beep + return USB_ERROR; + } else { // Disconnect + USB_DisconnectDevice(HcStruc, HubAddr, PortNum); + SpeakerBeep(8, 0x1000, HcStruc); + return USB_SUCCESS; + } + } + if (Count == 5) { + USB_DisableHubPort(HcStruc, HubAddr, PortNum); + return USB_ERROR; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_MemAlloc +// +// Description: This routine allocates blocks of memory from the global +// memory pool +// +// Output: bNumBlocks Number of 32 byte blocks needed +// +// Output: Start offset to the allocated block (NULL on error) +// +// NOTES: This routine allocates continuous 32 byte memory blocks. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID _FAR_ * +USB_MemAlloc(UINT16 wNumBlk) +{ + UINT8 bMemIsFound = FALSE, + bBitCount = 0, + bStart = 0; + UINT16 wCount; + UINT16 Count = 0; // Contiguous blocks counter + + UINT16 BlkOffset = 0, + wMapDwordPtr; + //(EIP89641)> + UINT16 PageCount = 0; + UINT16 MapDwordCount = 0; + UINT32 BlksStsDwordsPerPage = 0; + + UINT32 dMask, + dTemp; + + if (wNumBlk == 0) return NULL; + +#if USB_FORCE_64BIT_ALIGNMENT + if (wNumBlk % 2) wNumBlk++; +#endif + wCount = wNumBlk; + + BlksStsDwordsPerPage = (gUsbData->MemBlkStsBytes >> 2) / gUsbData->MemPages; + + // + // Locate wNumBlk contiguous blocks from each memory page + // + for(PageCount = 0; (PageCount < gUsbData->MemPages) && !bMemIsFound; PageCount++) { + + // Do not reset the counter if the allocated blocks greater than a page. + if (wNumBlk <= (0x1000 / sizeof(MEM_BLK))) { + Count = 0; // Reset contiguous blocks counter + } + + for (MapDwordCount = 0; MapDwordCount < BlksStsDwordsPerPage; MapDwordCount++) { + // + // Read the next DWORD memory map data + // + wMapDwordPtr = (PageCount * BlksStsDwordsPerPage) + MapDwordCount; + dTemp = gUsbData->aMemBlkSts[wMapDwordPtr]; + + for (bBitCount = 0; bBitCount < 32; bBitCount++) { + BlkOffset++; + if (dTemp & (UINT32)(1 << bBitCount)) { + Count++; // Found another free block + if(Count == wCount) { + BlkOffset = (UINT16)(BlkOffset-Count); + bMemIsFound = TRUE; + break; // Found the requested number of free blocks + } + } + else + { + Count = 0; // Reset contiguous blocks counter + } + } + if (bMemIsFound) break; + } + } + //<(EIP89641) + if (!bMemIsFound) { + ASSERT(FALSE); + return NULL; + } + +// +// Change the appropriate bits in the memory map to indicate that some memory +// is being allocated +// +// At this point, +// bBitCount points to the end of the block within DWORD +// wMapDwordPtr points to the status dword in question + +// We have to reset bCount number of bits starting from +// wMapDwordPtr[bBitCount] to wStsX[BitPosY] +// where wStsX is the status double word of the starting block, +// BitPosY is the bit position of the starting block. +// + USB_DEBUG(DEBUG_LEVEL_4, "wMapDwordPtr = %d\n", wMapDwordPtr); +// +// Let us have a do loop to do the trick +// + do { + // + // Find out how many bits we can reset in current (pointed by wMapDwordPtr) + // double word + // + Count = (UINT16)((bBitCount >= (wCount-1)) ? wCount : bBitCount+1); + // + // Find out the starting bit offset + // + bStart = (UINT8)(bBitCount + 1 - Count); + // + // Form the 32bit mask for the AND operation + // First prepare the bits left on the left + // + // Note: FFFFFFFF << 32 treated differently by different compilers; it + // results as 0 for 16 bit compiler and FFFFFFFF for 32 bit. That's why + // we use caution while preparing the AND mask for the memory map update. + // + dMask = ((Count + bStart) < 32) ? (0xFFFFFFFF << (Count + bStart)) : 0; + + // + // Second, prepare the bits on the right + // + if (bStart) + { + dMask = dMask | ~(0xFFFFFFFF << bStart); + } + + // + // Reset the specified number of bits + // + gUsbData->aMemBlkSts[wMapDwordPtr] &= dMask; + + // + // Update the bCount, StsWordCount & BitCount + // + bBitCount = 31; // End of previous double word where we have to start + wMapDwordPtr--; // Previous double word + wCount = wCount - Count; + } while ( wCount ); + + USB_DEBUG(DEBUG_LEVEL_4, "MemAlloc: %d block(s) at %x %x %x\n", + wNumBlk, + gUsbData->fpMemBlockStart + BlkOffset * sizeof(MEM_BLK), + gUsbData->aMemBlkSts[0], + gUsbData->aMemBlkSts[1]); + + return ((VOID _FAR_ *) + (gUsbData->fpMemBlockStart + (UINT32)BlkOffset * sizeof(MEM_BLK))); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_MemFree +// +// Description: This routine frees the chunk of memory allocated using +// the USBMem_Alloc call +// +// Output: fpPtr Pointer to the memory block to be freed +// bNumBlocks Number of 32 byte blocks to be freed +// +// Output: Start offset to the allocated block (NULL on error) +// +// NOTES: This routine frees continuous memory blocks starting +// from the fpPtr. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_MemFree ( + VOID _FAR_ * fpPtr, + UINT16 wNumBlk) +{ + UINT8 bOffset, bCount; + UINT16 wBlkCount, wBlkOffset, wStsWord; + +#if USB_FORCE_64BIT_ALIGNMENT + if (wNumBlk % 2) wNumBlk++; +#endif + wBlkCount = wNumBlk; + wBlkOffset = 0; + + // + // Check for pointer validity + // + if (fpPtr == NULL) return USB_ERROR; + + if ((fpPtr < (VOID *)gUsbData->fpMemBlockStart) || + (fpPtr > (VOID *)(gUsbData->fpMemBlockStart + + (MEM_BLK_COUNT+1)*sizeof(MEM_BLK)))) { + return USB_ERROR; + } + + wBlkOffset = (UINT16)((UINTN)fpPtr - (UINTN)gUsbData->fpMemBlockStart) / sizeof (MEM_BLK); + + if (wBlkOffset >= MEM_BLK_COUNT) { + return USB_ERROR; + } + + wStsWord = (UINT16)(wBlkOffset >> 5); // Divide by 32 + bOffset = (UINT8)(wBlkOffset & 0x1F); // Mod 32 + bCount = 0; + + do { + gUsbData->aMemBlkSts[wStsWord] |= ((UINT32)1 << (bCount + bOffset)); + wBlkCount--; + bCount++; + + if ((bCount + bOffset) && (!((bCount + bOffset) & 0x1F))) { + wStsWord ++; + bCount = bOffset = 0; + } + } while (wBlkCount); + + USB_DEBUG(DEBUG_LEVEL_4, "MemFree: %d block(s) at %x %x %x\n", + wNumBlk, fpPtr, + gUsbData->aMemBlkSts[0], gUsbData->aMemBlkSts[1]); + // + // Pointer is valid. Fill the memory with 0's + // + MemFill (fpPtr, (UINT32)(wNumBlk * sizeof (MEM_BLK)), 0); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_InstallCallBackFunction +// +// Description: This function adds a new callback function to the globall +// callback function list and returns the index of it. +// +// Output: pfnCallBackFunction Callback function address +// +// Output: Callback function index +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_InstallCallBackFunction ( + CALLBACK_FUNC CallBackFunction +) +{ + UINT8 Index; + // + // Check whether this function is already installed or none found + // + for (Index = 0; Index < MAX_CALLBACK_FUNCTION; Index++) { + // + // Check for null entry + // + if (gUsbData->aCallBackFunctionTable[Index] == 0) { + break; // No entry found + } + + if (gUsbData->aCallBackFunctionTable[Index] == CallBackFunction) { + return (UINT8)(Index+1); + } + } + + ASSERT(Index != MAX_CALLBACK_FUNCTION); + if (Index == MAX_CALLBACK_FUNCTION) { + EFI_DEADLOOP(); // Exceeding max # of callback function is illegal + } else { + // + // Store the call back function + // + gUsbData->aCallBackFunctionTable[Index] = CallBackFunction; + } + + return (UINT8)(Index + 1); +} + +DEV_DRIVER* +UsbFindDeviceDriverEntry( + DEV_DRIVER* DevDriver +) +{ + UINTN Index; + + if (DevDriver == NULL) { + return DevDriver; + } + + for (Index = 0; Index < MAX_DEVICE_TYPES; Index++) { + if (DevDriver == &gUsbData->aDevDriverTable[Index]) { + return &gUsbData->aDevDriverTable[Index]; + } + if (DevDriver == &gUsbData->aDelayedDrivers[Index]) { + return &gUsbData->aDelayedDrivers[Index]; + } + } + + return NULL; + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_GetDescriptor +// +// Description: This function executes a get descriptor command to the +// given USB device and endpoint +// +// Output: fpHCStruc HCStruc pointer +// fpDevInfo Device info pointer +// fpBuffer Buffer to be used for the transfer +// wLength Size of the requested descriptor +// bDescType Requested descriptor type +// bDescIndex Descriptor index +// +// Output: Pointer to memory buffer containing the descriptor +// NULL on error +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8* +USB_GetDescriptor( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpBuffer, + UINT16 wLength, + UINT8 bDescType, + UINT8 bDescIndex) +{ + UINT8 bGetDescIteration; + UINT16 wReg, + wStatus; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return NULL; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return NULL; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); + if (EFI_ERROR(EfiStatus)) { + return NULL; + } + gCheckUsbApiParameter = FALSE; + } +#endif + //(EIP60640)> + for (bGetDescIteration = 0; bGetDescIteration < 5; bGetDescIteration++) { + wReg = (UINT16)((bDescType << 8) + bDescIndex); + wStatus = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDControlTransfer)( + fpHCStruc, + fpDevInfo, + (UINT16)USB_RQ_GET_DESCRIPTOR, + (UINT16)0, + wReg, + fpBuffer, + wLength); + if (wStatus) { + return fpBuffer; + } + if (gUsbData->dLastCommandStatusExtended & USB_TRNSFR_TIMEOUT) { + break; + } + FixedDelay(10 * 1000); + } + //<(EIP60640) + return NULL; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_SetAddress +// +// Description: This function sets the USB device address of device 0 to +// the given value. After this call the USB device will respond +// at its new address. +// +// Output: fpHCStruc Pointer to HCStruc structure +// fpDevInfo Pointer to device info structure +// bNewDevAddr New device address to set +// +// Output: USB_SUCCESS or USB_ERROR +// +// Notes: Skip SET_ADDRESS request for XHCI controllers +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_SetAddress( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8 bNewDevAddr) +{ + //(EIP60640)> + UINT8 SetAddressIteration; + + for (SetAddressIteration = 0; SetAddressIteration < 5; SetAddressIteration++) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDControlTransfer)( + fpHCStruc, + fpDevInfo, + (UINT16)USB_RQ_SET_ADDRESS, + 0, + (UINT16)bNewDevAddr, + 0, + 0); + if (!(gUsbData->bLastCommandStatus & USB_CONTROL_STALLED )) { + USB_DEBUG(DEBUG_LEVEL_5, "USB_SetAddress#%d\n",bNewDevAddr); + return USB_SUCCESS; + } + } + return USB_ERROR; + //<(EIP60640) +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_SetConfig +// +// Description: This function sets the device configuration. +// +// Input: HcStruc Pointer to HCStruc structure +// DevInfo Pointer to device info structure +// ConfigNum Configuration Value +// +// Output: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_SetConfig( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 ConfigNum) +{ + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDControlTransfer)( + HcStruc, + DevInfo, + USB_RQ_SET_CONFIGURATION, + 0, + (UINT16)ConfigNum, + 0, + 0); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: UsbSetInterface +// +// Description: This function sets the device interface. +// +// Input: HcStruc Pointer to HCStruc structure +// DevInfo Pointer to device info structure +// InterfaceNum Interface Value +// +// Output: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbSetInterface( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 InterfaceNum +) +{ + USB_DEBUG(3, "UsbSetInterface %d\n", InterfaceNum); + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDControlTransfer)( + HcStruc, + DevInfo, + USB_RQ_SET_INTERFACE, + 0, + (UINT16)InterfaceNum, + 0, + 0); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USBLogError +// +// Description: This routine logs the USB error in the data area. This +// logged errors will be displayed during the POST. +// +// Output: wErrorCode Error code to log +// +// Output: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBLogError(UINT16 wErrorCode) +{ + // + // First check for end of the buffer + // + if(gUsbData->bErrorLogIndex < MAX_USB_ERRORS_NUM) + { + // + // Still have space to log errors + // + gUsbData->aErrorLogBuffer[gUsbData->bErrorLogIndex] = wErrorCode; + gUsbData->bErrorLogIndex++; + } + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_GetDeviceInfoStruc +// +// Description: This function is used to retrieve the device info structure +// for the particular device address & HCStruc +// +// Output: bSearchFlag Flag indicating search type +// = USB_SRCH_DEV_ADDR to search by device address and +// HCStruc pointer +// = USB_SRCH_DEV_TYPE to search by device type +// = USB_SRCH_HC_STRUC to search by HC struc pointer +// = USB_SRCH_DEV_NUM to count the number of devices connected: +// if fpHCStruc is not NULL - count only devices connected to +// certain controller, otherwise - all devices of requested +// type. +// = USB_SERCH_DEV_INDX to search by device location in the DEV_INFO: +// a) if fpDevInfo <> 0 return index or the fpDevInfo +// b) if bDevAddr <> 0 return the corresponding fpDevInfo +// c) if both bDevAddr <> 0 and fpDevInfo <> 0, consider a) +// +// fpDevInfoPtr Pointer to the device info structure from where the +// search begins (if 0 start from first entry) +// bDev Device address/drive number/device type +// pHCStruc Pointer to the HCStruc structure +// +// Output: Depending on bSearchFlag this function returns: +// - pointer to DEV_INFO structure +// - table index +// - number of devices +// Function returns NULL if device is not found. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USB_GetDeviceInfoStruc( + UINT8 bSearchFlag, + DEV_INFO* fpDev_Info, + UINT8 bDev, + HC_STRUC* fpHcStruc +) +{ + UINT8 Index; + BOOLEAN TerminateSearch = FALSE; + UINT32 dDeviceCounter = 0; + + if (bSearchFlag == USB_SRCH_DEV_INDX) { + if (fpDev_Info) { + for (Index=1; Index < MAX_DEVICES; Index++) { + if (&gUsbData->aDevInfoTable[Index] == fpDev_Info) { + return (DEV_INFO*)(UINTN)Index; + } + } + return NULL; // Device address not found in the table + } + if (bDev == USB_HOTPLUG_FDD_ADDRESS) return &gUsbData->FddHotplugDev; + if (bDev == USB_HOTPLUG_HDD_ADDRESS) return &gUsbData->HddHotplugDev; + if (bDev == USB_HOTPLUG_CDROM_ADDRESS) return &gUsbData->CdromHotplugDev; + + if (bDev) return &gUsbData->aDevInfoTable[bDev]; + return NULL; // Invalid input - both bDev and fpDevInfo are zeroes. + } + + for (Index = 1; Index < MAX_DEVICES; Index ++) { + // + // if fpDev_Info is not null then position the search at the correct + // index that matches the fpDev_Info + // + if (fpDev_Info) { + if (&gUsbData->aDevInfoTable[Index] != fpDev_Info) + continue; + else { + fpDev_Info = 0; + continue; + } + } + // + // For USB_SRCH_DEVBASECLASS_NUM devices are counted regardless of their + // DEV_INFO_VALID_STRUC flag + // + if (bSearchFlag == USB_SRCH_DEVBASECLASS_NUM) + { + if(gUsbData->aDevInfoTable[Index].bBaseClass == bDev) { + if (fpHcStruc) { + // + // Check if device belongs to the specified HC + // + if (gUsbData->aDevInfoTable[Index].bHCNumber != fpHcStruc->bHCNumber) + { + continue; + } + } + if (gUsbData->aDevInfoTable[Index].Flag & DEV_INFO_DEV_PRESENT) + { + dDeviceCounter++; + } + } + continue; + } + + if ((gUsbData->aDevInfoTable[Index].Flag & DEV_INFO_VALIDPRESENT) == + DEV_INFO_VALIDPRESENT){ + switch(bSearchFlag) { + case USB_SRCH_HC_STRUC: + if (fpHcStruc == NULL) return NULL; + if (gUsbData->HcTable + [gUsbData->aDevInfoTable[Index].bHCNumber-1] == fpHcStruc) { + TerminateSearch = TRUE; + } + break; + + case USB_SRCH_DEV_TYPE: + if (gUsbData->aDevInfoTable[Index].bDeviceType == bDev) { + TerminateSearch = TRUE; + } + break; + case USB_SRCH_DEV_NUM: + if (gUsbData->aDevInfoTable[Index].bDeviceType == bDev) { + if (fpHcStruc) { + // + // Check if device belongs to the specified HC + // + if (gUsbData->aDevInfoTable[Index].bHCNumber != fpHcStruc->bHCNumber) + { + break; + } + } + dDeviceCounter++; + } + break; // Do not change TerminateSearch so loop continues + case USB_SRCH_DEV_ADDR: + if (gUsbData->aDevInfoTable[Index].bDeviceAddress == bDev) { + if ((fpHcStruc == NULL) || + (gUsbData->HcTable + [gUsbData->aDevInfoTable[Index].bHCNumber-1] == fpHcStruc)) { + TerminateSearch = TRUE; + } + } + break; + + default: + return NULL; + } + } + if (TerminateSearch) return ((DEV_INFO*)&gUsbData->aDevInfoTable[Index]); + } + if ( (bSearchFlag == USB_SRCH_DEV_NUM) || (bSearchFlag == USB_SRCH_DEVBASECLASS_NUM) ) + return (DEV_INFO*)(UINTN)dDeviceCounter; + + return NULL; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// PROCEDURE: UsbAllocDevInfo +// +// Description: Finds a non-used DEV_INFO record in aDevInfoTable and marks it +// reserved. To free the user need to clear DEV_INFO_VALID_STRUC +// bit in bFlag of DEV_INFO +// +// Output: Pointer to new device info. struc. 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +DEV_INFO* UsbAllocDevInfo() +{ + UINT8 bIndex; + DEV_INFO *fpNewDevInfo; + + for (bIndex = 1; bIndex < MAX_DEVICES; bIndex ++){ + fpNewDevInfo = gUsbData->aDevInfoTable +bIndex; + if ((fpNewDevInfo->Flag & + ( DEV_INFO_VALID_STRUC | DEV_INFO_DEV_BUS)) == 0 ){ + // + // Free device info structure. Save it if not. + // + fpNewDevInfo->Flag |= DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT; + return fpNewDevInfo; + } + } + return NULL; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBGetProperDeviceInfoStructure +// +// Description: This routine searches for a device info structure that +// matches the vendor and device id, and LUN of the device +// found. If such a device info structure not found, then it +// will return a free device info structure +// +// Input: Vendor, Device ID, Current LUN +// +// Output: Pointer to new device info. struc. NULL on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBGetProperDeviceInfoStructure( + DEV_INFO* Dev, + UINT8 Lun) +{ + UINT8 bCount; + DEV_INFO *fpDevInfo, *fpFreeDevInfo; + + fpFreeDevInfo = NULL; + +// +// Scan through the device info table for a free entry. Also if the device +// connected is a mass storage device look for a device info structure whose +// device is disconnected and its vendor & device id matches the one of +// current device. If such a structure found that means this device may be +// reconnected - use the same structure +// + for (bCount = 1; bCount < MAX_DEVICES; bCount++) + { + fpDevInfo = (DEV_INFO*) &gUsbData->aDevInfoTable[bCount]; + + if (fpDevInfo->Flag & DEV_INFO_DEV_DUMMY) { + continue; + } + + // Check whether the structure is valid + if (!(fpDevInfo->Flag & DEV_INFO_VALID_STRUC)) { + if (fpFreeDevInfo == NULL) { + fpFreeDevInfo = fpDevInfo; // Store the value of the free device info + } + } else { + // + // Yes, structure is valid. Check for device presence + // + if (fpDevInfo->Flag & DEV_INFO_DEV_PRESENT) { + if ((fpDevInfo->bHubDeviceNumber != Dev->bHubDeviceNumber) || + (fpDevInfo->bHubPortNumber != Dev->bHubPortNumber)) { + continue; + } + } + // + // Device is not present. Match the vendor, device id and LUN with + // current device info + // + if ((fpDevInfo->wVendorId == Dev->wVendorId) && + (fpDevInfo->wDeviceId == Dev->wDeviceId) && + (fpDevInfo->bInterfaceNum == Dev->bInterfaceNum) && + (fpDevInfo->bEndpointSpeed == Dev->bEndpointSpeed) && + (fpDevInfo->bLUN == Lun)) { + return fpDevInfo; // "Abandoned" device entry found + } + } + } + return fpFreeDevInfo; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// PROCEDURE: USB_ConfigureDevice +// +// Description: This routine completes the USB device configuration for +// the devices supported by USB BIOS. This routine +// handles the generic configuration for the devices. +// +// Output: pHCStruc HCStruc pointer +// pDevInfo Device information structure pointer +// pDesc Pointer to the descriptor structure +// wStart Offset within interface descriptor +// supported by the device +// wEnd End offset of the device descriptor +// +// Output: Pointer to new device info. struc. 0 on error +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USB_ConfigureDevice ( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Desc, + UINT16 Start, + UINT16 End +) +{ + DEV_INFO *NewDevInfo; + + NewDevInfo = USBGetProperDeviceInfoStructure(DevInfo, 0); + + if (NewDevInfo == NULL) { + return NULL; + } + // + // Check whether this device is reconnected by checking the valid + // structure flag + // + if (NewDevInfo->Flag & DEV_INFO_VALID_STRUC) { + USB_DEBUG(DEBUG_LEVEL_3, "USB_ConfigureDevice: Existing device.\n"); + // + // This device is reconnected. Reuse the old device address so that + // INT13h can identify this drive properly + // + DevInfo->Flag |= NewDevInfo->Flag; + NewDevInfo->wDataInSync = 0; + NewDevInfo->wDataOutSync = 0; + } + else { + // + // Check whether we reached the limit of devices of this type + // + if (CheckDeviceLimit(DevInfo->bBaseClass) == TRUE) { + return NULL; + } + } + + // + // For registered devices skip updating bFlag + // + if (!(NewDevInfo->Flag & DEV_INFO_MASS_DEV_REGD)) { + // + // Since DeviceInfo[0] already has many fields filled in, the new entry + // should be initialized with a copy of DeviceInfo[0]. But, the new + // DeviceInfo should not be marked as "present" until the device + // is successfully initialized. + // + // Copy old DeviceInfo struc to new DeviceInfo struc and zero device[0] + // + MemCopy ((UINT8*)DevInfo, (UINT8*)NewDevInfo, sizeof (DEV_INFO)); + NewDevInfo->Flag &= DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT | + DEV_INFO_MASS_DEV_REGD | DEV_INFO_DEV_BUS | + DEV_INFO_IN_QUEUE | DEV_INFO_ALT_SETTING_IF; + } else { + // Change the parent HC number and port number in the existing DEV_INFO + NewDevInfo->bHCNumber = DevInfo->bHCNumber; + NewDevInfo->bHubDeviceNumber = DevInfo->bHubDeviceNumber; + NewDevInfo->bHubPortNumber = DevInfo->bHubPortNumber; + NewDevInfo->bEndpointSpeed = DevInfo->bEndpointSpeed; + NewDevInfo->wEndp0MaxPacket = DevInfo->wEndp0MaxPacket; + NewDevInfo->DevMiscInfo = DevInfo->DevMiscInfo; + NewDevInfo->bDeviceAddress = DevInfo->bDeviceAddress; + } + + // + // Do a SetConfiguration command to the device to set it to its + // HID/Boot configuration. + // + NewDevInfo->Flag |= DEV_INFO_VALIDPRESENT; + if (!(DevInfo->Flag & DEV_INFO_MULTI_IF)) { + USB_SetConfig(HcStruc, NewDevInfo, NewDevInfo->bConfigNum); + if (DevInfo->Flag & DEV_INFO_ALT_SETTING_IF) { + UsbSetInterface(HcStruc, NewDevInfo, NewDevInfo->bAltSettingNum); + } + } + + USB_DEBUG(3, "new dev: %x, flag: %x, addr %d\n", + NewDevInfo, NewDevInfo->Flag, NewDevInfo->bDeviceAddress); + + return NewDevInfo; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBCheckNonCompliantDevice +// +// Description: This function checks for non-compliant USB devices by +// by comparing the device's vendor and device id with +// the non-compliant device table list and updates the +// data structures appropriately to support the device. +// +// Input: fpHCStruc - HCStruc pointer +// fpDevInfo - Device information structure pointer +// fpDesc - Pointer to the descriptor structure +// wDescLength - End offset of the device descriptor +// +// Output: Updated fpDevInfo->wIncompatFlags field +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +USBCheckNonCompliantDevice( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpDesc, + UINT16 wLength, + UINT16 wDescLength +) +{ + USB_BADDEV_STRUC *fpBadDevice; + INTRF_DESC *fpIntrfDesc; + + fpIntrfDesc = (INTRF_DESC*)((UINT8*)fpDesc + wLength); + + // + // Search the bad device table to get the structure for this device + // + for (fpBadDevice = gUsbBadDeviceTable; + fpBadDevice->wDID | fpBadDevice->wVID; fpBadDevice++) { + + if ((fpBadDevice->wDID != fpDevInfo->wDeviceId) || + (fpBadDevice->wVID != fpDevInfo->wVendorId)) { + continue; + } +USB_DEBUG(DEBUG_LEVEL_3, "Found non-compatible device: DID=%x, VID=%x\n", fpBadDevice->wDID, fpBadDevice->wVID); + // + // Save the incompatibility flag into device info structure + // + fpDevInfo->wIncompatFlags = fpBadDevice->wFlags; + + // + // Check which fields to update in the interface descriptor + // + // Check for base class field + // + if (fpBadDevice->bBaseClass) { + // + // Update base class field in the interface descriptor + // + fpIntrfDesc->bBaseClass = fpBadDevice->bBaseClass; + } + // + // Check for base sub class field + // + if (fpBadDevice->bSubClass) { + // + // Update sub class field in the interface descriptor + // + fpIntrfDesc->bSubClass = fpBadDevice->bSubClass; + } + // + // Check for protocol field + // + if (fpBadDevice->bProtocol) { + // + // Update protocol field in the interface descriptor + // + fpIntrfDesc->bProtocol = fpBadDevice->bProtocol; + } + break; + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// PROCEDURE: USBIdentifyAndConfigureDevice +// +// Description: This routine invokes the device drivers 'check device type' +// routine and identifies the device type. +// +// Output: pHCStruc HCStruc pointer +// pDevInfo Device information structure pointer +// pDesc Pointer to the descriptor structure +// wStart Offset within interface descriptor +// supported by the device +// wEnd End offset of the device descriptor +// +// Output: Pointer to new device info. struc, NULL on error +// +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBIdentifyAndConfigureDevice ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpDesc, + UINT16 wLength, + UINT16 wDescLength) +{ + UINT8 bBaseClass, bSubClass, bProtocol, + bIndex, bRetValue; + DEV_INFO* fpDevInfoLocal; + DEV_DRIVER* fpDevDriver; + INTRF_DESC* fpIntrfDesc; + + // + // Check for non-compliant device. If non-compliant device found then + // the descriptor values will get updated depending on the need. + // + USBCheckNonCompliantDevice ( + fpHCStruc, + fpDevInfo, + fpDesc, + wLength, + wDescLength); + + USB_DEBUG(DEBUG_LEVEL_3, "USBIdentifyAndConfigureDevice..."); + + // + // Check whether device needs to be disable + // + if (fpDevInfo->wIncompatFlags & USB_INCMPT_DISABLE_DEVICE) { + USB_DEBUG(DEBUG_LEVEL_3, "not compatible device.\n"); + return NULL; + } + + fpIntrfDesc = (INTRF_DESC*)(fpDesc + wLength); + +//(EIP74609+)> + if(OEMSkipList(fpDevInfo->bHubDeviceNumber,fpDevInfo->bHubPortNumber,fpHCStruc->wBusDevFuncNum,fpIntrfDesc->bBaseClass,1)) { + USB_DEBUG(3, "Match the skip table ; skipping this device.\n"); //(EIP98145) + return NULL; + } +//<(EIP74609+) + // + // Get the base, sub class & protocol values + // + bBaseClass = fpIntrfDesc->bBaseClass; + bSubClass = fpIntrfDesc->bSubClass; + bProtocol = fpIntrfDesc->bProtocol; + + // + // Check for matching device driver + // + fpDevInfoLocal = NULL; + bRetValue = USB_ERROR; + + //(EIP96616+)> + for (bIndex = 0; bIndex < MAX_DEVICE_TYPES; bIndex ++) { + fpDevDriver = &gUsbData->aDevDriverTable[bIndex]; + // + // Check structure validity + // + if (!fpDevDriver->bDevType) { + continue; // Driver table not valid + } + // + // Verify presence of Check Device routine + // + if (fpDevDriver->pfnCheckDeviceType) { + // + // Check device type is implemented. Execute it! + // + bRetValue = (*fpDevDriver->pfnCheckDeviceType)( + fpDevInfo,bBaseClass, + bSubClass,bProtocol); + if (bRetValue != USB_ERROR) + break; + } else { + // + // Check device type is not implemented. Compare the class codes + // + if((fpDevDriver->bBaseClass == bBaseClass) || + (fpDevDriver->bSubClass == bSubClass) || + (fpDevDriver->bProtocol == bProtocol)) { + // + // If the class codes match set bRetValue with the bDevType from the Device Driver + // + bRetValue = fpDevDriver->bDevType; + break; + } + } + } + if(bRetValue != USB_ERROR){ + // + // Check whether we reached the limit of devices of this type + // + //if (CheckDeviceLimit(bBaseClass) == TRUE) continue; //(EIP81761-) + + // + // Set the device type in the Device Info structure + // + fpDevInfo->bDeviceType = bRetValue; + + // + // Set Base Class, Subclass and Protocol information + // + fpDevInfo->bBaseClass = bBaseClass; + fpDevInfo->bProtocol = bProtocol; + fpDevInfo->bSubClass = bSubClass; + + // + // Device identified. Issue common configure call + // Call a common routine to handle the remaining initialization that is done + // for all devices. + // + fpDevInfoLocal = USB_ConfigureDevice( + fpHCStruc, + fpDevInfo, + fpDesc, + wLength, + wDescLength); + + if (fpDevInfoLocal == NULL) { + USB_DEBUG(DEBUG_LEVEL_3, "USB: Common configure failed.\n"); + return fpDevInfoLocal; + } + + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + if (!(fpDevInfoLocal->Flag & DEV_INFO_IN_QUEUE)) { + USB_SmiQueuePut(fpDevInfoLocal); + fpDevInfoLocal->Flag |= DEV_INFO_IN_QUEUE; + } + } + + fpDevInfoLocal->fpDeviceDriver = fpDevDriver; + fpDevInfoLocal = (*fpDevDriver->pfnConfigureDevice)( + fpHCStruc, + fpDevInfoLocal, + fpDesc, + wLength, + wDescLength); + if (!fpDevInfoLocal || + !(fpDevInfoLocal->Flag & DEV_INFO_VALID_STRUC) ) + { + fpDevInfoLocal = 0; + USB_DEBUG(DEBUG_LEVEL_3, "USB: Device specific configure failed.\n"); + return fpDevInfoLocal; + } + + //<(EIP96616+) + } + + USB_DEBUG(DEBUG_LEVEL_3, "%x\n", fpDevInfoLocal); + + return fpDevInfoLocal; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USB_InitFrameList +// +// Description: This routine initializes the frame list pointed by fpPtr +// with the dValue provided +// +// Output: fpHCStruc Pointer to the Host Controller structure +// dValue Value to be initialized with +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + + +VOID +USB_InitFrameList( + HC_STRUC* fpHCStruc, + UINT32 dValue) +{ + UINT16 wIndex; + UINT32 *fpPtr = (UINT32*)fpHCStruc->fpFrameList; + + for (wIndex = 0; wIndex < fpHCStruc->wAsyncListSize; wIndex ++) { + fpPtr[wIndex] = dValue; + } + return; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBKeyRepeat +// +// Description: This function handles different key repeat related functions +// depending on the input +// +// Input: fpHCStruc - pointer for the HC that implements the key repeat function +// bAction - sub-function index: +// 0 Install key repeat HCStruc +// 1 Disable key repeat +// 2 Enable key repeat +// 3 Uninstall key repeat HCStruc +// +// Output: None +// +// Note: fpHCStruc is only relevant for sub-function 0. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKeyRepeat( + HC_STRUC* HcStruc, + UINT8 Action +) +{ + +//USB_DEBUG(DEBUG_LEVEL_3, "KR%d\n", bAction); + UINT8 i; + + switch (Action) { + case 0: // Sub-function 0: Save the HCStruc value for later use + if (gKeyRepeatStatus == FALSE) { + gUsbData->fpKeyRepeatHCStruc = HcStruc; + } + break; + case 1: // Sub-function 0: Disable key repeat + if (gKeyRepeatStatus) { +#if USB_HID_KEYREPEAT_USE_SETIDLE == 1 + if (gUsbData->fpKeyRepeatDevInfo != NULL) { + // + // Set the HID SET_IDLE request to 0 + // + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable[gUsbData->fpKeyRepeatDevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer) + (gUsbData->HcTable[gUsbData->fpKeyRepeatDevInfo->bHCNumber - 1], + gUsbData->fpKeyRepeatDevInfo,(UINT16)HID_RQ_SET_IDLE, gUsbData->fpKeyRepeatDevInfo->bInterfaceNum, 0, 0, 0); //(EIP54782) + } +#else + if (gUsbData->fpKeyRepeatHCStruc) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + gUsbData->fpKeyRepeatHCStruc->bHCType)].pfnHCDDisableKeyRepeat)( + gUsbData->fpKeyRepeatHCStruc); + } +#endif + gKeyRepeatStatus = FALSE; + } + break; + case 2: // Sub-function 0: Enable key repeat + if (!gKeyRepeatStatus) { +#if USB_HID_KEYREPEAT_USE_SETIDLE == 1 + if(gUsbData->fpKeyRepeatDevInfo != NULL) { + // + // Set the HID SET_IDLE request to 0x200 (8ms) + // + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable[gUsbData->fpKeyRepeatDevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer) + (gUsbData->HcTable[gUsbData->fpKeyRepeatDevInfo->bHCNumber - 1], + gUsbData->fpKeyRepeatDevInfo,(UINT16)HID_RQ_SET_IDLE, gUsbData->fpKeyRepeatDevInfo->bInterfaceNum, 0x400, 0, 0); //(EIP54782) + } +#else + if (gUsbData->fpKeyRepeatHCStruc) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + gUsbData->fpKeyRepeatHCStruc->bHCType)].pfnHCDEnableKeyRepeat)( + gUsbData->fpKeyRepeatHCStruc); + } +#endif + gKeyRepeatStatus=TRUE; + } + break; + case 3: + if (gUsbData->fpKeyRepeatHCStruc == HcStruc) { + gUsbData->fpKeyRepeatHCStruc = NULL; + for (i = 0; i < gUsbData->HcTableCount; i++) { + if (gUsbData->HcTable[i] == NULL) { + continue; + } + if (gUsbData->HcTable[i] == HcStruc) { + continue; + } + if (gUsbData->HcTable[i]->dHCFlag & HC_STATE_RUNNING) { + gUsbData->fpKeyRepeatHCStruc = gUsbData->HcTable[i]; + if (gKeyRepeatStatus) { + gKeyRepeatStatus = FALSE; + USBKeyRepeat(NULL, 2); + } + break; + } + } + } + break; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: BusFillDriverEntries +// +// Description: Install drivers that redirects ...???? +// +// Input: fpDevDriver - record that the routine can use to install the drive +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_bus_interrupt_handler ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + USBHC_INTERRUPT_DEVNINFO_T *Idi = (USBHC_INTERRUPT_DEVNINFO_T *)DevInfo->pExtra; + EFI_STATUS Status = EFI_SUCCESS; + + ASSERT(Idi); + if (Idi == NULL) { + return USB_SUCCESS; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Idi, sizeof(USBHC_INTERRUPT_DEVNINFO_T)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + + USB_SmiQueuePutMsg(&Idi->QCompleted, Buffer, (int)Idi->DataLength); + return USB_SUCCESS; +} + +VOID +UsbBusDeviceInit( + VOID +) +{ + USB_InstallCallBackFunction(USB_bus_interrupt_handler); + return; +} + +DEV_INFO* +USB_on_configDev( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 *fpDesc, + UINT16 wStart, + UINT16 wEnd +) +{ + fpDevInfo->bDeviceType = (UINT8)BIOS_DEV_TYPE_USBBUS; + fpDevInfo->bCallBackIndex = USB_InstallCallBackFunction(USB_bus_interrupt_handler); + return(fpDevInfo); +} + +UINT8 +USB_on_identifyDev( + DEV_INFO* fpDevInfo, + UINT8 bBaseClass, + UINT8 bSubClass, + UINT8 bProtocol +) +{ + //(EIP96616+)> + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) + return BIOS_DEV_TYPE_USBBUS; + else + return USB_ERROR; + //<(EIP96616+) +} + +UINT8 +USB_on_disconnectDev( + DEV_INFO* fpDevInfo +) +{ + return USB_SUCCESS; +} + +VOID +BusFillDriverEntries( + DEV_DRIVER *fpDevDriver +) +{ + fpDevDriver->bDevType = BIOS_DEV_TYPE_USBBUS; + fpDevDriver->bBaseClass = 0; + fpDevDriver->bSubClass = 0; + fpDevDriver->bProtocol = 0; + fpDevDriver->pfnDeviceInit = UsbBusDeviceInit; + fpDevDriver->pfnCheckDeviceType = USB_on_identifyDev; + fpDevDriver->pfnConfigureDevice = USB_on_configDev; + fpDevDriver->pfnDisconnectDevice = USB_on_disconnectDev; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USB_ReConfigDevice, USB_ReConfigDevice2 +// +// Description: EFI code will call this function to give a chance for +// SMI dev driver to complete the configuration of device +// +// Before call, USB device is connected, address is assigned +// and configuration is set. DEV_INFO structure is initalized +// from information parsed from descriptors and linked +// to USBBUS dev driver. Device driver specific to the type +// of USB device wasn't called on this device +// +// After the call returns, a specific device driver +// initialization was performed by calling pfnCheckDeviceType +// and pfnConfigureDevice functions of device driver. Parameters +// to those functions are taken from descriptors downloaded from +// the device. Device preserve old address and active configuration +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +int USB_ReConfigDevice2( HC_STRUC* fpHCStruc, DEV_INFO* fpDevInfo, + CNFG_DESC *fpCnfgDesc, + INTRF_DESC * fpIntrfDesc ); + +int USB_ReConfigDevice( HC_STRUC* fpHCStruc, DEV_INFO* fpDevInfo ) +{ + INTRF_DESC *fpIntrfDesc=NULL; + + UINT8 iConfig; + int status = USB_SUCCESS; //(EIP90124) + UINT8* fpBuffer; + CNFG_DESC *fpCnfgDesc=NULL; + UINT16 OrgTimeOutValue; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + gCheckUsbApiParameter = FALSE; + + if (fpDevInfo->bDeviceType != 0 && + fpDevInfo->bDeviceType != BIOS_DEV_TYPE_USBBUS) { + return USB_SUCCESS; + } + + fpBuffer = USB_MemAlloc (GET_MEM_BLK_COUNT(MAX_CONTROL_DATA_SIZE)); + if (fpBuffer == NULL) { + return USB_ERROR; + } + // + // Find configuration desc + // + for (iConfig = 0; iConfig < fpDevInfo->DevDesc.NumConfigs;++iConfig){ + + OrgTimeOutValue = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = USB_GET_CONFIG_DESC_TIMEOUT_MS; + + fpCnfgDesc = (CNFG_DESC*)USB_GetDescriptor( + fpHCStruc, + fpDevInfo, + fpBuffer, + (MAX_CONTROL_DATA_SIZE - 1), + DESC_TYPE_CONFIG, + iConfig); + + gUsbData->wTimeOutValue = OrgTimeOutValue; + + if (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_FULL) { + FixedDelay(1000); + } + if(fpCnfgDesc != NULL && fpCnfgDesc->bDescType == DESC_TYPE_CONFIG && + fpDevInfo->bConfigNum == fpCnfgDesc->bConfigValue ){ + break; + } + + fpCnfgDesc = NULL; + } + + if( fpCnfgDesc ){ + UINT16 offset; + UINT16 wDescLength; + INTRF_DESC *pIntrf; + + if(fpCnfgDesc->wTotalLength > MAX_CONTROL_DATA_SIZE - 1) + fpCnfgDesc->wTotalLength = MAX_CONTROL_DATA_SIZE - 1; + wDescLength = fpCnfgDesc->wTotalLength; + for(offset=(UINT16)fpCnfgDesc->bDescLength;offset <wDescLength ;offset = offset + (UINT16)pIntrf->bDescLength){ + pIntrf = (INTRF_DESC*)((UINT8*)fpCnfgDesc + offset); + if(pIntrf->bDescLength == 0) { + break; + } + if (pIntrf->bDescType == DESC_TYPE_INTERFACE && + fpDevInfo->bInterfaceNum == pIntrf->bInterfaceNum && + fpDevInfo->bAltSettingNum == pIntrf->bAltSettingNum ) { + fpIntrfDesc =pIntrf; + break; + } + } + } + + USB_DEBUG(DEBUG_LEVEL_3, + "USB_reConfigDev:: CfgDsc=%x; IntrfDsc=%x\n", + fpCnfgDesc, fpIntrfDesc); + + if (fpIntrfDesc && fpCnfgDesc) { + status = USB_ReConfigDevice2(fpHCStruc, fpDevInfo, + fpCnfgDesc, fpIntrfDesc); + } else { + status = USB_ERROR; + } + + USB_MemFree(fpBuffer, (UINT8)(MAX_CONTROL_DATA_SIZE / sizeof(MEM_BLK))); + + return status; +} + +//---------------------------------------------------------------------------- +// USB_ReConfigDevice2 +//---------------------------------------------------------------------------- +int +USB_ReConfigDevice2( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + CNFG_DESC *fpCnfgDesc, + INTRF_DESC *fpIntrfDesc +) +{ +// int abort=0; + int bIndex; + UINT8 bRetValue = USB_ERROR; + DEV_DRIVER *fpDevDriver = NULL; + DEV_INFO *fpDevInfoLocal; + UINT8 bBaseClass, bSubClass, bProtocol; + EFI_STATUS EfiStatus; + + USB_DEBUG(DEBUG_LEVEL_3, "USB_ReConfigDevice2.\n"); + + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpCnfgDesc, sizeof(CNFG_DESC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpCnfgDesc, fpCnfgDesc->wTotalLength); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpIntrfDesc, sizeof(INTRF_DESC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + // + // Check for non-compliant device. If non-compliant device found then + // the descriptor values will get updated depending on the need. + // + USBCheckNonCompliantDevice ( + fpHCStruc, + fpDevInfo, + (UINT8*)fpCnfgDesc, + fpCnfgDesc->bDescLength, + fpCnfgDesc->wTotalLength); + + // + // Check whether device needs to be disable + // + if (fpDevInfo->wIncompatFlags & USB_INCMPT_DISABLE_DEVICE) + { + return USB_ERROR; + } + + // + // Get the base, sub class & protocol values + // + bBaseClass = fpIntrfDesc->bBaseClass; + bSubClass = fpIntrfDesc->bSubClass; + bProtocol = fpIntrfDesc->bProtocol; + + // + // Check for matching device driver + // + fpDevInfoLocal = NULL; + for (bIndex = 0, bRetValue = USB_ERROR; + bIndex < MAX_DEVICE_TYPES && bRetValue == USB_ERROR; bIndex ++) { + fpDevDriver = &gUsbData->aDelayedDrivers[bIndex]; + if (!fpDevDriver->bDevType) + continue; + if (fpDevDriver->pfnCheckDeviceType){ + bRetValue = (*fpDevDriver->pfnCheckDeviceType)( + fpDevInfo,bBaseClass,bSubClass,bProtocol); + }else if((fpDevDriver->bBaseClass == bBaseClass) && + (fpDevDriver->bSubClass == bSubClass) && + (fpDevDriver->bProtocol == bProtocol)){ + bRetValue = fpDevDriver->bDevType; + } + } + if(bRetValue == USB_ERROR) + return bRetValue; + + //driver was found + + fpDevInfo->bDeviceType = bRetValue; + fpDevInfo->fpDeviceDriver = fpDevDriver; + fpDevInfoLocal = (*fpDevDriver->pfnConfigureDevice)( + fpHCStruc,fpDevInfo,(UINT8*)fpCnfgDesc, + (UINT16)(UINTN)((char*)fpIntrfDesc - (char*)fpCnfgDesc),fpCnfgDesc->wTotalLength); + if (!fpDevInfoLocal) + { + USB_DEBUG(DEBUG_LEVEL_0, "USB_ReConfigDevice2: Device specific configure failed.\n"); + return USB_ERROR; + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: hcnum2hcstruc +// +// Description: Search for the HC_STRUC with specified bHCNumber +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +HC_STRUC* +hcnum2hcstruc( + UINT8 bHCNumber +) +{ + return gUsbData->HcTable[bHCNumber - 1]; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: prepareForLegacyOS +// +// Description: Changes global state of USBSMI module to function properly +// in non-EFI OS - without support from EFI drivers +// +// Before call USB BUS is a driver that handles all devices ( +// except hub) and rest of the drivers are delayed. Number of +// devices are supported by SUBBUS driver and custom EFI driver +// +// After call returns, USBBUS driver is removed and all drivers +// that where +// delayed became active. All USBBUS devices are reconfigured. +// Devices that are not supported by now active drivers are decon- +// figured. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +prepareForLegacyOS() +{ + //(EIP96616)> + DEV_INFO* di; + HC_STRUC* fpHCStruc; + DEV_INFO* e = gUsbData->aDevInfoTable + COUNTOF(gUsbData->aDevInfoTable); + int status; + + gCheckUsbApiParameter = FALSE; + + + // + //First Reconfigure all USBBUS device (while drivers are in delayed array) + // + for( di = &gUsbData->aDevInfoTable[1]; di != e; ++di ){ //(EIP34448) + if((di->Flag & DEV_INFO_VALIDPRESENT) == DEV_INFO_VALIDPRESENT && + di->bDeviceType == BIOS_DEV_TYPE_USBBUS ) + { + fpHCStruc = hcnum2hcstruc(di->bHCNumber); + status = USB_ReConfigDevice(fpHCStruc, di ); + if(status == USB_ERROR){ + // + // Release DEV_INFO + // + di->Flag &= ~DEV_INFO_VALIDPRESENT; + } + } + //di->Flag &= ~DEV_INFO_DEV_BUS; + } + //<(EIP96616) + + + USBKeyRepeat(NULL, 1); // Disable key repeat + //gUsbData->dUSBStateFlag |= USB_FLAG_RUNNING_UNDER_OS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USB_ResetAndReconfigDev +// +// Description: This routine resets and reconfigures the device. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USB_ResetAndReconfigDev( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo +) +{ + DEV_INFO *Dev; + UINT32 Status; + UINT8 DevAddr; + UINT8 *Buffer; + DEV_DESC *DevDesc; + CNFG_DESC *CnfgDesc; + INTRF_DESC *IntrfDesc; + UINT8 ConfigIndx; + UINT8 IntrfIndx; + DEV_DRIVER *DevDriver; + UINT8 i; + UINT8 PortStatus; + UINT8 *DevMiscInfo; + UINT16 TotalLength; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + gCheckUsbApiParameter = FALSE; + + for (i = 1; i < MAX_DEVICES; i++) { + Dev = &gUsbData->aDevInfoTable[i]; + if ((Dev->Flag & (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT | + DEV_INFO_DEV_DUMMY)) != (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT)) { + continue; + } + if ((Dev->bHubDeviceNumber == DevInfo->bHubDeviceNumber) && + (Dev->bHubPortNumber == DevInfo->bHubPortNumber) && + (Dev->bDeviceType != BIOS_DEV_TYPE_USBBUS)) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + HcStruc->bHCType)].pfnHCDDeactivatePolling)(HcStruc, Dev); + } + } + + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDDeinitDeviceData) + (HcStruc, DevInfo); + if (Status != USB_SUCCESS) { + return Status; + } + + Status = USB_ResetHubPort(HcStruc, DevInfo->bHubDeviceNumber, DevInfo->bHubPortNumber); + if (Status != USB_SUCCESS) { + return Status; + } + + Status = USB_EnableHubPort(HcStruc, DevInfo->bHubDeviceNumber, DevInfo->bHubPortNumber); + if (Status != USB_SUCCESS) { + return Status; + } + + PortStatus = USB_GetHubPortStatus(HcStruc, DevInfo->bHubDeviceNumber, DevInfo->bHubPortNumber, TRUE); + + if (PortStatus == USB_ERROR) { + return USB_ERROR; + } + + if (!(PortStatus & USB_PORT_STAT_DEV_ENABLED)) { + return USB_ERROR; + } + + // Initialize HC specific data before device configuration + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDInitDeviceData)( + HcStruc, DevInfo, PortStatus, &DevMiscInfo); + if (Status != USB_SUCCESS) { + return Status; + } + + DevInfo->DevMiscInfo = (VOID*)DevMiscInfo; + + Buffer = USB_MemAlloc(GET_MEM_BLK_COUNT(sizeof(DEV_DESC))); + if (Buffer == NULL) { + return USB_ERROR; + } + + DevAddr = DevInfo->bDeviceAddress; + DevInfo->bDeviceAddress = 0; + + DevDesc = (DEV_DESC*)USB_GetDescriptor(HcStruc, DevInfo, Buffer, sizeof(DEV_DESC), + DESC_TYPE_DEVICE, 0); + if(DevDesc == NULL) { + USB_MemFree(Buffer, GET_MEM_BLK_COUNT(sizeof(DEV_DESC))); + return USB_ERROR; + } + + Status = USB_SetAddress(HcStruc, DevInfo, DevAddr); + if (Status != USB_SUCCESS) { + USB_MemFree(DevDesc, GET_MEM_BLK_COUNT(sizeof(DEV_DESC))); + return Status; + } + + DevInfo->bDeviceAddress = DevAddr; + + Buffer = USB_MemAlloc(GET_MEM_BLK_COUNT(MAX_CONTROL_DATA_SIZE)); + if (Buffer == NULL) { + USB_MemFree(DevDesc, GET_MEM_BLK_COUNT(sizeof(DEV_DESC))); + return USB_ERROR; + } + + for (ConfigIndx = 0; ConfigIndx < DevDesc->NumConfigs; ConfigIndx++) { + CnfgDesc = (CNFG_DESC*)USB_GetDescriptor(HcStruc, DevInfo, Buffer, + 0xFF, DESC_TYPE_CONFIG, ConfigIndx); + if (CnfgDesc == NULL) { + continue; + } + TotalLength = CnfgDesc->wTotalLength; + if (TotalLength > 0xFF) { + if (TotalLength > (MAX_CONTROL_DATA_SIZE - 1)) { + TotalLength = MAX_CONTROL_DATA_SIZE - 1; + } + CnfgDesc = (CNFG_DESC*)USB_GetDescriptor(HcStruc, DevInfo, Buffer, + TotalLength, DESC_TYPE_CONFIG, ConfigIndx); + if (CnfgDesc == NULL) { + continue; + } + } + + if (CnfgDesc->bDescType == DESC_TYPE_CONFIG) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDEnableEndpoints)( + HcStruc, DevInfo, (UINT8*)CnfgDesc); + } + + USB_SetConfig(HcStruc, DevInfo, CnfgDesc->bConfigValue); + + IntrfDesc = (INTRF_DESC*)CnfgDesc; + for (IntrfIndx = 0; IntrfIndx < CnfgDesc->bNumInterfaces; IntrfIndx++) { + do { + IntrfDesc = (INTRF_DESC*)((UINTN)IntrfDesc + IntrfDesc->bDescLength); + if ((UINTN)IntrfDesc > ((UINTN)CnfgDesc + CnfgDesc->wTotalLength) || + (UINTN)IntrfDesc > ((UINTN)CnfgDesc + MAX_CONTROL_DATA_SIZE)) { + break; + } + } while (IntrfDesc->bDescType != DESC_TYPE_INTERFACE); + + if (IntrfDesc->bDescType != DESC_TYPE_INTERFACE) { + break; + } + + for (i = 1; i < MAX_DEVICES; i++) { + Dev = &gUsbData->aDevInfoTable[i]; + if ((Dev->Flag & (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT | + DEV_INFO_DEV_DUMMY)) != (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT)) { + continue; + } + if ((Dev->bHubDeviceNumber == DevInfo->bHubDeviceNumber) && + (Dev->bHubPortNumber == DevInfo->bHubPortNumber) && + (Dev->bConfigNum == CnfgDesc->bConfigValue) && + (Dev->bInterfaceNum == IntrfDesc->bInterfaceNum) && + (Dev->bAltSettingNum == IntrfDesc->bAltSettingNum)) { + break; + } + } + if (i == MAX_DEVICES) { + continue; + } + + Dev->wVendorId = DevDesc->VendorId; + Dev->wDeviceId = DevDesc->DeviceId; + + if (Dev->bDeviceType != BIOS_DEV_TYPE_USBBUS) { + DevDriver = UsbFindDeviceDriverEntry(Dev->fpDeviceDriver); + if (DevDriver != NULL) { + (*DevDriver->pfnConfigureDevice)(HcStruc, Dev, (UINT8*)CnfgDesc, + (UINT16)((UINTN)IntrfDesc - (UINTN)CnfgDesc), CnfgDesc->wTotalLength); + } + } + } + } + + USB_MemFree(DevDesc, GET_MEM_BLK_COUNT(sizeof(DEV_DESC))); + USB_MemFree(Buffer, GET_MEM_BLK_COUNT(MAX_CONTROL_DATA_SIZE)); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USB_DevDriverDisconnect +// +// Description: +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USB_DevDriverDisconnect( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo +) +{ + DEV_DRIVER* DevDriver; + UINT8 Index; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + gCheckUsbApiParameter = FALSE; + + DevDriver = UsbFindDeviceDriverEntry(DevInfo->fpDeviceDriver); + + if (DevDriver && DevDriver->pfnDisconnectDevice) { + DevDriver->pfnDisconnectDevice(DevInfo); + + DevInfo->bDeviceType = 0; + DevInfo->fpDeviceDriver = NULL; + + for (Index = 0; Index < MAX_DEVICE_TYPES; Index++) { + DevDriver = &gUsbData->aDevDriverTable[Index]; + + if (DevDriver->bDevType == BIOS_DEV_TYPE_USBBUS) { + DevInfo->bDeviceType = DevDriver->bDevType; + DevDriver->pfnConfigureDevice(HcStruc, DevInfo, NULL, 0, 0); + break; + } + } + } else { + if (DevInfo->IntInEndpoint) { + // Stop polling the device's interrupt endpoint + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDDeactivatePolling) + (HcStruc, DevInfo); + DevInfo->IntInEndpoint = 0; + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VALID_DEVINFO +// +// Description: Checks if DEV_INFO is a valid connected device info +// Due to hot-plug a DEV_INFO can become invalid in the +// midle of configuration +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +int VALID_DEVINFO(DEV_INFO* pDevInfo) +{ + return (pDevInfo->Flag & DEV_INFO_VALIDPRESENT)!=0; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: USB_AbortConnectHubChildren +// +// Description: Mark DEV_INFO not valid for all the devices connected to a +// given hub. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USB_AbortConnectHubChildren( + UINT8 HubAddr +) +{ + UINT8 i; + DEV_INFO *Dev = &gUsbData->aDevInfoTable[1]; + + for (i=1; i<MAX_DEVICES; i++, Dev++) { + if ((Dev->bHubDeviceNumber == HubAddr) && (Dev->Flag & DEV_INFO_VALIDPRESENT)) { + Dev->Flag &= ~DEV_INFO_DEV_PRESENT; + if (!(Dev->Flag & DEV_INFO_MASS_DEV_REGD)) { + Dev->Flag &= ~DEV_INFO_VALID_STRUC; + } + + USB_DEBUG(DEBUG_LEVEL_3, "USB: abort device [%x] connected to hub[%x]\n", + Dev->bDeviceAddress, HubAddr); + + if (Dev->bDeviceType == BIOS_DEV_TYPE_HUB) { + USB_AbortConnectHubChildren(Dev->bDeviceAddress); + } + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: USB_FreeDeviceAddress +// +// Description: This routine releases the given device's address by +// updating gUsbData->dDeviceAddressMap. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USB_FreeDeviceAddress( + DEV_INFO *DevInfo +) +{ + UINT8 i; + UINT8 Found = 0; + + if (DevInfo->bDeviceAddress) + { + for (i=1; i<MAX_DEVICES; i++) { + if (gUsbData->aDevInfoTable+i != DevInfo && + gUsbData->aDevInfoTable[i].bDeviceAddress == DevInfo->bDeviceAddress) + { + Found++; + } + } + if (Found == 0){ + //The DevInfo was the only function with allocated address - + // return the address to the pool + gUsbData->DeviceAddressMap |= Shl64(1, DevInfo->bDeviceAddress); + } + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USB_AbortConnectDev +// +// Description: Mark DEV_INFO not valid and release its device address +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USB_AbortConnectDev( + DEV_INFO* pDevInfo +) +{ + USB_DEBUG(DEBUG_LEVEL_3, "USB: abort connect [%x].flag = %x\n", + pDevInfo, pDevInfo->Flag); + + pDevInfo->Flag &= ~DEV_INFO_DEV_PRESENT; + + if (!(pDevInfo->Flag & DEV_INFO_MASS_DEV_REGD)) { + pDevInfo->Flag &= ~DEV_INFO_VALID_STRUC; + if (pDevInfo->bDeviceAddress == 0) return; + + USB_FreeDeviceAddress(pDevInfo); + } + + // Remove children (if any) from aborted parent hub device. + // Assume the child device has not been connected since + // the hub has to be connected first. + if (pDevInfo->bDeviceType == BIOS_DEV_TYPE_HUB) { + USB_AbortConnectHubChildren(pDevInfo->bDeviceAddress); + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: USB_SmiQueuePut +// +// Description: Puts the pointer pointer into the queue for processing, +// updates queue head and tail. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USB_SmiQueuePut(VOID * d) +{ + QUEUE_T* q = &gUsbData->QueueCnnctDisc; + + 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; + } + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: QueuePutMsg +// +// Description: Add a variable size item to the queue +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USB_SmiQueuePutMsg( QUEUE_T* q, VOID * d, int sz ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if (q->head + sz > q->maxsize) { + q->head = 0; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)((UINTN)q->data + q->head), sz); + if (EFI_ERROR(Status)) { + return; + } +#endif + MemCopy((UINT8*)d, (UINT8*)((UINTN)q->data + q->head), sz); + q->head += sz; + if(q->head==q->maxsize) q->head = 0; + if(q->head==q->tail){ + //Drop data from queue + q->tail+=sz; + if( q->tail >= q->maxsize ) q->tail = 0; + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CheckDeviceLimit +// +// Description: Verifies whether the number of initialized devices of a given +// class has reached the limit. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +CheckDeviceLimit( + UINT8 BaseClass +) +{ + URP_STRUC Urp; + UINT8 DevNumber; + + Urp.bFuncNumber = USB_API_CHECK_DEVICE_PRESENCE; + Urp.bSubFunc = 1; + Urp.ApiData.ChkDevPrsnc.fpHCStruc = NULL; + Urp.ApiData.ChkDevPrsnc.bDevType = BaseClass; + + USBAPI_CheckDevicePresence(&Urp); + + if (Urp.bRetValue == USB_SUCCESS) + { + DevNumber = Urp.ApiData.ChkDevPrsnc.bNumber; + if ((BaseClass == BASE_CLASS_HID) + && ((USB_DEV_HID_COUNT == 0) || (DevNumber == USB_DEV_HID_COUNT))) + { + USB_DEBUG(3, "Reached the limit of supported HIDs (%d); skipping this device.\n", USB_DEV_HID_COUNT); + return TRUE; + } + + if ((BaseClass == BASE_CLASS_HUB) + && ((USB_DEV_HUB_COUNT == 0) || (DevNumber == USB_DEV_HUB_COUNT))) + { + USB_DEBUG(3, "Reached the limit of supported HUBs (%d); skipping this device.\n", USB_DEV_HUB_COUNT); + return TRUE; + } + + if ((BaseClass == BASE_CLASS_MASS_STORAGE) + && ((USB_DEV_MASS_COUNT == 0) || (DevNumber == USB_DEV_MASS_COUNT))) + { + USB_DEBUG(3, "Reached the limit of supported Mass Storage Devices (%d); skipping this device.\n", USB_DEV_MASS_COUNT); + return TRUE; + } + if ((BaseClass == BASE_CLASS_CCID_STORAGE) + && ((USB_DEV_CCID_COUNT == 0) || (DevNumber == USB_DEV_CCID_COUNT+1))) + { + USB_DEBUG(3, "Reached the limit of supported CCID Devices (%d); skipping this device.\n", USB_DEV_CCID_COUNT); + return TRUE; + } + } + return FALSE; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbControlTransfer +// +// Description: +// +// Input: +// +// Output: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbControlTransfer( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + DEV_REQ DevReq, + UINT16 Timeout, + VOID* Buffer) +{ + UINT16 Status; + UINT16 SavedTimeout; + + SavedTimeout = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = Timeout; + + Status = (*gUsbData->aHCDriverTable[ + GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDControlTransfer)( + HcStruc, + DevInfo, + DevReq.wRequestType, + DevReq.wIndex, + DevReq.wValue, + Buffer, + DevReq.wDataLength); + + gUsbData->wTimeOutValue = SavedTimeout; + + return DevReq.wDataLength && (Status == 0)? USB_ERROR : USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbInterruptTransfer +// +// Description: This function executes an interrupt transaction on the USB. +// +// Input: +// HcStruc Pointer to HCStruc of the host controller. +// DevInfo DeviceInfo structure (if available else 0). +// EndpointAddress The destination USB device endpoint to which the device request +// is being sent. +// MaxPktSize Indicates the maximum packet size the target endpoint is capable +// of sending or receiving. +// Buffer Buffer containing data to be sent to the device or buffer to be +// used to receive data. +// Length Length request parameter, number of bytes of data to be transferred. +// Timeout Indicates the maximum time, in milliseconds, which the transfer +// is allowed to complete. +// +// Output: USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbInterruptTransfer ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + VOID *Buffer, + UINT16 Length, + UINT16 Timeout +) +{ + UINT16 SavedTimeout; + UINT16 BytesTransferred; + + SavedTimeout = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = Timeout; + + BytesTransferred = (*gUsbData->aHCDriverTable[ + GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDInterruptTransfer)( + HcStruc, + DevInfo, + EndpointAddress, + MaxPktSize, + Buffer, + Length); + + gUsbData->wTimeOutValue = SavedTimeout; + + if (BytesTransferred == 0) { + return USB_ERROR; + } else { + return USB_SUCCESS; + } + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: USB_EnableEndpointsDummy +// +// Description: Dummy HC API function used by the HC drivers that do not need +// to implement enable endpoint function. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USB_EnableEndpointsDummy ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Desc +) +{ + return USB_SUCCESS; +} + +UINT8 +USB_InitDeviceDataDummy ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 PortStatus, + UINT8 **DeviceData +) +{ + *DeviceData = NULL; + return USB_SUCCESS; +} + +UINT8 +USB_DeinitDeviceDataDummy ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo +) +{ + return USB_SUCCESS; +} + + //(EIP54018+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: LocatePwrCapOffset +// +// Description: +// This function locate power management capability offset +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +LocatePwrCapOffset ( + IN UINT16 BusDevFunc +) +{ +#if USB_RUNTIME_DRIVER_IN_SMM + UINT16 StatusReg; + UINT8 CapOffset; + EFI_PCI_CAPABILITY_HDR CapHeader; + + // Check if device supports extended capabilities + StatusReg = (UINT16)ReadPCIConfig(BusDevFunc, PCI_STATUS_REGISTER_OFFSET); + if((StatusReg & PCI_STS_CAPABILITY) == 0) { + return 0; + } + // Get offset of first capability structure + CapOffset = (UINT8)ReadPCIConfig(BusDevFunc, EFI_PCI_CAPABILITY_PTR); + // Check capabilities until PMI is found or no more capabilities + while (CapOffset) { + CapHeader.CAP_HDR = (UINT16)ReadPCIConfig(BusDevFunc, CapOffset); + // If PMI block, return offset + if(CapHeader.CapabilityID == PCI_CAP_ID_PMI) { + return CapOffset; + } + // If not, check for next offset + CapOffset = CapHeader.NextItemPtr; + } +#endif + return 0; +} + +#if USB_S5_WAKEUP_SUPPORT +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: ResumePciBridge +// +// Description: +// This function resumed PciBridge +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +ResumePciBridge( + UINT16 BusDevFun +) +{ + UINT32 PmStaCtlReg; + UINT32 PmCapReg; + UINT8 PwrCapPtr; + UINT8 PciCommand; + + PwrCapPtr = LocatePwrCapOffset(BusDevFun); + + if (PwrCapPtr) { + PmCapReg = ReadPCIConfig(BusDevFun, PwrCapPtr); + PmStaCtlReg = ReadPCIConfig(BusDevFun, PwrCapPtr + 0x04); + if (PmCapReg & (BIT31 | BIT30)) { + PmStaCtlReg |= BIT8; + } + if (PmStaCtlReg & (BIT0 | BIT1)) { + PmStaCtlReg &= ~(BIT0 | BIT1); + } + DwordWritePCIConfig(BusDevFun, PwrCapPtr + 0x04, PmStaCtlReg); + } + + PciCommand = (UINT8)ReadPCIConfig(BusDevFun, PCI_COMMAND_REGISTER_OFFSET); + PciCommand |= (PCI_CMD_MEMORY_SPACE + PCI_CMD_BUS_MASTER); + ByteWritePCIConfig(BusDevFun, PCI_COMMAND_REGISTER_OFFSET, PciCommand); + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: StopPciBridge +// +// Description: +// This function stopped PciBridge +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +StopPciBridge( + UINT16 BusDevFun +) +{ + UINT32 PmStaCtlReg; + UINT8 PwrCapPtr; + UINT8 PciCommand; + + PwrCapPtr = LocatePwrCapOffset(BusDevFun); + + if (PwrCapPtr) { + PmStaCtlReg = ReadPCIConfig(BusDevFun, PwrCapPtr + 0x04); + PmStaCtlReg |= (BIT0 + BIT1); + DwordWritePCIConfig(BusDevFun, PwrCapPtr + 0x04, PmStaCtlReg); + } + + PciCommand = (UINT8)ReadPCIConfig(BusDevFun, PCI_COMMAND_REGISTER_OFFSET); + PciCommand &= (~PCI_CMD_BUS_MASTER); + ByteWritePCIConfig(BusDevFun, PCI_COMMAND_REGISTER_OFFSET, PciCommand); + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: EnablePciBridge +// +// Description: +// This function scaned PciBridge +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +ScanPciBridge( + UINT16 *BridgePciAddr +) +{ + HC_STRUC *HcStruc; + UINT8 HcBus[256]; + UINT16 HcBusIndex = 0; + UINT16 MaxHcBus = 0; + UINT16 i; + UINT16 PciAddr; + UINT16 PciBus; + UINT16 PciDev; + UINT16 PciFun; + UINT16 BridgeIndex = 255; + UINT16 DownstreamBus; + + for (i = 0; i < gUsbData->HcTableCount; i++) { + HcStruc = gUsbData->HcTable[i]; + if (HcStruc == NULL) { + continue; + } + + if (!(HcStruc->dHCFlag & HC_STATE_USED)) { + continue; + } + + if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { + HcBus[HcBusIndex] = (UINT8)(HcStruc->wBusDevFuncNum >> 8); + if(MaxHcBus < HcBus[HcBusIndex]) { + MaxHcBus = HcBus[HcBusIndex]; + } + HcBusIndex++; + } + } + + for (PciBus = 0; PciBus < MaxHcBus; PciBus++) { + for (PciDev = 0; PciDev < 0x20 ; PciDev++) { + PciAddr = (UINT16)((PciBus << 8) | (PciDev << 3) | 0); + if (ReadPCIConfig(PciAddr, PCI_VID) != 0xffffffff) { + PciFun = ((UINT8)ReadPCIConfig(PciAddr, PCI_HDR) & 0x80) ? 8 : 1; + do { + PciFun--; + PciAddr = (UINT16)((PciBus << 8) | (PciDev << 3) | PciFun); + if (PciFun != 0) { + if (ReadPCIConfig(PciAddr, PCI_VID) == 0xffffffff) { + continue; + } + } + if (ReadPCIConfig(PciAddr, PCI_SCC) == 0x0604) { + DownstreamBus = (UINT16)ReadPCIConfig(PciAddr, PCI_SBUS); + for (i = 0; i < HcBusIndex; i++) { + if ((HcBus[i] >= (UINT8)(DownstreamBus)) && + (HcBus[i] <= (UINT8)(DownstreamBus >> 8))) { + ResumePciBridge(PciAddr); + BridgePciAddr[BridgeIndex] = PciAddr; + BridgeIndex--; + break; + } + } + } + } while (PciFun); + } + } + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: UsbSuspendHubPort +// +// Description: This function suspends the hub port +// +// Input: DevInfo Device info pointer +// +// Output: Status: EFI_SUCCESS = Success +// EFI_DEVICE_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +UsbSuspendHubPort ( + DEV_INFO *DevInfo +) +{ + UINT32 Index; + DEV_INFO *HubDevInfo; + HC_STRUC *HcStruc; + UINT16 OrgTimeOutValue; + + if (DevInfo->bHubDeviceNumber & BIT7) { + return EFI_SUCCESS; + } + + for (Index = 1; Index < MAX_DEVICES; Index++) { + HubDevInfo = &gUsbData->aDevInfoTable[Index]; + if ((HubDevInfo->Flag & DEV_INFO_VALIDPRESENT) != DEV_INFO_VALIDPRESENT) { + continue; + } + if (DevInfo->bHubDeviceNumber == HubDevInfo->bDeviceAddress) { + HcStruc = gUsbData->HcTable[HubDevInfo->bHCNumber - 1]; + + OrgTimeOutValue = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = USB_SUSPEND_HUB_PORT_TIMEOUT_MS; + + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + HcStruc->bHCType)].pfnHCDControlTransfer)( + HcStruc, + HubDevInfo, + (UINT16)HUB_RQ_SET_PORT_FEATURE, + DevInfo->bHubPortNumber, + (UINT16)PortSuspend, + 0, 0); + + gUsbData->wTimeOutValue = OrgTimeOutValue; + return EFI_SUCCESS; + } + } + return EFI_DEVICE_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UsbSuspendDevices +// +// Description: +// This function suspends usb devices. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UsbSuspendDevices ( + VOID +) +{ + UINT32 Index; + DEV_INFO *DevInfo; + + for (Index = MAX_DEVICES; Index > 0; Index--) { + + DevInfo = &gUsbData->aDevInfoTable[Index]; + + if ((DevInfo->Flag & DEV_INFO_VALIDPRESENT) != DEV_INFO_VALIDPRESENT) { + continue; + } + UsbSuspendHubPort(DevInfo); + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UsbSuspend +// +// Description: +// This function suspend USB +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UsbSuspend( + VOID +) +{ + HC_STRUC *HcStruc; + DEV_INFO *DevInfo; + CNFG_DESC *CnfgDesc; + UINT8 *Buffer; + UINT16 i; + UINT32 PmStaCtlReg; + UINT32 PmCapReg; + UINT16 BridgePciAddr[256]; + UINT32 HcLowBaseAddress; + UINT32 HcHighBaseAddress; + UINT16 HcIoAddress; + UINT16 OrgTimeOutValue; + + for (i = 0; i < 256; i++) { + BridgePciAddr[i] = 0; + } + + ScanPciBridge(BridgePciAddr); + + for (i = 0; i < gUsbData->HcTableCount; i++) { + HcStruc = gUsbData->HcTable[i]; + if (HcStruc == NULL) { + continue; + } + + if (!(HcStruc->dHCFlag & HC_STATE_USED)) { + continue; + } + + HcStruc->PwrCapPtr = LocatePwrCapOffset(HcStruc->wBusDevFuncNum); + if (HcStruc->PwrCapPtr) { + PmCapReg = ReadPCIConfig(HcStruc->wBusDevFuncNum, + HcStruc->PwrCapPtr); + PmStaCtlReg = ReadPCIConfig(HcStruc->wBusDevFuncNum, + HcStruc->PwrCapPtr + 0x04); + if (PmCapReg & (BIT31 | BIT30)) { + PmStaCtlReg |= BIT8; + } + if (PmStaCtlReg & (BIT0 | BIT1)) { + PmStaCtlReg &= ~(BIT0 | BIT1); + } + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, + HcStruc->PwrCapPtr + 0x04, PmStaCtlReg); + } + if (HcStruc->bHCType == USB_HC_UHCI) { + HcIoAddress = (UINT16)ReadPCIConfig(HcStruc->wBusDevFuncNum, USB_IO_BASE_ADDRESS); + if (HcStruc->BaseAddress != HcIoAddress) { + WordWritePCIConfig(HcStruc->wBusDevFuncNum, + USB_IO_BASE_ADDRESS, (UINT32)HcStruc->BaseAddress); + } + ByteWritePCIConfig(HcStruc->wBusDevFuncNum, + PCI_CMD, PCI_CMD_IO_SPACE | PCI_CMD_BUS_MASTER); + } else { + HcLowBaseAddress = ReadPCIConfig(HcStruc->wBusDevFuncNum, PCI_BAR0); + if ((((UINT8)HcLowBaseAddress & (BIT1 |BIT2)) == BIT2) && ((sizeof(VOID*) / sizeof(UINT32)) == 2)) { + HcHighBaseAddress = ReadPCIConfig(HcStruc->wBusDevFuncNum, PCI_BAR1); + if(HcStruc->BaseAddress != ((UINTN)(HcLowBaseAddress & 0xFFFFFFF0)) + + (Shl64((UINTN)HcHighBaseAddress, 32))) { + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, + PCI_BAR0, (UINT32)HcStruc->BaseAddress); + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, + PCI_BAR1, (UINT32)(Shr64(HcStruc->BaseAddress, 32))); + } + } else { + if (HcStruc->BaseAddress != (HcLowBaseAddress & 0xFFFFFFF0)) { + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, + PCI_BAR0, (UINT32)HcStruc->BaseAddress); + } + } + ByteWritePCIConfig(HcStruc->wBusDevFuncNum, + PCI_CMD, PCI_CMD_MEMORY_SPACE | PCI_CMD_BUS_MASTER); + } + } + + // Remove the prsent flag of devices before we reenumerate. + for (i = 1; i < MAX_DEVICES; i++) { + DevInfo = &gUsbData->aDevInfoTable[i]; + DevInfo->Flag &= ~DEV_INFO_DEV_PRESENT; + } + + gUsbData->UsbSetupData.UsbMassDriverSupport = FALSE; + gUsbData->bHandOverInProgress = FALSE; + + //Start XHCI + StartControllerType(USB_HC_XHCI); + //Start EHCI + StartControllerType(USB_HC_EHCI); + //Start UHCI + StartControllerType(USB_HC_UHCI); + //Start OHCI + StartControllerType(USB_HC_OHCI); + + //Wait for the usb devices connect. + FixedDelay(50 * 1000); + + USB_EnumerateRootHubPorts(USB_HC_XHCI); + USB_EnumerateRootHubPorts(USB_HC_EHCI); + USB_EnumerateRootHubPorts(USB_HC_UHCI); + USB_EnumerateRootHubPorts(USB_HC_OHCI); + + Buffer = USB_MemAlloc(sizeof(CNFG_DESC)); + + OrgTimeOutValue = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = 500; + + for (i = 1; i < MAX_DEVICES; i++) { + + DevInfo = &gUsbData->aDevInfoTable[i]; + + if ((DevInfo->Flag & DEV_INFO_VALIDPRESENT) != DEV_INFO_VALIDPRESENT) { + continue; + } + + if (DevInfo->bDeviceType == BIOS_DEV_TYPE_HUB) { + continue; + } + + HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + + CnfgDesc = (CNFG_DESC*)USB_GetDescriptor( + HcStruc, + DevInfo, + Buffer, + sizeof(CNFG_DESC), + DESC_TYPE_CONFIG, + 0); + + if (CnfgDesc == NULL) { + continue; + } + + //Check the device have the capable of remote wakeup + if (CnfgDesc ->bConfigFlags & BIT5) { + //Send device wakeup command to the device + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + HcStruc->bHCType)].pfnHCDControlTransfer)( + HcStruc, + DevInfo, + (UINT16)USB_RQ_SET_FEATURE, + 0, + (UINT16)USB_FSEL_DEV_REMOTE_WAKEUP, + 0, 0); + + } + + } + + gUsbData->wTimeOutValue = OrgTimeOutValue; + + USB_MemFree(Buffer, sizeof(CNFG_DESC)); + + UsbSuspendDevices(); + + for (i = 0; i < gUsbData->HcTableCount; i++) { + HcStruc = gUsbData->HcTable[i]; + if (HcStruc == NULL) { + continue; + } + + //Global suspend host + if (HcStruc->dHCFlag & HC_STATE_RUNNING) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + HcStruc->bHCType)].pfnHCDGlobalSuspend)(HcStruc); + if (HcStruc->PwrCapPtr) { + PmStaCtlReg = ReadPCIConfig(HcStruc->wBusDevFuncNum, + HcStruc->PwrCapPtr + 0x04); + PmStaCtlReg |= (BIT0 + BIT1); + DwordWritePCIConfig(HcStruc->wBusDevFuncNum, + HcStruc->PwrCapPtr + 0x04, PmStaCtlReg); + } + } + } + + for (i = 0; i < 256; i++) { + if (BridgePciAddr[i] != 0) { + StopPciBridge(BridgePciAddr[i]); + } + } + + UsbSbEnablePme(); + +} + +#endif + //<(EIP54018+) +UINT8 +UsbGetDataToggle( + DEV_INFO *DevInfo, + UINT8 EndpointAddr +) +{ + DEV_INFO *DevInfoToToggle; + UINT8 ToggleBit = (EndpointAddr & 0xF) - 1; + UINT16 *DataSync; + EFI_STATUS Status; + + if (DevInfo->fpLUN0DevInfoPtr) { + Status = UsbDevInfoValidation(DevInfo->fpLUN0DevInfoPtr); + if (EFI_ERROR(Status)) { + return 0; + } + DevInfoToToggle = DevInfo->fpLUN0DevInfoPtr; + } else { + DevInfoToToggle = DevInfo; + } + + if (EndpointAddr & BIT7) { + DataSync = &DevInfoToToggle->wDataInSync; + } else { + DataSync = &DevInfoToToggle->wDataOutSync; + } + + return (UINT8)((*DataSync) >> ToggleBit) & 0x1; +} + +VOID +UsbUpdateDataToggle( + DEV_INFO *DevInfo, + UINT8 EndpointAddr, + UINT8 DataToggle +) +{ + DEV_INFO *DevInfoToToggle; + UINT8 ToggleBit = (EndpointAddr & 0xF) - 1; + UINT16 *DataSync; + EFI_STATUS Status; + + if (DevInfo->fpLUN0DevInfoPtr) { + Status = UsbDevInfoValidation(DevInfo->fpLUN0DevInfoPtr); + if (EFI_ERROR(Status)) { + return; + } + DevInfoToToggle = DevInfo->fpLUN0DevInfoPtr; + } else { + DevInfoToToggle = DevInfo; + } + + if (EndpointAddr & BIT7) { + DataSync = &DevInfoToToggle->wDataInSync; + } else { + DataSync = &DevInfoToToggle->wDataOutSync; + } + + *DataSync &= (UINT16)~(1 << ToggleBit); + *DataSync |= (UINT16)(DataToggle << ToggleBit); + return; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** 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 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbdef.h b/Core/EM/usb/rt/usbdef.h new file mode 100644 index 0000000..1367c27 --- /dev/null +++ b/Core/EM/usb/rt/usbdef.h @@ -0,0 +1,2221 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbdef.h 149 10/16/16 10:15p Wilsonlee $ +// +// $Revision: 149 $ +// +// $Date: 10/16/16 10:15p $ +// +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/rt/usbdef.h $ +// +// 149 10/16/16 10:15p 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 +// +// 148 7/07/16 1:13a 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 +// +// 147 3/02/16 9:44p 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 +// +// 146 11/04/15 9:53p Wilsonlee +// TAG] EIP241067 +// [Category] Improvement +// [Description] Add the device descriptor to the DEV_INFO structure. +// [Files] usb.c, usbdef.h, xhci.c, usbbus.c, AmiUsbController.h +// +// 145 9/01/15 10:18p Wilsonlee +// [TAG] EIP235482 +// [Category] Improvement +// [Description] Select this alternate setting for multiple TTs hubs. +// [Files] usbhub.c, usb.c, amiusb.h, usbdef.h +// +// 144 7/24/15 4:43a Wilsonlee +// [TAG] EIP226493 +// [Category] Improvement +// [Description] Block to process periodic list to prevent that we might +// send the wrong command sequences to the same device. +// [Files] usbmass.c, ehci.c, xhci.h, xhci.c, usbdef.h, uhcd.c +// +// 143 5/28/15 4:29a Wilsonlee +// [TAG] EIP219785 +// [Category] Improvement +// [Description] Suspend usb devices which are connected to Hubs. +// [Files] usb.c, usbdef.h +// +// 142 5/26/15 11:39p Wilsonlee +// [TAG] EIP219658 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] It is failed at executing ConfigureEndpoint command for +// DisplayLink devices. +// [RootCause] The value of Average TRB Length should not be 0. +// [Solution] Reasonable initial values of Average TRB Length for +// Control endpoints Control endpoints would be 8B, Interrupt endpoints +// 1KB, and Bulk and Isoch endpoints 3KB. +// [Files] xhci.c, usbdef.h +// +// 141 4/29/15 11:29p Wilsonlee +// [TAG] EIP215031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Transcend USB 3.0 HDD is disappeared in the setup menu by +// cold boot. +// [RootCause] We only can get SerialNumber string descriptor before +// setting configuration for this device, otherwise it is failed at +// getting this descriptor and inquiry command is also failed. +// [Solution] Retry inquiry command. +// [Files] usb.c, usbmass.c, efiusbmass.c, usbbus.c, usbdef.h +// +// 140 4/27/15 2:26a Wilsonlee +// [TAG] EIP211855 +// [Category] Improvement +// [Description] Set the default interface if the device has alternate +// setting for the interface. +// [Files] usb.c, usbdef.h +// +// 139 4/10/15 3:07a 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 +// +// 138 3/26/15 3:25a Wilsonlee +// [TAG] EIP210432 +// [Category] Improvement +// [Description] Change ReportCount to UINT32. +// [Files] usbdef.h +// +// 137 1/22/15 10:21p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 136 12/24/14 9:34p Wilsonlee +// [TAG] EIP194683 +// [Category] Improvement +// [Description] Add the flag "USB_INCMPT_HID_BOOT_PROTOCOL_ONLY" of usb +// bad device table to keep devices use boot protocol. +// [Files] usbkbd.c, usbms.c, usbhid.c, usbdef.h +// +// 135 12/24/14 1:11a Wilsonlee +// [TAG] EIP192517 +// [Category] Improvement +// [Description] USB Driver handles 0x100 NumHeads as a valid value. +// [Files] usbmass.c, usbdef.h, UsbInt13.c, UsbInt13.h, UI13.bin, +// Bfiusb.equ, Bfiusb.asm +// +// 134 12/03/14 9:37p Wilsonlee +// [TAG] EIP193805 +// [Category] Improvement +// [Description] Security Enhancement for SMIHandler in USB module. +// [Files] amiusb.c, uhcd.c, usbrt.mak, usbdef.h, usbsb.c +// +// 133 11/24/14 12:50a Wilsonlee +// [TAG] EIP185972 +// [Category] Improvement +// [Description] To acquire more bandwidth, a dynamically transfer queue +// allocation mechanism is required. +// [Files] ehci.c, usbdef.h +// +// 132 9/29/14 11:38p Wilsonlee +// [TAG] EIP181169 +// [Category] Improvement +// [Description] Support XHCI 1.1/USB 3.1. +// [Files] xhci.c, xhci.h, usb.c, usbbus.c, usbdef.h, UsbHc.h +// +// 131 9/02/14 3:54a Wilsonlee +// [TAG] EIP182567 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] POST B4h sometimes stays about 30 sec if using special +// KB/Ms. +// [RootCause] It's timeout in getting config or report descriptor +// commands. +// [Solution] Set the timeout to 500 ms. +// [Files] usb.c, usbhid.c, usbdef.h +// +// 130 8/20/14 10:04p Wilsonlee +// [TAG] EIP180089 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] After updated to AMI_USB_07, we get EHCI TIMEOUT for +// specific mouse. +// [RootCause] This device may not respond getting string descriptors +// which describing manufacturer, product and the device's serial number. +// [Solution] Set the timeout value to 100 ms, the original is 20 secs. +// [Files] usbbus.c, usbdef.h +// +// 129 8/07/14 2:20a Wilsonlee +// [TAG] EIP176549 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Microstep USB Keyboard issue. +// [RootCause] The report descriptor of Microstep USB Keyboard (Sonix +// Technology Co chip) has an error, Modifier keys is bitmap data, but it +// reports as array data. +// [Solution] We need to force variable flag for Modifier keys input +// item. +// [Files] usbhid.c, usbkbd.c, usbdef.h +// +// 128 7/06/14 10:22p Wilsonlee +// [TAG] EIP176288 +// [Category] Improvement +// [Description] Change the value of MAX_CONTROL_DATA_SIZE to 0x800. +// [Files] usbdef.h +// +// 127 5/06/14 5:18a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 126 4/30/14 6:15a 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 +// +// 125 4/30/14 5:28a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 124 4/07/14 2:08a Wilsonlee +// [TAG] EIP156126 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] The power Format of UEFI can not be identified when we +// install OS from USB CD-ROM. +// [RootCause] The media information is incorrect when we install +// BlockIoProtocol for usb CD / DVD devices. +// [Solution] Get the media status before we install BlockIoProtocol. +// [Files] usbmass.c, usbdef.h, efiusbmass.c +// +// 123 2/26/14 1:57a 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 +// +// 122 12/15/13 10:15p Wilsonlee +// [TAG] EIP136594 +// [Category] New Feature +// [Description] Support 64 bits LBA of usb mass storages. +// [Files] Bfiusb.asm, Bfiusb.equ, UsbInt13.c, UsbInt13.h, amiusb.c, +// usbdef.h, usbmass.c, UsbMass.h, efiusbmass.c, UI13.bin +// +// 121 10/19/13 7:09a Ryanchou +// [TAG] EIP138257 +// [Category] Improvement +// [Description] Correct USB HID device type. +// [Files] amiusb.c, usbdef.h, usbhid.c, efiusbhid.c, uhcd.c +// +// 120 7/26/13 2:42a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 119 7/23/13 2:12a Wilsonlee +// [TAG] EIP127941 +// [Category] Improvement +// [Description] Replace UI13HDDFunc08 with UI13FDDFunc08 if the media +// descriptor is a fixed disk. +// [Files] UsbInt13.h, UsbInt13.c, usbmass.c, usbdef.h, Bfiusb.asm, +// Bfiusb.equ +// +// 118 7/22/13 10:32p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 117 7/04/13 5:50a Roberthsu +// [TAG] EIP127014 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Mouse drifting not smooth +// [RootCause] Bbecause Efi simple point protocol RelativeMovementX +// type is INT32. +// [Solution] Transfer data type to INT32. +// [Files] usbdef.h,usbhid.c,usbms.c,usbkbd.h +// +// 116 6/30/13 11:41p Wilsonlee +// [TAG] EIP121374 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB flash is not recognized after re-plugged on DOS. +// [RootCause] Some devices need to wait for that they are being settle. +// [Solution] Delay for 50 ms allowing port to settle when pluged in +// devices. +// [Files] usbhub.c, usbdef.h +// +// 115 6/02/13 11:44p Wilsonlee +// [TAG] EIP123235 +// [Category] Improvement +// [Description] Stop the usb host controller at ExitBootService if it +// is an extend card or it doesn't support HW SMI. +// [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, +// uhcd.c +// +// 114 4/16/13 6:47a Ryanchou +// [TAG] EIP118912 +// [Category] Improvement +// [Description] Add VIA VT6212 EHCI controller support. +// [Files] ehci.c, uhci.c, usbdef.h, uhcd.c +// +// 113 3/19/13 4:02a 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 +// +// 112 3/18/13 4:51a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 111 1/23/13 5:21a Ryanchou +// [TAG] EIP111280 +// [Category] Improvement +// [Description] Add USB APIs for external driver. +// [Files] amiusb.c, amiusb.h, usbdef.h +// +// 110 1/22/13 3:10a Wilsonlee +// [TAG] EIP112938 +// [Category] Improvement +// [Description] Create a header file for usb mass storage driver. +// [Files] UsbMass.h, usbmass.c, usbdef.h, amiusb.c, efiusbmass.c +// +// 109 1/22/13 2:39a Wilsonlee +// [TAG] EIP110305 +// [Category] Improvement +// [Description] Set the device address after we send the first +// get-device-descriptor command. +// [Files] usbmass.c, usb.c, usbdef.h, usbbus.c, efiusbmass.c, uhcd.c, +// usbport.c +// +// 108 1/11/13 4:22a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 107 12/21/12 5:03a Ryanchou +// [TAG] EIP71730 +// [Category] New Feature +// [Description] Added OHCI handoff support. +// [Files] usb.sdl, usbport.c, amiusb.c, usbdef.h, UsbPolicy.h, usb.sd, +// usb.uni +// +// 106 11/10/12 6:43a 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 +// +// 105 9/04/12 8:04a Wilsonlee +// [TAG] EIP99882 +// [Category] New Feature +// [Description] Add the usb setup item and usbpolicyprotocol to enable +// or disable the usb mass storage driver. +// [Files] UsbPolicy.h, usb.uni, usb.sd, usbmass.c, usbdef.h, +// efiusbmass.c, usbport.c, uhcd.c +// +// 104 8/29/12 8:41a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 103 8/13/12 3:26a Roberthsu +// [TAG] EIP96010 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The KB can not work under bios. +// [RootCause] Usage count overflow. +// [Solution] Add usage count check. +// [Files] usbdef.h,usbhid.c +// +// 102 5/04/12 6:46a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 101 5/04/12 5:28a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 100 5/03/12 6:24a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 99 5/03/12 5:10a Ryanchou +// [TAG] EIP83361 +// [Category] New Feature +// [Description] Added "USB 2.0 Controller Mode" setup item. +// [Files] ehci.c, usb.sd, usb.sdl, usb.uni, usbdef.h, UsbPolicy.h, +// usbport.c +// +// 98 5/02/12 8:08a Wilsonlee +// [TAG] EIP86793 +// [Category] New Feature +// [Description] Add the SDL token "USB_MASS_EMULATION_FOR_NO_MEDIA" for +// determine the USB mass storage device emulation type without media. +// [Files] usbmass.c, usbport.c, uhcd.c, usbdef.h, usbsrc.sdl +// +// 97 5/02/12 2:00a 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~ +// +// 96 4/03/12 5:52a Roberthsu +// [TAG] EIP80948 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] When insert the touch board, it will block the function +// of rear USB ports. +// [RootCause] Report item not enough. +// [Solution] Create buffer use report length. +// [Files] usbhid.c,usbdef.h +// +// 95 1/14/12 6:41a Wilsonlee +// [TAG] EIP80382 +// [Category] New Feature +// [Description] Add the SDL token "USB_MASS_EMULATION_BY_SIZE" for +// determine the USB mass storage device emulation type by size only. +// [Files] usbmass.c, usbport.c, uhcd.c, usbdef.h, usbsrc.sdl +// +// 94 11/09/11 3:35a Ryanchou +// [TAG] EIP73692 +// [Category] Improvement +// [Description] Implement the ownership change mechanism for PCH. +// [Files] ehci.c, usbdef.h, usbsrc.sdl +// +// 93 11/08/11 8:24a Wilsonlee +// [TAG] EIP74876 +// [Category] New Feature +// [Description] Add USB API for shutdown single USB controller. +// [Files] amiusb.c, amiusb.h, usb.c, usbdef.h, uhcd.c, uhcd.h, +// AmiUsbController.h +// +// 92 11/08/11 2:00a Ryanchou +// [TAG] EIP63188 +// [Category] Improvement +// [Description] External USB controller support. +// [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, +// usbdef.h, usbmisc.c, usbsb.c, xhci.c +// +// 91 11/05/11 7:37a Wilsonlee +// [TAG] EIP64781 +// [Category] New Feature +// [Description] Added SDL token +// SKIP_CARD_READER_CONNECT_BEEP_IF_NO_MEDIA that skip the connect beep if +// no media present in USB card reader. +// [Files] usbport.c, usbmass.c, usb.c, usbdef.h, uhcd.c, usbsrc.sdl +// +// 90 10/25/11 3:52a Ryanchou +// [TAG] EIP70933 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System hangs at checkpoint 0x98 when webcam plugged +// [RootCause] The webcam return invalid data in configuration +// descriptor. +// [Solution] Get the configuration descriptor twice, the first time is +// to receive the returned configure descriptor to get the total length +// and the second time is to feed the length to the function again. +// [Files] usb.c, usbdef.h +// +// 89 9/27/11 12:08a Roberthsu +// [TAG] EIP65344 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Razer mouse will hang in post +// [RootCause] Razer has report keyboard interface.But not report led +// usage. +// [Solution] Check if not report led usage page.Do not send led +// command. +// [Files] syskbc.c,usbhid.c,usbdef.h +// +// 88 9/19/11 9:28a Lavanyap +// [TAG] EIP66198 +// [Category] Improvement +// [Description] Added Mouse Wheel support in PS2 and USB drivers. +// [Files] usbdef.h, usbms.c, efiusbms.c, ps2mouse.h, mouse.c +// +// 87 8/08/11 7:02a Ryanchou +// [TAG] EIP54018 +// [Category] New Feature +// [Description] Added USB S5 wake up support. +// [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, +// usbsb.c xhci.c +// +// 86 8/08/11 5:25a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 85 7/19/11 5:22a Ryanchou +// [TAG] EIP64498 +// [Category] New Feature +// [Description] Implement EHCI key repeat function. +// [Files] ehci.c, ehci.h, usb.c, usbdef.h +// +// 84 7/15/11 6:30a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, efiusbpoint.c, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, +// usb.c, usbdef.h, usbhid.c, usbkbd.c, usbkbd.h, usbms.c, usbpoint.c, +// usbrt.cif, usbsb.c, usbsetup.c, usbsrc.sdl, xhci.c +// +// 83 7/13/11 2:50a Ryanchou +// [TAG] EIP60460 +// [Category] Improvement +// [Description] Adds a flag when device disconnected during data +// transfer, BIOS will not issue a transfer to the devicce if this flag is +// set. This change is for Fresco USB 3.0 controller. +// [Files] usb.c, usbdef.h, xhci.c, xhci.h +// +// 82 7/12/11 8:16a 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 +// +// 81 6/22/11 1:46a Ryanchou +// [TAG] EIP59738 +// [Category] Improvement +// [Description] Support Block size other than 512 bytes USB HDD in UEFI +// mode. +// [Files] efiusbmass.c, uhci.c, usb.c, usbdef.h, usbmass.c +// +// 80 5/03/11 10:13a Ryanchou +// [TAG] EIP54283 +// [Category] Improvement +// [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery +// endpoint halt. +// [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c +// +// 79 4/06/11 1:34a Ryanchou +// [TAG] EIP54782 +// [Category] Improvement +// [Description] Change polling data size of HID devices to max packet +// size of interrupt endpoint. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c +// +// 78 4/06/11 12:50a Ryanchou +// [TAG] EIP51653 +// [Category] New Feature +// [Description] Added an interface that skips specific port +// enumeration. +// [Files] AmiUsbController.h, uhcd.c, uhcd.h, usb.c, usbdef.h, +// usbport.c +// +// 77 3/29/11 10:55p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 76 3/29/11 10:19a Ryanchou +// [TAG] EIP53518 +// [Category] Improvement +// [Description] Added chipset xHCI chip support. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, +// usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c +// +// 75 11/11/10 11:38p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 74 10/22/10 8:59a Ryanchou +// EIP46693: Clear xHCI BIOS owned semaphore bit and SMI enable bit in +// PreInitXhci. +// +// 73 10/20/10 10:26a Ryanchou +// EIP44702: Added USB 3.0 hub support. +// +// 72 10/12/10 2:11a Rameshr +// [TAG]- EIP 44585 +// [Category]-IMPROVEMENT +// [Description]- Number of maximum supported USB Mass Storage device +// increased from 8 to 16. +// [Files]- Uin13.bin, UsbPort.c, UsbInt13.h, Usb.c, Usbdef.h, Uasbmass.c, +// Usb.sd, usb.uni, UsbSetup.c, UsbSrc.sdl, UsbPolicy.h +// +// 71 9/16/10 12:49p Olegi +// Added USB_FLAG_EFIMS_DIRECT_ACCESS flag definition. +// +// 70 9/07/10 4:42a Tonylo +// Remove user tags for coding standard. +// +// 69 7/15/10 4:43a Tonylo +// EIP15489 - Add USB HandOff function for shurdown/init USB legacy +// through USB API function. +// +// 68 7/13/10 7:13a Ryanchou +// EIP38356: Implement shutdown USB legacy support in ACPI enable call. +// +// 67 6/22/10 9:10p Olegi +// EIP39708: Added new incompatibility type for HIDs that ignore boot +// protocol. +// +// 66 6/17/10 10:34a Olegi +// EIP39326: Runtime data moved to runtime memory region. +// +// 65 5/30/10 10:24p Tonylo +// Name tags clean up for coding standard. +// +// 64 5/11/10 9:33a Olegi +// Corrected the mouse data report. EIP37798 +// +// 63 4/19/10 1:52p Olegi +// +// 62 3/11/10 9:49a Olegi +// +// 61 3/11/10 9:21a Olegi +// +// 60 2/27/10 12:00p Olegi +// +// 59 2/26/10 4:08p Olegi +// +// 58 2/08/10 10:05a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 57 1/19/10 12:00p Olegi +// +// 56 12/23/09 11:59a Olegi +// +// 55 11/24/09 11:36a Olegi +// EIP#29733 - BIOS adds an USB API (Block KBC Access) +// +// 54 11/13/09 9:14a Olegi +// +// 53 11/04/09 12:46p Olegi +// +// 52 11/04/09 11:10a Olegi +// Increased KBC character buffer. (EIP29345) +// +// 51 10/30/09 5:48p Olegi +// +// 50 10/09/09 5:57p Olegi +// +// 49 10/02/09 10:50a Olegi +// Code cleanup. +// +// 48 9/15/09 12:21p Olegi +// Added KEY_REPEAT_LOGIC functionality. EIP#25841 +// +// 47 8/26/09 11:44a Olegi +// Changes that prevent collision of keyboard activity and mass storage +// access. EIP#22808 +// +// 46 5/22/09 1:49p Olegi +// Added the definition of USB_INCMPT_BUILT_IN_HUB. +// +// 45 5/21/09 5:17p Olegi +// Added HDD hotplug support definitions. +// +// 44 2/20/09 2:32p Olegi +// Added USB_SAFE_DISABLE_INTERRUPT, EIP#19525 +// +// 43 2/18/09 3:45p Olegi +// Added a feature that allows to skip mass storage device installation +// depending on physical media presence. EIP#19260. +// +// 42 2/17/09 8:44a Olegi +// Modified the value of DESC_TYPE_CLASS_HUB. +// +// 38 9/05/08 4:11p Olegi +// fpCallbackNotifyX were removed from global data area. +// +// 33 5/16/08 12:03p Olegi +// Compliance with AMI coding standard. +// +// 32 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 30 9/26/07 9:27a Olegi +// Added USB_FORCE_64BIT_ALIGNMENT flag. +// +// 28 9/06/07 6:08p Olegi +// USB_FLAG_DRIVER_CONSISTENT flag added. +// +// 27 7/09/07 2:12p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 19 10/12/06 9:09p Andriyn +// Fix: unexpected plug-off lead to endless timeout +// +// 17 4/14/06 6:42p Olegi +// Conversion to be able to use x64 compiler. +// +// 16 3/20/06 3:38p Olegi +// Version 8.5 - x64 compatible. +// +// 14 3/06/06 6:28p Olegi +// Lun devices support modifications: supported using the index in +// DEV_INFO table, not through dedicated massLun table. +// +// 13 3/01/06 3:54p Olegi +// Added definition of USB_FLAG_RUNNING_UNDER_OS flag. +// +// 7 8/04/05 5:59p Andriyn +// Legacy over LegacyFree +// +// 6 6/03/05 6:31p Andriyn +// Device path added to HC_STRUC for the need of Aptio framework +// +// 5 5/20/05 12:10p Andriyn +// HC driver to support both protocols +// +// 4 5/20/05 11:05a Andriyn +// reconcile Aptio changes with Alaska +// +// 3 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 2 5/10/05 4:13p Andriyn +// USBBUS implementation +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//********************************************************************** + +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: UsbDef.h +// +// Description: AMI USB driver definitions +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// AVOID including multiple instance of this file +#ifndef __USB_H +#define __USB_H + +typedef struct _EFI_PCI_IO_PROTOCOL EFI_PCI_IO_PROTOCOL; + +#include "efi.h" + +#include "Protocol\UsbHC.h" +#include <Protocol/AmiUsbController.h> +#include "token.h" + +#include "uhci.h" +#include "ohci.h" +#include "ehci.h" +#include "xhci.h" + +#include <Protocol\DevicePath.h> +#include <Protocol\UsbPolicy.h> +#include <AmiDxeLib.h> +#include "AmiusbrtCCID.h" + +// +// USB Module version number +// +#define USB_MAJOR_VER USB_DRIVER_MAJOR_VER +#define USB_MINOR_VER USB_DRIVER_MINOR_VER +#define USB_BUG_RELEASE_VER USB_DRIVER_BUILD_VER +#define USB_ACTIVE 0xFC +#define USB_LEGACY_ENABLE 0x01 +#define USB_6064_ENABLE 0x02 + +#define MAX_DEVICE_TYPES 0x07 // 7 different types of devices +#define MAX_HC_TYPES 0x04 // 4 different types of host controllers +#define MAX_MASS_DEVICES 0x06 +#define MAX_CCID_DEVICES 0x06 + +#define BIOS_DEV_TYPE_HID 0x01 +//#define BIOS_DEV_TYPE_KEYBOARD 0x01 +//#define BIOS_DEV_TYPE_MOUSE 0x02 +#define BIOS_DEV_TYPE_HUB 0x03 +#define BIOS_DEV_TYPE_STORAGE 0x04 +#define BIOS_DEV_TYPE_SECURITY 0x05 +#define BIOS_DEV_TYPE_USBBUS 0x06 // Generic USB device driver +#define BIOS_DEV_TYPE_USBBUS_SHADOW 0x07 // Dummy device type for temp usage +#define BIOS_DEV_TYPE_CCID 0x08 // CCID device type + +#define HID_DEV_TYPE_KEYBOARD BIT0 +#define HID_DEV_TYPE_MOUSE BIT1 +#define HID_DEV_TYPE_POINT BIT2 + +#define MAX_DEVICES (USB_DEV_HID_COUNT+USB_DEV_MASS_COUNT+USB_DEV_HUB_COUNT+USB_DEV_CCID_COUNT+USB_DEV_UNSUPPORTED) + + +// USB HC type +#define USB_HC_UHCI 0x10 +#define USB_HC_OHCI 0x20 +#define USB_HC_EHCI 0x30 +#define USB_HC_XHCI 0x40 +#define GET_HCD_INDEX(bHCType) (((bHCType) - USB_HC_UHCI) >> 4) +#define USB_INDEX_UHCI (GET_HCD_INDEX(USB_HC_UHCI)) +#define USB_INDEX_OHCI (GET_HCD_INDEX(USB_HC_OHCI)) +#define USB_INDEX_EHCI (GET_HCD_INDEX(USB_HC_EHCI)) +#define USB_INDEX_XHCI (GET_HCD_INDEX(USB_HC_XHCI)) + +#define USB_MEM_BLK_SIZE 32 // 32 bytes +#define USB_MEM_BLK_SIZE_SHIFT 5 // log2 (USB_MEM_BLK_SIZE) + +#define USB_FORCE_64BIT_ALIGNMENT 1 + +#if USB_FORCE_64BIT_ALIGNMENT +#define USB_MEM_ALLOCATION_UNIT_SIZE 64 +#else +#define USB_MEM_ALLOCATION_UNIT_SIZE 32 +#endif + +// The following macro returns number of memory blocks needed for the structure provided +#define GET_MEM_BLK_COUNT_STRUC(Struc) ((sizeof(Struc)+(sizeof(MEM_BLK)-1))/sizeof(MEM_BLK)) + +// The following macro returns number of memory blocks needed for the size of data provided +#define GET_MEM_BLK_COUNT(Size) (((Size) + (sizeof(MEM_BLK)-1))/sizeof(MEM_BLK)) + +#define MAX_SPLIT_PERIODIC_NUMBER 0x07 +//#define TEMP_BUFFER_SIZE 0x80 // Size of temp buffer +//#define CONTROL_DATA_SIZE 0x100 +#define MAX_CONTROL_DATA_SIZE 0x800 +#define MAX_TEMP_BUFFER_SIZE 0x80 // Size of temp buffer +#define MAX_CONSUME_BUFFER_SIZE 0x1000 //(EIP59738+) +// USB state flag equates +#define USB_FLAG_ENABLE_BEEP_MESSAGE 0x0001 // BIT 0 +#define USB_FLAG_RUNNING_UNDER_EFI 0x0002 // BIT 1 +#define USB_FLAG_DISABLE_LEGACY_SUPPORT 0x0004 // BIT 2 +#define USB_FLAG_6064EMULATION_ON 0x0008 // BIT 3 +#define USB_FLAG_RUNNING_UNDER_OS 0x0010 // BIT 4 +#define USB_FLAG_DRIVER_CONSISTENT 0x0020 // BIT 5 //AMI Tracker 27603 +#define USB_FLAG_DRIVER_STARTED 0x0080 // BIT 7 +#define USB_FLAG_6064EMULATION_IRQ_SUPPORT 0x0100 // BIT 8 +#define USB_HOTPLUG_FDD_ENABLED 0x0200 // BIT 9 +#define USB_HOTPLUG_HDD_ENABLED 0x0400 // BIT 10 +#define USB_HOTPLUG_CDROM_ENABLED 0x0800 // BIT 11 +#define USB_FLAG_MASS_NATIVE_EMULATION 0x1000 // BIT 12 +#define USB_FLAG_MASS_MEDIA_CHECK 0x2000 // BIT 13 +#define USB_FLAG_MASS_SKIP_FDD_MEDIA_CHECK 0x4000 // BIT 14 +#define USB_FLAG_EFIMS_DIRECT_ACCESS 0x8000 // BIT15 +#define USB_FLAG_SKIP_CARD_READER_CONNECT_BEEP 0x10000 //BIT16 //(EIP64781+) +#define USB_FLAG_MASS_SIZE_EMULATION 0x20000 //BIT17 //(EIP80382+) +#define USB_FLAG_MASS_EMULATION_FOR_NO_MEDIA 0x40000 //BIT18 //(EIP86793+) + +// PCI related equates + // Invalid PCI register address bits +#define PCI_REG_MAX_ADDRESS 0xFF00 +#define PCI_REG_ADDRESS_BYTE PCI_REG_MAX_ADDRESS + 0x000 +#define PCI_REG_ADDRESS_WORD PCI_REG_MAX_ADDRESS + 0x001 +#define PCI_REG_ADDRESS_DWORD PCI_REG_MAX_ADDRESS + 0x003 + +// For systems with config mechanism 1 +#define CFG_SPACE_INDEX_REG 0xCF8 +#define CFG_SPACE_DATA_REG 0xCFC + +// Standard PCI configuration register offsets and relevant values +//------------------------------------------------------------------------------ +#define PCI_REG_VENDID 0x00 //PCI vendor ID register +#define PCI_REG_DEVID 0x02 //PCI device ID register +#define PCI_REG_COMMAND 0x04 //PCI command register + +//---------------------------------------------------------------------------- +// USB API equates +//---------------------------------------------------------------------------- +#define USB_NEW_API_START_FUNC 0x20 + +#define USB_API_CHECK_PRESENCE 0x00 +#define USB_API_START 0x20 +#define USB_API_STOP 0x21 +#define USB_API_DISABLE_INTERRUPTS 0x22 +#define USB_API_ENABLE_INTERRUPTS 0x23 +#define USB_API_MOVE_DATA_AREA 0x24 +#define USB_API_GET_DEVICE_INFO 0x25 +#define USB_API_CHECK_DEVICE_PRESENCE 0x26 +#define USB_API_MASS_DEVICE_REQUEST 0x27 +#define USB_API_POWER_MANAGEMENT 0x28 +#define USB_API_PREPARE_FOR_OS 0x29 +#define USB_API_SECURITY_INTERFACE 0x2A +#define USB_API_LIGHTEN_KEYBOARD_LEDS 0x2B +#define USB_API_CHANGE_OWNER 0x2C +#define USB_API_HC_PROC 0x2D +#define USB_API_CORE_PROC 0x2E +#define USB_API_KBC_ACCESS_CONTROL 0x30 //(EIP29733+) +#define USB_API_LEGACY_CONTROL 0x31 // +#define USB_API_GET_DEV_ADDR 0x32 +#define USB_API_EXT_DRIVER_REQUEST 0x33 +#define USB_API_CCID_DEVICE_REQUEST 0x34 +#define USB_API_USB_STOP_CONTROLLER 0x35 //(EIP74876+) +#define USB_API_HC_START_STOP 0x36 + +#define USB_MASSAPI_GET_DEVICE_INFO 0x000 +#define USB_MASSAPI_GET_DEVICE_GEOMETRY 0x001 +#define USB_MASSAPI_RESET_DEVICE 0x002 +#define USB_MASSAPI_READ_DEVICE 0x003 +#define USB_MASSAPI_WRITE_DEVICE 0x004 +#define USB_MASSAPI_VERIFY_DEVICE 0x005 +#define USB_MASSAPI_FORMAT_DEVICE 0x006 +#define USB_MASSAPI_CMD_PASS_THRU 0x007 +#define USB_MASSAPI_ASSIGN_DRIVE_NUMBER 0x008 +#define USB_MASSAPI_CHECK_DEVICE 0x009 +#define USB_MASSAPI_GET_MEDIA_STATUS 0x00A +#define USB_MASSAPI_GET_DEV_PARMS 0x00B + +#define USB_MASS_MEDIA_PRESENT BIT0 +#define USB_MASS_MEDIA_CHANGED BIT1 +#define USB_MASS_GET_MEDIA_FORMAT BIT2 //(EIP13457+) +#define USB_MASS_MEDIA_REMOVEABLE BIT3 + +#define USB_SECURITY_API_READ_DEVICE 0x000 +#define USB_SECURITY_API_WRITE_DEVICE 0x001 + +#define USB_PM_SUSPEND 0x010 +#define USB_PM_RESUME 0x020 + +// Error returned from API handler +#define USB_SUCCESS 0x000 +#define USB_PARAMETER_ERROR 0x010 +#define USB_NOT_SUPPORTED 0x020 +#define USBAPI_INVALID_FUNCTION 0x0F0 +#define USB_ERROR 0x0FF + +// +// Bit definitions for a generic pointer +// +#define TERMINATE 0x00000001 +#define QUEUE_HEAD 0x00000002 +#define VERTICAL_FLAG 0x00000004 +#define LINK_POINTER 0xFFFFFFF0 +// Mass storage data sync equates +#define USB_BULK_IN_DATA_SYNC BIT0 +#define USB_BULK_IN_DATA_SYNC_SHIFT 0 +#define USB_BULK_OUT_DATA_SYNC BIT1 +#define USB_BULK_OUT_DATA_SYNC_SHIFT 1 +#define USB_INT_DATA_SYNC BIT2 +#define USB_INT_DATA_SYNC_SHIFT 2 + +// Highest possible device address +#define MAX_DEVICE_ADDR MAX_DEVICES +// Addr that is guaranted not to be used +#define DUMMY_DEVICE_ADDR (MAX_DEVICE_ADDR + 1) + +#define DEFAULT_PACKET_LENGTH 8 // Max size of packet data + +// USB BIOS related error codes +#define USB_ERROR_CODE_START 0x8100 +#define ERRUSB_HC_NOT_FOUND (USB_ERROR_CODE_START + 1) +#define ERRUSB_DEVICE_INIT (USB_ERROR_CODE_START + 2) +#define ERRUSB_DEVICE_DISABLED (USB_ERROR_CODE_START + 3) +#define ERRUSB_OHCI_EMUL_NOT_SUPPORTED (USB_ERROR_CODE_START + 4) +#define ERRUSB_EHCI_64BIT_DATA_STRUC (USB_ERROR_CODE_START + 5) + +// USB internal error codes +#define USB_ERR_DEV_INIT_MEM_ALLOC 0x01 +#define USB_ERR_DEV_INIT_GET_DESC_8 0x02 +#define USB_ERR_DEV_INIT_SET_ADDR 0x03 +#define USB_ERR_DEV_INIT_GET_DESC_100 0x04 +#define USB_ERR_DEV_INIT_GET_DESC_200 0x05 +#define USB_ERR_NO_DRIVER 0x20 +#define USB_ERR_NO_HCSTRUC 0x21 +#define USB_ERR_STARTHC_NO_MEMORY 0x22 +#define USB_ERR_KBCONNECT_FAILED 0x23 +#define USB_ERR_HC_RESET_FAILED 0x24 +#define USB_ERR_PORT_RESET_FAILED 0x25 +#define USB_ERR_CONTROL_XFER_TIMEOUT 0x80 +//---------------------------------------------------------------------------- +// Descriptor Type Values +//--------------------------------------------------------------------------- +#define DESC_TYPE_DEVICE 1 // Device Descriptor (Type 1) +#define DESC_TYPE_CONFIG 2 // Configuration Descriptor (Type 2) +#define DESC_TYPE_STRING 3 // String Descriptor (Type 3) +#define DESC_TYPE_INTERFACE 4 // Interface Descriptor (Type 4) +#define DESC_TYPE_ENDPOINT 5 // Endpoint Descriptor (Type 5) + //(EIP38434+)> +#define DESC_TYPE_REPORT 0x22 // Report Descriptor (Type 22h) +#define DESC_TYPE_HID 0x21 // HID Descriptor (Type 21h) + //<(EIP38434+) +#define DESC_TYPE_HUB 0x29 // Hub Descriptor (Type 29h) +#define DESC_TYPE_SS_HUB 0x2A + +#define DESC_TYPE_SS_EP_COMP 48 //SuperSpeed Endpoint Companion Decsriptor + +#define DESC_TYPE_CLASS_HUB 0x2900 // Hub Class Descriptor (Type 0) + + +//---------------------------------------------------------------------------- +// Usb device requests timeout +//--------------------------------------------------------------------------- + +#ifndef USB_GET_CONFIG_DESC_TIMEOUT_MS +#define USB_GET_CONFIG_DESC_TIMEOUT_MS 500 +#endif + +#ifndef USB_GET_STRING_DESC_TIMEOUT_MS +#define USB_GET_STRING_DESC_TIMEOUT_MS 100 +#endif + +#ifndef USB_GET_SERIAL_NUMBER_DESC_TIMEOUT_MS +#define USB_GET_SERIAL_NUMBER_DESC_TIMEOUT_MS 3000 +#endif + +#ifndef USB_GET_REPORT_DESC_TIMEOUT_MS +#define USB_GET_REPORT_DESC_TIMEOUT_MS 500 +#endif + +#ifndef USB_SUSPEND_HUB_PORT_TIMEOUT_MS +#define USB_SUSPEND_HUB_PORT_TIMEOUT_MS 200 +#endif + +//---------------------------------------------------------------------------- +// USB protocol related routines +//---------------------------------------------------------------------------- + +#define MAX_USB_ERROR_RETRY 01 + +// USB Version structure +typedef struct { + UINT8 bMajor; + UINT8 bMinor; + UINT8 bBugRel; +} USB_VERSION; + +typedef struct { + UINT8 aBuf[32]; +} MEM_BLK; + +#define MEM_BLK_COUNT (MEM_PAGE_COUNT * (4096 / USB_MEM_BLK_SIZE)) +#define MEM_BLK_STS_COUNT (MEM_BLK_COUNT / 32) + + +typedef struct { + UINT16 wPCIDev; + UINT16 wHCType; +} HC_PCI_INFO; + +#pragma pack(push, 1) + +typedef struct { + UINT8 bDescLength; + UINT8 bDescType; + UINT16 wTotalLength; + UINT8 bNumInterfaces; + UINT8 bConfigValue; + UINT8 bConfigString; + UINT8 bConfigFlags; + UINT8 bConfigPower; +} CNFG_DESC; + +typedef struct { + UINT8 bDescLength; + UINT8 bDescType; + UINT8 bInterfaceNum; + UINT8 bAltSettingNum; + UINT8 bNumEndpoints; + UINT8 bBaseClass; + UINT8 bSubClass; + UINT8 bProtocol; + UINT8 bInterfaceString; +}INTRF_DESC; + +typedef struct { + UINT8 DescLength; + UINT8 DescType; + UINT8 MaxBurst; + UINT8 Attributes; + UINT16 BytesPerInterval; +} SS_ENDP_COMP_DESC; + +typedef struct { + UINT8 bDescLength; + UINT8 bDescType; + UINT8 bEndpointAddr; + UINT8 bEndpointFlags; + UINT16 wMaxPacketSize; + UINT8 bPollInterval; +} ENDP_DESC; + + //(EIP38434+)> +typedef struct { + UINT8 bDescLength; + UINT8 bDescType; + UINT16 bcdHID; + UINT8 bCountryCode; + UINT8 bNumEndpoints; + UINT8 bDescriptorType; + UINT16 bDescriptorLength; +} HID_DESC; + +#pragma pack(pop) + +//---------------------------------------------------------------------------- +// Report descriptor struct define +//---------------------------------------------------------------------------- +#define HID_REPORT_FIELD_FLAG_CONSTANT BIT0 //0:DATA 1:CONSTANT +#define HID_REPORT_FIELD_FLAG_VARIABLE BIT1 //0:ARRAY 1:VARIABLE +#define HID_REPORT_FIELD_FLAG_RELATIVE BIT2 //0:ABSOLUTE 1:RELATIVE +#define HID_REPORT_FIELD_FLAG_INPUT BIT4 //0:OUTPUT 1:INPUT + +#define HID_BTYPE_KEYBOARD 0x1 +#define HID_BTYPE_MOUSE 0x2 +#define HID_BTYPE_POINT 0X3 + +#define HID_REPORT_FLAG_REPORT_PROTOCOL BIT0 //If use report protocol +#define HID_REPORT_FLAG_REPORT_ID BIT1 //1:REPORT_ID EXIST +#define HID_REPORT_FLAG_TOUCH_BUTTON_FLAG BIT2 +#define HID_REPORT_FLAG_LED_FLAG BIT3 //1:LED //EIP65344 +#define HID_REPORT_FLAG_RELATIVE_DATA BIT4 +#define HID_REPORT_FLAG_ABSOLUTE_DATA BIT5 + +//---------------------------------------------------------------------------- +// Report descriptor's hid_item +//---------------------------------------------------------------------------- +typedef struct { + UINT8 bSize; + UINT8 bType; + UINT8 bTag; + union { + UINT8 u8; + UINT16 u16; + UINT32 u32; + } data; +} HID_ITEM; + + +//---------------------------------------------------------------------------- +// HID Report define start +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// HID report item format +//---------------------------------------------------------------------------- +#define HID_ITEM_FORMAT_SHORT 0 +#define HID_ITEM_FORMAT_LONG 1 + +//---------------------------------------------------------------------------- +// HID report descriptor item type (prefix bit 2,3) +//---------------------------------------------------------------------------- +#define HID_ITEM_TYPE_MAIN 0 +#define HID_ITEM_TYPE_GLOBAL 1 +#define HID_ITEM_TYPE_LOCAL 2 +#define HID_ITEM_TYPE_RESERVED 3 + +//---------------------------------------------------------------------------- +// HID report descriptor main item tags +//---------------------------------------------------------------------------- +#define HID_MAIN_ITEM_TAG_INPUT 8 +#define HID_MAIN_ITEM_TAG_OUTPUT 9 +#define HID_MAIN_ITEM_TAG_FEATURE 0xb +#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 0xa +#define HID_MAIN_ITEM_TAG_END_COLLECTION 0xc + +//---------------------------------------------------------------------------- +// HID report descriptor main item contents +//---------------------------------------------------------------------------- +#define HID_MAIN_ITEM_CONSTANT 0x001 +#define HID_MAIN_ITEM_VARIABLE 0x002 +#define HID_MAIN_ITEM_RELATIVE 0x004 +#define HID_MAIN_ITEM_WRAP 0x008 +#define HID_MAIN_ITEM_NONLINEAR 0x010 +#define HID_MAIN_ITEM_NO_PREFERRED 0x020 +#define HID_MAIN_ITEM_NULL_STATE 0x040 +#define HID_MAIN_ITEM_VOLATILE 0x080 +#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 + +//---------------------------------------------------------------------------- +// HID report descriptor collection item types +//---------------------------------------------------------------------------- +#define HID_COLLECTION_PHYSICAL 0 +#define HID_COLLECTION_APPLICATION 1 +#define HID_COLLECTION_LOGICAL 2 + +//---------------------------------------------------------------------------- +// HID report descriptor global item tags +//---------------------------------------------------------------------------- +#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 +#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 +#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 +#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 +#define HID_GLOBAL_ITEM_TAG_UNIT 6 +#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 +#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 +#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 +#define HID_GLOBAL_ITEM_TAG_PUSH 0x0a +#define HID_GLOBAL_ITEM_TAG_POP 0x0b + +//---------------------------------------------------------------------------- +// HID report descriptor local item tags +//---------------------------------------------------------------------------- +#define HID_LOCAL_ITEM_TAG_USAGE 0 +#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 +#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 +#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 +#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 +#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 +#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 +#define HID_LOCAL_ITEM_TAG_DELIMITER 0x0a + + +//---------------------------------------------------------------------------- +// HID usage pages +//---------------------------------------------------------------------------- +#define HID_UP_GENDESK 0x01 +#define HID_UP_KEYBOARD 0x07 +#define HID_UP_BUTTON 0x08 + +#define HID_UP_KEYBOARD_LEFT_CTRL 0xE0 +#define HID_UP_KEYBOARD_LEFT_SHIFT 0xE1 +#define HID_UP_KEYBOARD_LEFT_ALT 0xE2 +#define HID_UP_KEYBOARD_LEFT _GUI 0xE3 +#define HID_UP_KEYBOARD_RIGHT_CTRL 0xE4 +#define HID_UP_KEYBOARD_RIGHT_SHIFT 0xE5 +#define HID_UP_KEYBOARD_RIGHT_ALT 0xE6 +#define HID_UP_KEYBOARD_RIGHT_GUI 0xE7 + +//---------------------------------------------------------------------------- +// HID Report define end +//---------------------------------------------------------------------------- + //<(EIP38434+) +//---------------------------------------------------------------------------- +// Bit definitions for EndpointDescriptor.EndpointAddr +//---------------------------------------------------------------------------- +#define EP_DESC_ADDR_EP_NUM 0x0F //Bit 3-0: Endpoint number +#define EP_DESC_ADDR_DIR_BIT 0x80 //Bit 7: Direction of endpoint, 1/0 = In/Out +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Bit definitions for EndpointDescriptor.EndpointFlags +//---------------------------------------------------------------------------- +#define EP_DESC_FLAG_TYPE_BITS 0x03 //Bit 1-0: Indicate type of transfer on endpoint +#define EP_DESC_FLAG_TYPE_CONT 0x00 //Bit 1-0: 00 = Endpoint does control transfers +#define EP_DESC_FLAG_TYPE_ISOC 0x01 //Bit 1-0: 01 = Endpoint does isochronous transfers +#define EP_DESC_FLAG_TYPE_BULK 0x02 //Bit 1-0: 10 = Endpoint does bulk transfers +#define EP_DESC_FLAG_TYPE_INT 0x03 //Bit 1-0: 11 = Endpoint does interrupt transfers +//---------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Values for InterfaceDescriptor.BaseClass +//--------------------------------------------------------------------------- +#define BASE_CLASS_HID 0x03 +#define BASE_CLASS_MASS_STORAGE 0x08 +#define BASE_CLASS_HUB 0x09 +//---------------------------------------------------------------------------- + + +//--------------------------------------------------------------------------- +// Values for InterfaceDescriptor.SubClass +//--------------------------------------------------------------------------- +#define SUB_CLASS_BOOT_DEVICE 0x01 // Boot device sub-class +#define SUB_CLASS_HUB 0x00 //Hub Device Sub Class? + +// Mass storage related sub-class equates +#define SUB_CLASS_RBC 0x01 // RBC T10 project,1240-D, e.g. Flash +#define SUB_CLASS_SFF8020I 0x02 // SFF8020I, e.g. ATAPI CD-ROM +#define SUB_CLASS_QIC157 0x03 // QIC-157, e.g. ATAPI Tape device +#define SUB_CLASS_UFI 0x04 // UFI, e.g. Floppy +#define SUB_CLASS_SFF8070I 0x05 // SFF8070I, e.g. ATAPI Floppy +#define SUB_CLASS_SCSI 0x06 // SCSI transparent command set + +// Vendor specific mass storage related sub-class equates +#define SUB_CLASS_PL2307 0x80 // Prolific 2307 ,USB to IDE +#define SUB_CLASS_SL11R 0x81 // ScanLogic SL11R-IDE +#define SUB_CLASS_THUMB_DRV 0x82 // ThumbDrive +#define SUB_CLASS_DFUSB01 0x83 // DataFab ATA Bridge +#define SUB_CLASS_DOK 0x84 // Disk On Key +#define SUB_CLASS_VENDOR_SPECIFIC 0xFF // Vendor Specific +//--------------------------------------------------------------------------- + + +//--------------------------------------------------------------------------- +// Values for InterfaceDescriptor.Protocol +//--------------------------------------------------------------------------- +#define PROTOCOL_KEYBOARD 0x01 // Keyboard device protocol +#define PROTOCOL_MOUSE 0x02 // Mouse device protocol? + +#define PROTOCOL_HUB_SINGLE_TT 0x00 // Hub single TT protocol +#define PROTOCOL_HUB_MULTIPLE_TTS 0x02 // Hub multiple TTs protocol + +// Mass storage related protocol equates +#define PROTOCOL_CBI 0x00 // Mass Storage Control/Bulk/Interrupt + // with command completion interrupt +#define PROTOCOL_CBI_NO_INT 0x01 // MASS STORAGE Control/Bulk/Interrupt + // with NO command completion interrupt +#define PROTOCOL_BOT 0x50 // Mass Storage Bulk-Only Transport +#define PROTOCOL_VENDOR 0xFF // Vendor specific mass protocol +//--------------------------------------------------------------------------- + +#pragma pack(push, 1) + +typedef struct { + UINT16 wRequestType; + UINT16 wValue; + UINT16 wIndex; + UINT16 wDataLength; +} DEV_REQ; + +#pragma pack(pop) + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: HCD_HEADER +// +// Description: USB Host Controller Driver function list structure. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// bFlag UINT8 Driver Header Status +// pfnHCDStart UINT8 Driver Start +// pfnHCDStop UINT8 Driver Stop +// pfnHCDEnumeratePorts UINT8 Enumerate Root Ports +// pfnHCDDisableInterrupts UINT8 Disable Interrupts +// pfnHCDEnableInterrupts UINT8 Enable Interrupts +// pfnHCDProcessInterrupt UINT8 Process Interrupt +// pfnHCDGetRootHubStatus UINT8 Get Root Hub Ports Status +// pfnHCDDisableRootHub UINT8 Disable Root Hub +// pfnHCDEnableRootHub UINT8 Enable Root Hub +// pfnHCDControlTransfer UINT16 Perform Control Transfer +// pfnHCDBulkTransfer UINT32 Perform Bulk Transfer +// pfnHCDInterruptTransfer UINT8 Perform Interrupt Transfer +// pfnHCDDeactivatePolling UINT8 Deactivate Polling +// pfnHCDActivatePolling UINT8 Activate Polling +// pfnHCDDisableKeyRepeat UINT8 Disable Key Repead +// pfnHCDEnableKeyRepeat UINT8 Enable Key Repeat +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> +//!!!! +//!!!! If you change this structure, please, check UN_HCD_HEADER also. +//!!!! +typedef struct { + UINT8 bFlag; + UINT8 (*pfnHCDStart) (HC_STRUC*); + UINT8 (*pfnHCDStop) (HC_STRUC*); + UINT8 (*pfnHCDEnumeratePorts) (HC_STRUC*); + UINT8 (*pfnHCDDisableInterrupts) (HC_STRUC*); + UINT8 (*pfnHCDEnableInterrupts) (HC_STRUC*); + UINT8 (*pfnHCDProcessInterrupt) (HC_STRUC*); + UINT8 (*pfnHCDGetRootHubStatus) (HC_STRUC*,UINT8, BOOLEAN); + UINT8 (*pfnHCDDisableRootHub) (HC_STRUC*,UINT8); + UINT8 (*pfnHCDEnableRootHub) (HC_STRUC*,UINT8); + UINT16 (*pfnHCDControlTransfer) (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); + UINT32 (*pfnHCDBulkTransfer) (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); + UINT16 (*pfnHCDInterruptTransfer) (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); + UINT8 (*pfnHCDDeactivatePolling) (HC_STRUC*,DEV_INFO*); + UINT8 (*pfnHCDActivatePolling) (HC_STRUC*,DEV_INFO*); + UINT8 (*pfnHCDDisableKeyRepeat) (HC_STRUC*); + UINT8 (*pfnHCDEnableKeyRepeat) (HC_STRUC*); + UINT8 (*pfnHCDEnableEndpoints) (HC_STRUC*,DEV_INFO*,UINT8*); + UINT8 (*pfnHCDInitDeviceData) (HC_STRUC*,DEV_INFO*,UINT8,UINT8**); + UINT8 (*pfnHCDDeinitDeviceData) (HC_STRUC*,DEV_INFO*); + UINT8 (*pfnHCDResetRootHub) (HC_STRUC*,UINT8); + UINT8 (*pfnHCDClearEndpointState) (HC_STRUC*,DEV_INFO*,UINT8); //(EIP54283+) + UINT8 (*pfnHCDGlobalSuspend) (HC_STRUC*); //(EIP54018+) +} HCD_HEADER; + +typedef union { + HCD_HEADER hcd_header; + struct { + UINT8 bFlag; + VOID* proc[(sizeof(HCD_HEADER)-1)/sizeof(VOID*)]; + } asArray; +} UN_HCD_HEADER; + +// Equates related to host controller state +#define HC_STATE_RUNNING BIT0 +#define HC_STATE_SUSPEND BIT1 +#define HC_STATE_USED BIT2 +#define HC_STATE_INITIALIZED BIT3 +#define HC_STATE_EXTERNAL BIT4 +#define HC_STATE_OWNERSHIP_CHANGE_IN_PROGRESS BIT5 +#define HC_STATE_CONTROLLER_WITH_RMH BIT6 + +#pragma pack(push, 1) + +typedef struct { + UINT8 bDescLength; + UINT8 bDescType; + UINT8 bNumPorts; // Number of downstream ports on hub + UINT16 wHubFlags; // See HUB_FLAG_xxx bit definitions below + UINT8 bPowerOnDelay; // Time to delay after turning on power to port (in 2ms units) + UINT8 bHubControlAmps; // Milliamps of current needed by hub controller + UINT8 bHubHdrDecLat; + UINT16 wHubDelay; + UINT16 DeviceRemovable; // Variable size array of bits (one for each port) +} HUB_DESC; + +#pragma pack(pop) + +#define DEV_INFO_VALID_STRUC BIT0 // Structure validity +#define DEV_INFO_DEV_PRESENT BIT1 // Device presence status +#define DEV_INFO_MASS_DEV_REGD BIT2 // Mass device registered(have + // drive number assigned) +#define DEV_INFO_MULTI_IF BIT3 // Indicates that the device + // is a part of multiple + // interface device +#define DEV_INFO_HOTPLUG BIT4 // Indicates that this device + // is a hotplugged device +#define DEV_INFO_DEV_DUMMY BIT5 +#define DEV_INFO_DEV_BUS BIT6 // Device info is locked by the bus +#define DEV_INFO_DEV_DISCONNECTING BIT7 //(EIP60460+) +#define DEV_INFO_IN_QUEUE BIT8 +#define DEV_INFO_ALT_SETTING_IF BIT9 // Indicates that the device + // has alternate setting for the + // interface + + +#define DEV_INFO_VALIDPRESENT (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT) +// Call back routine type definition +typedef UINT8 (*CALLBACK_FUNC) (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); + +#define MAX_CALLBACK_FUNCTION 50 + +#define MAX_USB_ERRORS_NUM 0x30 // 48 errors max + + + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: MASS_HOTPLUG +// +// Description: This is a Mass URP (Mass USB Request Packet) structure for +// the BIOS API call USBMass_HotPlugDeviceSupport +// (API #27h, SubFunc 09h) +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// bDevAddr BYTE USB device address of the device +// bNumUSBFDD BYTE Number of USB FDD's installed +// bNumUSBCDROM BYTE Number of USB CDROM's installed +// bDeviceFlag BYTE Flag indicating what hot plug devices to be added +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct _MASS_HOTPLUG { + UINT8 bDevAddr; // USB Device Address + UINT8 bNumUSBFDD; // Number of USB FDD's installed + UINT8 bNumUSBCDROM; // Number of USB CDROM's installed + UINT8 bDeviceFlag; // Flag indicating what hot plug devices to be added +} MASS_HOTPLUG; + +#define USB_HOTPLUG_ENABLE_FDD BIT0 +#define USB_HOTPLUG_ENABLE_CDROM BIT1 +#define USB_HOTPLUG_HDD_ADDRESS 0x7D +#define USB_HOTPLUG_FDD_ADDRESS 0x7E +#define USB_HOTPLUG_CDROM_ADDRESS 0x7F + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: MASS_XACT_STRUC +// +// Description: This structure holds the information needed for the mass +// transaction (for CBI or BULK) +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// pCmdBuffer UINT16 Pointer to the mass transaction command buffer +// bCmdSize UINT8 Size of the command buffer +// bXferDir UINT8 Transfer direction (BIT7) +// fpBuffer UINT32 Far pointer of the data buffer (IN/OUT) +// dwLength UINT32 Length of the data buffer +// wPreSkip UINT16 Number of bytes to skip before getting actual data +// wPostSkip UINT16 Number of bytes to skip after getting actual data +// wMiscFlag UINT16 Flag for special cases refer USBM_XACT_FLAG_XXX +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + UINT8 *fpCmdBuffer; + UINT8 bCmdSize; + UINT8 bXferDir; + UINT8 *fpBuffer; + UINT32 dLength; + UINT16 wPreSkip; + UINT16 wPostSkip; + UINT16 wMiscFlag; +} MASS_XACT_STRUC; + +#define USBM_XACT_FLAG_32BIT_DATA_BUFFER BIT0 + +typedef struct _QUEUE_T{ + VOID* volatile* data; + int maxsize; + volatile int head; + volatile int tail; +} QUEUE_T; + //(EIP38434+)> +typedef struct _ABS_MOUSE{ + UINT8 ReportID; + UINT8 ButtonStauts; + UINT16 Xcoordinate; + UINT16 Ycoordinate; + UINT16 Pressure; + UINT16 Max_X; + UINT16 Max_Y; +} ABS_MOUSE; + //<(EIP38434+) +typedef struct MOUSE_DATA{ + UINT8 ButtonStatus; + INT32 MouseX; + INT32 MouseY; + INT32 MouseZ; +} MOUSE_DATA; + + +#define MAX_NOTIFICATIONS_COUNT 100 + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: USB_GLOBAL_DATA +// +// Description: USB Global Data Area structure +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + USB_VERSION stUSBVersion; + UINT32 dUSBStateFlag; + UINT16 aErrorLogBuffer[MAX_USB_ERRORS_NUM]; + UINT8 bErrorLogIndex; + HCD_HEADER aHCDriverTable[MAX_HC_TYPES]; // For 4 type of HC + DEV_DRIVER aDevDriverTable[MAX_DEVICE_TYPES]; // For 5 types of devices + DEV_DRIVER aDelayedDrivers[MAX_DEVICE_TYPES]; // For 5 types of devices + DEV_INFO aDevInfoTable[MAX_DEVICES]; + HC_STRUC **HcTable; + UINT8 HcTableCount; + UINT8 NumOfHc; + DEV_INFO FddHotplugDev; + DEV_INFO HddHotplugDev; + DEV_INFO CdromHotplugDev; + UINT8 bCallBackFunctionIndex; + CALLBACK_FUNC aCallBackFunctionTable[MAX_CALLBACK_FUNCTION]; + UINT64 DeviceAddressMap; + UINT8 bEnumFlag; + UINT32 MemPages; + UINT8 *fpMemBlockStart; + UINT32 MemBlkStsBytes; + UINT32 *aMemBlkSts; +//Hub related fields + UINT32 dHubPortStatus; + //UINT16 wHubPortStatus; +//KBD related fields +// Buffer to store keyboard shift key status bytes. This is correlated with +// scan code buffer to generate proper scan code sequence + UINT8 aKBCShiftKeyStatusBufferStart[16]; + UINT8 aKBCDeviceIDBufferStart[16]; // Buffer to store keyboard device ID +// Buffer to store keyboard shift key status bytes. This is correlated with +// scan code buffer to generate proper scan code sequence + UINT8 aKBCScanCodeBufferStart[16]; + + UINT8 aKBCUsbDataBufferStart[32]; + UINT8 *aKBCUsbDataBufferHead; // Keyboard character buffer head and tail pointers + UINT8 *aKBCUsbDataBufferTail; + UINT8 aKBCCharacterBufferStart[128]; //(EIP29345) + UINT8 bCurrentUSBKeyCode; + UINT8 bUSBKBShiftKeyStatus; + UINT8 bNonUSBKBShiftKeyStatus; + UINT8 bUSBKBC_ExtStatusFlag; + UINT8 bUSBDeviceList; + UINT8 bSet2ScanCode; // Temporary storage for the scan code set 2 scan code + UINT8 bLastUSBKeyCode; // Last USB key code processed + UINT8 bBreakCodeDeviceID; // Device IDs for the keyboards generating break code + UINT8 bCurrentDeviceID; // Current USB keyboard device ID + UINT16 wUSBKBC_StatusFlag; + UINT16 wRepeatCounter; // Typematic repeat counter + UINT16 wRepeatRate; // Typematic repeat rate + UINT8 *fpKBCCharacterBufferHead; // Keyboard character buffer head and tail pointers + UINT8 *fpKBCCharacterBufferTail; + UINT8 *fpKBCScanCodeBufferPtr; // Keyboard scan code buffer pointer + UINT8 bUSBKBC_MassStorage; + UINT8 bKbdDataReady; + UINT8 aKBInputBuffer[16]; // Keyboard expanded input buffer pointer (null-terminated) + UINT8 bCCB; + VOID *EfiKeyboardBuffer; + UINT8 RepeatKey; + HC_STRUC *fpKeyRepeatHCStruc; + DEV_INFO *fpKeyRepeatDevInfo; + DEV_INFO *aUSBKBDeviceTable[USB_DEV_HID_COUNT]; +// Added by mouse driver + MOUSE_DATA MouseData; + UINT8 aMouseInputBuffer[15]; + ABS_MOUSE AbsMouseData[10]; //(EIP38434+) +// Mouse input buffer head and tail pointers + UINT8 *fpMouseInputBufferHeadPtr; + UINT8 *fpMouseInputBufferTailPtr; + UINT8 bMouseStatusFlag; + // Bit 7 : Mouse enabled bit (1/0) + // Bit 6 : Mouse data ready (1/0) + // BIT 5 : Mouse data from USB (1/0) + // BIT 4 : 4-byte mouse data (1/0) + // Bit 3-0 : Reserved + UINT8 *fpUSBTempBuffer; + UINT8 *fpUSBMassConsumeBuffer; + UINT32 wInterruptStatus; + URP_STRUC *fpURP; // Request Packet pointer +// BOTCommandTag used to maintain BOT command block number + UINT32 dBOTCommandTag; + //UINT16 wMassTempData; + UINT8 bUSBStorageDeviceDelayCount; + UINT16 wBulkDataXferDelay; +// Flag that allows mass storage device to handle special conditions. The +// bit pattern is defined by the USBMASS_MISC_FLAG_XXX equates in USB.EQU + UINT16 wMassStorageMiscFlag; + UINT8 bGeometryCommandStatus; + UINT8 bModeSenseSectors; + UINT8 bModeSenseHeads; + UINT16 wModeSenseCylinders; + UINT16 wModeSenseBlockSize; + UINT32 dModeSenseMaxLBA; + UINT8 bReadCapSectors; + UINT8 bReadCapHeads; + UINT16 wReadCapCylinders; + UINT16 wReadCapBlockSize; + UINT32 dReadCapMaxLBA; + UINT8 bDiskMediaType; + UINT16 wTimeOutValue; + UINT8 bLastCommandStatus; + UINT32 dLastCommandStatusExtended; +// Added by EHCI driver + //UINT8 aControlSetupData[8]; +// EHCI_QH *fpQHAsyncXfer; + UINT8 bIgnoreConnectStsChng; + UINT8 ProcessingPeriodicList; + UINT8 bHandOverInProgress; + HC_STRUC *RootHubHcStruc; + +// Tokens representation for the module binary + UINT8 kbc_support; + UINT8 fdd_hotplug_support; + UINT8 hdd_hotplug_support; + UINT8 cdrom_hotplug_support; + UINT8 UsbMassResetDelay; // 0/1/2/3 for 10/20/30/40 seconds + UINT8 PowerGoodDeviceDelay; // 0/1/5/6/../10 seconds + UINT8 UsbXhciSupport; // 0/1 for Disabled/Enabled + UINT8 UsbXhciHandoff; // 0/1 for Disabled/Enabled + UINT8 UsbEhciHandoff; // 0/1 for Disabled/Enabled + UINT8 UsbOhciHandoff; // 0/1 for Disabled/Enabled + UINT8 UsbEmul6064; // 0/1 for Disabled/Enabled + UINT8 NumberOfFDDs; + UINT8 NumberOfHDDs; + UINT8 NumberOfCDROMs; + UINT8 USBMassEmulationOptionTable[16]; + QUEUE_T QueueCnnctDisc; + QUEUE_T ICCQueueCnnctDisc; //QueueCnnctDisc will work of USB devices. Smart Card reader will work in that queue. But Smart Card(ICC) isn't a USB device. So create a new queue to handle it. + DEV_INFO *QueueData1[MAX_NOTIFICATIONS_COUNT]; + UINT8 *gUsbSkipListTable; //(EIP51653+) + UINT8 UsbHiSpeedSupport; + USB_TIMING_POLICY UsbTimingPolicy; + USB_SUPPORT_SETUP UsbSetupData; //(EIP99882+) +} USB_GLOBAL_DATA; + +// Note: If additional space is needed in USB data segment, +// MAX_BULK_DATA_SIZE can be changed to 200h without significant +// decrease in mass storage data transfer performance +// .. moved to SDL +//#define MAX_BULK_DATA_SIZE 0x0400 // Maximum amount of data to transfer + +#define USB_HC_CLASS_CODE 0x0C03 + +#define MAX_NUM_HC_MODULES 0x03 + +// Equates to disable/enable USB port interrupt generation and +// 060/064h trapping +#define USB_DISABLE_INTERRUPT 0x000 +#define USB_SAFE_DISABLE_INTERRUPT 0x001 +#define USB_ENABLE_INTERRUPT 0x00F + +#define TRAP_REQUEST_CLEAR 0x000 +#define TRAP_REQUEST_DISABLE 0x0FF + +//--------------------------------------------------------------------------- +// Equates for Generic USB specific registers in the PCI config space +//--------------------------------------------------------------------------- +#define USB_REG_COMMAND 0x004 +#define USB_MEM_BASE_ADDRESS 0x010 // Offset 10-13h +#define USB_IO_BASE_ADDRESS 0x020 +#define USB_IRQ_LEVEL 0x03C +#define USB_RELEASE_NUM 0x060 +#define USB_HC_CLASS_CODE 0x0C03 + +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Equates common to all host controllers +//--------------------------------------------------------------------------- +#define USB_PORT_STAT_DEV_CONNECTED BIT0 +#define USB_PORT_STAT_DEV_LOWSPEED BIT1 +#define USB_PORT_STAT_DEV_FULLSPEED BIT2 +#define USB_PORT_STAT_DEV_HISPEED 0//(BIT1 + BIT2) +#define USB_PORT_STAT_DEV_SUPERSPEED BIT3 +#define USB_PORT_STAT_DEV_SPEED_MASK (BIT1 + BIT2 + BIT3 + BIT7) +#define USB_PORT_STAT_DEV_SPEED_MASK_SHIFT 0x1 +#define USB_PORT_STAT_DEV_CONNECT_CHANGED BIT4 +#define USB_PORT_STAT_DEV_ENABLED BIT5 +#define USB_PORT_STAT_DEV_OWNER BIT6 +#define USB_PORT_STAT_DEV_SUPERSPEED_PLUS BIT7 + +#define USB_DEV_SPEED_LOW (USB_PORT_STAT_DEV_LOWSPEED >> USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) +#define USB_DEV_SPEED_FULL (USB_PORT_STAT_DEV_FULLSPEED >> USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) +#define USB_DEV_SPEED_HIGH (USB_PORT_STAT_DEV_HISPEED >> USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) +#define USB_DEV_SPEED_SUPER (USB_PORT_STAT_DEV_SUPERSPEED >> USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) +#define USB_DEV_SPEED_SUPER_PLUS (USB_PORT_STAT_DEV_SUPERSPEED_PLUS >> USB_PORT_STAT_DEV_SPEED_MASK_SHIFT) + +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Equates related to USB equipment list +//--------------------------------------------------------------------------- + //(EIP84455+)> +#define USB_TYPE_KEYBOARD BIT0 +#define USB_TYPE_MOUSE BIT1 +#define USB_TYPE_POINT BIT2 +#define USB_TYPE_HUB BIT3 +#define USB_TYPE_MASS_STORAGE BIT4 + //<(EIP84455+) + +// Bulk transfer error status (bLastCommandStatus) +#define USB_BULK_STALLED BIT0 +#define USB_BULK_TIMEDOUT BIT1 +#define USB_CONTROL_STALLED BIT2 + +#define USB_TRNSFR_ERRBIT_SHIFT 0 +#define USB_TRNSFR_BITSTUFF BIT0 +#define USB_TRNSFR_CRCERROR BIT1 +#define USB_TRNSFR_NAK BIT2 +#define USB_TRNSFR_BABBLE BIT3 +#define USB_TRSFR_BUFFER_ERROR BIT4 +#define USB_TRSFR_STALLED BIT5 +#define USB_TRNSF_ERRORS_MASK (USB_TRNSFR_ERRBIT_SHIFT | \ + USB_TRNSFR_BITSTUFF | USB_TRNSFR_CRCERROR |\ + USB_TRNSFR_NAK|USB_TRNSFR_BABBLE|USB_TRSFR_BUFFER_ERROR ) +#define USB_TRNSFR_TIMEOUT BIT6 + +//---------------------------------------------------------------------------- +// Equates regarding USB device info structure search parameter +//---------------------------------------------------------------------------- +#define USB_SRCH_DEV_ADDR 0x10 // +#define USB_SRCH_DEV_TYPE 0x20 // Next device of a given type +#define USB_SRCH_DEV_NUM 0x30 // Number of devices of certain type +#define USB_SRCH_DEVBASECLASS_NUM 0x31 // Number of devices of certain base class +#define USB_SRCH_HC_STRUC 0x40 // Next device of a given HC +#define USB_SRCH_DEV_INDX 0x80 // Device of a given index +/* +// USB Initialization Flags - passed in when USB is initialized +//---------------------------------------------------------------------------- +#define INIT_FLAG_MANUAL 0x07 //Bit 2-0: 000 = Auto enum + // 001 = KB on port 1 + // ... ... + // 111 = KB on port 7 +#define INIT_FLAG_ENUM_DISABLE 0x08 // 3: If set, do not enum the USB +#define INIT_FLAG_BEEP_DISABLE 0x10 // 4: If set, do not beep on new devices +#define INIT_FLAG_USB_STOP_EHCI_IN_OHCI_HANDOVER 0x20 +*/ +//---------------------------------------------------------------------------- +// Bit definitions for DeviceRequest.RequestType +//---------------------------------------------------------------------------- +// Bit 7: Data direction +#define USB_REQ_TYPE_OUTPUT 0x00 // 0 = Host sending data to device +#define USB_REQ_TYPE_INPUT 0x80 // 1 = Device sending data to host + +// Bit 6-5: Type +#define USB_REQ_TYPE_STANDARD 0x00 // 00 = Standard USB request +#define USB_REQ_TYPE_CLASS 0x20 // 01 = Class specific +#define USB_REQ_TYPE_VENDOR 0x40 // 10 = Vendor specific + +// Bit 4-0: Recipient +#define USB_REQ_TYPE_DEVICE 0x00 // 00000 = Device +#define USB_REQ_TYPE_INTERFACE 0x01 // 00001 = Interface +#define USB_REQ_TYPE_ENDPOINT 0x02 // 00010 = Endpoint +#define USB_REQ_TYPE_OTHER 0x03 // 00011 = Other + +//---------------------------------------------------------------------------- +// Values for DeviceRequest.RequestType and DeviceRequest.RequestCode fields +// combined as a word value. +//--------------------------------------------------------------------------- +#define USB_RQ_SET_ADDRESS ((0x05 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE) +#define USB_RQ_GET_DESCRIPTOR ((0x06 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE) +#define USB_RQ_GET_CONFIGURATION ((0x08 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE) +#define USB_RQ_SET_CONFIGURATION ((0x09 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE) +#define USB_RQ_SET_INTERFACE ((0x0B << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE) +#define USB_RQ_SET_FEATURE ((0x03 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE) + +#define USB_FSEL_DEV_REMOTE_WAKEUP 01 + +#define USB_RQ_GET_CLASS_DESCRIPTOR ((0x06 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE) +#define HID_RQ_GET_DESCRIPTOR ((0x06 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE) //(EIP38434+) +#define HID_RQ_SET_PROTOCOL ((0x0B << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE) +#define HID_RQ_SET_REPORT ((0x09 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE) +#define HID_RQ_SET_IDLE ((0x0A << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE) +#define HUB_RQ_GET_PORT_STATUS ((0x00 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER) +#define HUB_RQ_SET_PORT_FEATURE ((0x03 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER) +#define HUB_RQ_CLEAR_PORT_FEATURE ((0x01 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_OTHER) +#define HUB_RQ_SET_HUB_DEPTH ((0x0C << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE) + +//---------------------------------------------------------------------------- +// Bit definitions for HubDescriptor.HubFlags +//---------------------------------------------------------------------------- +#define HUB_FLAG_PWR_MODE_BITS 0x03 //Bit 1-0: Power switching mode used by hub +#define HUB_FLAG_PWR_MODE_GANG 0x00 // =00: All ports power on/off together +#define HUB_FLAG_PWR_MODE_INDIV 0x01 // =01: Ports power on/off individually +#define HUB_FLAG_PWR_MODE_FIXED 0x02 // =1x: Ports power is always on +#define HUB_FLAG_COMPOUND_DEV 0x04 //Bit 2: If set, hub is part of a compound device +#define HUB_FLAG_OVR_CUR_BITS 0x18 //Bit 4-3: Over-current protection mode used by hub +#define HUB_FLAG_OVR_CUR_GLOBAL 0x00 // =00: Hub reports only global over-current status +#define HUB_FLAG_OVR_CUR_INDIV 0x08 // =01: Hub reports individual over-current status +#define HUB_FLAG_OVR_CUR_NONE 0x10 // =1x: Hub has no over-current protection +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Hub Class Feature Selectors +//---------------------------------------------------------------------------- +#define HUB_FEATURE_C_HUB_LOCAL_POWER 0 +#define HUB_FEATURE_C_HUB_OVER_CURRENT 1 +#define HUB_FEATURE_PORT_CONNECTION 0 +#define HUB_FEATURE_PORT_ENABLE 1 //Hub port enable feature +#define HUB_FEATURE_PORT_SUSPEND 2 +#define HUB_FEATURE_PORT_OVER_CURRENT 3 +#define HUB_FEATURE_PORT_RESET 4 //Hub port reset feature +#define HUB_FEATURE_PORT_LINK_STATE 5 +#define HUB_FEATURE_PORT_POWER 8 //Hub port power feature +#define HUB_FEATURE_PORT_LOW_SPEED 9 //Hub port low speed feature +#define HUB_FEATURE_C_PORT_CONNECTION 16 //Hub port connect change feature +#define HUB_FEATURE_C_PORT_ENABLE 17 //Hub port enable change feature +#define HUB_FEATURE_C_PORT_SUSPEND 18 +#define HUB_FEATURE_C_PORT_OVER_CURRENT 19 +#define HUB_FEATURE_C_PORT_RESET 20 //Hub port reset change feature +#define HUB_FEATURE_PORT_U1_TIMEOUT 23 +#define HUB_FEATURE_PORT_U2_TIMEOUT 24 +#define HUB_FEATURE_C_PORT_LINK_STATE 25 +#define HUB_FEATURE_C_PORT_CONFIG_ERROR 26 +#define HUB_FEATURE_PORT_REMOTE_WAKE_MASK 27 +#define HUB_FEATURE_BH_PORT_RESET 28 +#define HUB_FEATURE_C_BH_PORT_RESET 29 +#define HUB_FEATURE_FORCE_LINKPM_ACCEPT 30 + +typedef enum { + HubLocalPower = 0, + HubOverCurrent, + PortConnection = 0, + PortEnable, + PortSuspend, + PortOverCurrent, + PortReset, + PortLinkState, + PortPower = 8, + PortLowSpeed, + PortConnectChange = 16, + PortEnableChange, + PortSuspendChange, + PortOverCurrentChange, + PortResetChange, + PortTest, + PortIndicator, + PortU1Timeout, + PortU2Timeout, + PortLinkStateChange, + PortConfigErrorChange, + PortRemoteWakeMask, + BhPortReset, + BhPortResetChange, + ForceLinkPmAccept +} HUB_FEATURE; + +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Hub Port Status Bit Definitions +//---------------------------------------------------------------------------- +#define HUB_PORT_STATUS_PORT_CONNECTION BIT0 //Bit 0: Set if device present +#define HUB_PORT_STATUS_PORT_ENABLED BIT1 //Bit 1: Set if port is enabled +#define HUB_PORT_STATUS_PORT_SUSPEND BIT2 //Bit 2: Set if device on port is suspended +#define HUB_PORT_STATUS_PORT_OVER_CURRENT BIT3 //Bit 3: Set if port has been powered down due to over-current +#define HUB_PORT_STATUS_PORT_RESET BIT4 //Bit 4: Set if reset sigaling is active +#define HUB_PORT_STATUS_PORT_POWER BIT8 //Bit 8: Set if port is enabled +#define HUB_PORT_STATUS_PORT_LOW_SPEED BIT9 //Bit 9: Set if a low speed device is attached +#define HUB_PORT_STATUS_PORT_HIGH_SPEED BIT10 //Bit 10: Set if a high speed device is attached +#define HUB_PORT_STATUS_PORT_TEST BIT11 +#define HUB_PORT_STATUS_PORT_INDICATOR BIT12 +#define HUB_PORT_STATUS_C_PORT_CONNECTION (BIT0 << 16) //Bit 0: Set if device has been attached/removed +#define HUB_PORT_STATUS_C_PORT_ENABLE (BIT1 << 16) //Bit 1: Set if port has been enabled/disabled by hardware in hub +#define HUB_PORT_STATUS_C_PORT_SUSPEND (BIT2 << 16) //Bit 2: Set if device has entered/left suspend state +#define HUB_PORT_STATUS_C_PORT_OVER_CURRENT (BIT3 << 16) //Bit 3: Set if over current indicator has changed +#define HUB_PORT_STATUS_C_PORT_RESET (BIT4 << 16) //Bit 4: Set when port reset sequence is complete + +#define USB3_HUB_PORT_STATUS_PORT_CONNECTION BIT0 +#define USB3_HUB_PORT_STATUS_PORT_ENABLED BIT1 +#define USB3_HUB_PORT_STATUS_PORT_OVER_CURRENT BIT3 +#define USB3_HUB_PORT_STATUS_PORT_RESET BIT4 +#define USB3_HUB_PORT_STATUS_PORT_LINK_STATE (BIT5 | BIT6 | BIT7 | BIT8) +#define USB3_HUB_PORT_STATUS_PORT_POWER BIT9 +#define USB3_HUB_PORT_STATUS_PORT_SPEED (BIT10 | BIT11 | BIT12) +#define USB3_HUB_PORT_STATUS_C_PORT_CONNECTION (BIT0 << 16) +#define USB3_HUB_PORT_STATUS_C_PORT_OVER_CURRENT (BIT3 << 16) +#define USB3_HUB_PORT_STATUS_C_PORT_RESET (BIT4 << 16) +#define USB3_HUB_PORT_STATUS_C_BH_PORT_RESET (BIT5 << 16) +#define USB3_HUB_PORT_STATUS_C_PORT_LINK_STATE (BIT6 << 16) +#define USB3_HUB_PORT_STATUS_C_PORT_CONFIG_ERROR (BIT7 << 16) + +#define USB3_HUB_PORT_LINK_U0 0x00 +#define USB3_HUB_PORT_LINK_U1 0x01 +#define USB3_HUB_PORT_LINK_U2 0x02 +#define USB3_HUB_PORT_LINK_U3 0x03 +#define USB3_HUB_PORT_LINK_DISABLED 0x04 +#define USB3_HUB_PORT_LINK_RXDETECT 0x05 +#define USB3_HUB_PORT_LINK_INACTIVE 0x06 +#define USB3_HUB_PORT_LINK_POLLING 0x07 +#define USB3_HUB_PORT_LINK_RECOVERY 0x08 +#define USB3_HUB_PORT_LINK_HOT_RESET 0x09 +#define USB3_HUB_PORT_LINK_COMPLIANCE_MODE 0x0A +#define USB3_HUB_PORT_LINK_LOOPBACK 0x0B + +#pragma pack(push, 1) + +typedef struct { + struct { + UINT16 Connected :1; + UINT16 Enabled :1; + UINT16 Suspend :1; + UINT16 OverCurrent :1; + UINT16 Reset :1; + UINT16 Reserved :3; + UINT16 Power :1; + UINT16 LowSpeed :1; + UINT16 HighSpeed :1; + UINT16 TestMode :1; + UINT16 Indicator :1; + UINT16 Reserved1 :3; + } PortStatus; + struct { + UINT16 ConnectChange :1; + UINT16 EnableChange :1; + UINT16 SuspendChange :1; + UINT16 OverCurrentChange :1; + UINT16 ResetChange :1; + UINT16 Reserved :11; + } PortChange; +} HUB_PORT_STATUS; + +typedef struct { + struct { + UINT16 Connected :1; + UINT16 Enabled :1; + UINT16 Reserved :1; + UINT16 OverCurrent :1; + UINT16 Reset :1; + UINT16 LinkState :4; + UINT16 Power :1; + UINT16 Speed :3; + UINT16 Reserved1 :3; + } PortStatus; + struct { + UINT16 ConnectChange :1; + UINT16 Reserved :2; + UINT16 OverCurrentChange :1; + UINT16 ResetChange :1; + UINT16 BhResetChange :1; + UINT16 LinkStateChange :1; + UINT16 ConfigErrorChange :1; + UINT16 Reserved1 :8; + } PortChange; +} USB3_HUB_PORT_STATUS; + +#pragma pack(pop) + +#define ENDPOINT_CLEAR_PORT_FEATURE (0x01 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_ENDPOINT + +#define ADSC_OUT_REQUEST_TYPE (0x00 << 8) | USB_REQ_TYPE_OUTPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE +#define ADSC_IN_REQUEST_TYPE (0x00 << 8) | USB_REQ_TYPE_INPUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE + +#define ENDPOINT_HALT 00 + +// Standard PCI configuration register offsets and relevant values +//------------------------------------------------------------------------------ +#define PCI_REG_VENDID 0x00 //PCI vendor ID register +#define PCI_REG_DEVID 0x02 //PCI device ID register +#define PCI_REG_COMMAND 0x04 //PCI command register +#define CMD_DEV_DISABLE 0x00 //Disables device when written to cmd reg +#define CMD_IO_SPACE 0x01 //IO space enable bit +#define CMD_MEM_SPACE 0x02 //Memory space enable bit +#define CMD_BUS_MASTER 0x4 //Bus master enable bit +#define CMD_SPECIAL_CYCLE 0x08 //Special cycle enable bit +#define CMD_MEM_INVALIDATE 0x10 //Memory write & invalidate enable bit +#define CMD_PAL_SNOOP 0x20 //VGA palette snoop enable bit +#define CMD_PARITY 0x40 //Parity error enable bit +#define CMD_WAIT_CYCLE 0x80 //Wait cycle control bit +#define CMD_SERR 0x100 //SERR# enable bit +#define CMD_FAST_BTOB 0x200 //Fast back-to-back enable bit +#define PCI_REG_STATUS 0x06 //PCI status register +#define STAT_RESET_ALL 0x0FFFF //Resets all status bits +#define PCI_REG_REVID 0x08 //PCI revision ID register +#define PCI_REG_IF_TYPE 0x09 //PCI interface type register +#define PCI_REG_SUB_TYPE 0x0A //PCI sub type register +#define PCI_REG_BASE_TYPE 0x0B //PCI base type register +#define PCI_REG_LINE_SIZE 0x0C //PCI cache line size register +#define PCI_REG_LATENCY 0x0D //PCI latency timer register +#define PCI_REG_LATENCY 0x0D //PCI latency timer register +#define PCI_REG_HEADER_TYPE 0x0E //PCI header type register +#define MULTI_FUNC_BIT 0x80 //If set, device is multi function +#define PCI_CFG_HEADER_STD 0x00 //Standard PCI config space +#define PCI_CFG_HEADER_PPB 0x01 //PCI-PCI bridge config space +#define PCI_REG_BIST 0x0F //PCI built in self test register +#define PCI_REG_FIRST_BASE_ADD 0x10 //PCI first base address register +#define PCI_REG_LAST_BASE_ADD 0x24 //PCI last base address register +#define PCI_BASE_ADD_PORT_BIT 0x01 //If set, base add reg is for I/O port +#define PCI_BASE_ADD_MEMTYPE 0x06 //Bits in lower word that are mem type +#define PCI_BASE_ADD_MT_32 0x00 //Memory must be located at 32 bit add +#define PCI_BASE_ADD_MT_20 0x02 //Memory must be located at 20 bit add +#define PCI_BASE_ADD_MT_64 0x04 //Memory must be located at 64 bit add +#define PCI_BASE_ADD_PREFETCH 0x08 //If set, memory is prefetchable +#define PCI_BASE_ADD_MEMMASK 0x0FFF0 //Bits in lower word that are memory mask +#define PCI_BASE_ADD_PORTMASK 0x0FFFC //Bits in lower word that are port mask +#define PCI_REG_ROM_BASE_ADD 0x30 //PCI expansion ROM base address register +#define PCI_BASE_ADD_ROMMASK 0x0FC00 //Bits in lower word that are ROM mask +#define PCI_REG_INT_LINE 0x3C //PCI interrupt line register +#define PCI_REG_INT_PIN 0x3D //PCI interrupt pin register +#define PCI_REG_MAX_GNT 0x3E //PCI max grant register +#define PCI_REG_MAX_LAT 0x3F //PCI max latency register + +#define INTR_CNTRLR_MASTER_PORT 0x020 +#define INTR_CNTRLR_SLAVE_PORT 0x0A0 +#define READ_IN_SERVICE_REGISTER 0x00B + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: USB_BADDEV_STRUC +// +// Description: This structure is used to define a non-compliant USB device +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// wVID WORD Vendor ID of the device +// wDID WORD Device ID of the device +// bBaseClass BYTE Base class of the device +// bSubClass BYTE Sub class of the device +// bProtocol BYTE Protocol used by the device +// wFlags INCMPT_FLAGS Incompatibility flags +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct { + UINT16 wVID; + UINT16 wDID; + UINT8 bBaseClass; + UINT8 bSubClass; + UINT8 bProtocol; + UINT16 wFlags; +} USB_BADDEV_STRUC; + + +//<AMI_GHDR_START> +//---------------------------------------------------------------------------- +// Name: INCMPT_FLAGS (Incompatibility attributes) +// +// Type: Equates +// +// Description: This equates are used to describe the incompatible USB mass +// storage devices. The bits defined are: +// BIT Description +// ============================================================= +// 0 1, indicates this device does not support mode sense command +// 1 1, indicates that this is a single LUN device (even though it is reporting as multiple LUN) +// 2 1, indicates that this device should be disabled +// 3 1, indicates this device does not support test unit ready command +// 4 1, indicates this device responds with wrong BOT status value +// 5 1, indicates that this device does not support start unit command +// 6 1, indicates that this device does not support read format capacity command +// 7 1, indicates that this hispeed device has to be in full speed always +// 8 1, indicates that this hispeed device has to be in hispeed always +// +// Notes: The device is identified by the vendor id and device id +// associated with the flags above +// +// Referrals: USB_BADDEV_STRUC +// +//---------------------------------------------------------------------------- +//<AMI_GHDR_END> + +#define USB_INCMPT_MODE_SENSE_NOT_SUPPORTED BIT0 +#define USB_INCMPT_SINGLE_LUN_DEVICE BIT1 +#define USB_INCMPT_DISABLE_DEVICE BIT2 +#define USB_INCMPT_TEST_UNIT_READY_FAILED BIT3 +#define USB_INCMPT_BOT_STATUS_FAILED BIT4 +#define USB_INCMPT_START_UNIT_NOT_SUPPORTED BIT5 +#define USB_INCMPT_FORMAT_CAPACITY_NOT_SUPPORTED BIT6 +#define USB_INCMPT_KEEP_FULLSPEED BIT7 +#define USB_INCMPT_KEEP_HISPEED BIT8 +#define USB_INCMPT_SET_BOOT_PROTOCOL_NOT_SUPPORTED BIT9 +#define USB_INCMPT_GETMAXLUN_NOT_SUPPORTED BIT10 +#define USB_INCMPT_RMH_DEVICE BIT11 +#define USB_INCMPT_HID_DATA_OVERFLOW BIT12 +#define USB_INCMPT_BOOT_PROTOCOL_IGNORED BIT13 +#define USB_INCMPT_REPORT_PROTOCOL_ONLY BIT14 //(EIP38434+) +#define USB_INCMPT_HID_BOOT_PROTOCOL_ONLY BIT15 + +//<AMI_SHDR_START> +//---------------------------------------------------------------------------- +// Name: HcDxeRecord +// +// Description: state information for USB_HC_PROTOCOL implementation +// +//---------------------------------------------------------------------------- +//<AMI_SHDR_END> + +typedef struct _HC_DXE_RECORD { + EFI_USB_HC_PROTOCOL hcprotocol; + EFI_USB2_HC_PROTOCOL hcprotocol2; + HC_STRUC *hc_data; + EFI_PCI_IO_PROTOCOL *pciIo; + DLIST AsyncTransfers; +} HC_DXE_RECORD; + +typedef struct { + QUEUE_T QCompleted; + UINTN DataLength; //size of each transfer + EFI_ASYNC_USB_TRANSFER_CALLBACK CallbackFunction; + VOID* Context; + EFI_EVENT Event; + DLINK Link; + UINT8 Lock; + UINT8 EndpointAddress; + UINT8 Data[1]; +} USBHC_INTERRUPT_DEVNINFO_T; + +int VALID_DEVINFO(DEV_INFO* pDevInfo); +VOID USB_AbortConnectDev(DEV_INFO* ); +EFI_STATUS UsbHcStrucValidation(HC_STRUC*); +EFI_STATUS UsbDevInfoValidation(DEV_INFO*); + +#endif // __USB_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbhid.c b/Core/EM/usb/rt/usbhid.c new file mode 100644 index 0000000..aa9eec6 --- /dev/null +++ b/Core/EM/usb/rt/usbhid.c @@ -0,0 +1,1474 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbhid.c 39 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 39 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbhid.c $ +// +// 39 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 +// +// 38 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 +// +// 37 4/29/15 5:29a Wilsonlee +// [TAG] EIP215830 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] CYBORG R.A.T3 Gaming Mouse left/right button has no +// function, instead DPI UP/DOWN config button has left/right click +// function. +// [RootCause] We get mouuse button data from constant data offset. +// [Solution] Mouse Data should be defining report fields that contain +// modifiable device data. +// [Files] usbms.c, usbhid.c, usbpoint.c +// +// 36 2/05/15 5:54a Wilsonlee +// [TAG] EIP203944 +// [Category] Improvement +// [Description] If InputReportDataLength is less than IntMaxPkt, we +// need to use IntMaxPkt polling interrupt data. +// [Files] usbhid.c +// +// 35 12/24/14 9:33p Wilsonlee +// [TAG] EIP194683 +// [Category] Improvement +// [Description] Add the flag "USB_INCMPT_HID_BOOT_PROTOCOL_ONLY" of usb +// bad device table to keep devices use boot protocol. +// [Files] usbkbd.c, usbms.c, usbhid.c, usbdef.h +// +// 34 10/05/14 10:06p Wilsonlee +// [TAG] EIP186639 +// [Category] Improvement +// [Description] Medigenic-Esterline USB keboard (Advanced Input Devices +// chip) workaround. +// [Files] usbhid.c +// +// 33 9/30/14 2:42a Wilsonlee +// [TAG] EIP183901 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] System will hang up when attach special docking. +// [RootCause] It hangs at HidParserLocal function because it caused +// dead loop if Field->UsageMax is 0xFFFF. +// [Solution] Change Data to UINT32. +// [Files] usbhid.c +// +// 32 9/02/14 3:53a Wilsonlee +// [TAG] EIP182567 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] POST B4h sometimes stays about 30 sec if using special +// KB/Ms. +// [RootCause] t's timeout in getting config or report descriptor +// commands. +// [Solution] Set the timeout to 500 ms. +// [Files] usb.c, usbhid.c, usbdef.h +// +// 31 8/07/14 2:19a Wilsonlee +// [TAG] EIP176549 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Microstep USB Keyboard issue. +// [RootCause] The report descriptor of Microstep USB Keyboard (Sonix +// Technology Co chip) has an error, Modifier keys is bitmap data, but it +// reports as array data. +// [Solution] We need to force variable flag for Modifier keys input +// item. +// [Files] usbhid.c, usbkbd.c, usbdef.h +// +// 30 5/06/14 5:15a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 29 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 +// +// 28 4/29/14 7:54p Wilsonlee +// [TAG] EIP163828 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The mouses stop more than 4 seconds during TP 0xB4 when +// power on several times. +// [RootCause] The device sometime doesn't respond the set report +// command. +// [Solution] Change the timeout of set report command to 100 ms. +// [Files] syskbc.c, sysnokbc.c, usbhid.c, amiusb.h +// +// 27 4/23/14 10:59p Wilsonlee +// [TAG] EIP158723 +// [Category] Improvement +// [Description] It sends set idle command before getting report +// descriptor command. +// [Files] usbhid.c +// +// 26 2/26/14 1:56a 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 +// +// 25 11/05/13 5:38a Ryanchou +// [TAG] EIP139807 +// [Category] Improvement +// [Description] Handle the 4 bytes of item size. +// [Files] usbhid.c +// +// 24 10/19/13 7:07a Ryanchou +// [TAG] EIP138257 +// [Category] Improvement +// [Description] Correct USB HID device type. +// [Files] amiusb.c, usbdef.h, usbhid.c, efiusbhid.c, uhcd.c +// +// 23 9/04/13 11:56p Ryanchou +// [TAG] N/A +// [Category] Improvement +// [Description] Add usage page check for HID set feature request. +// [Files] usbhid.c +// +// 22 7/04/13 5:48a Roberthsu +// [TAG] EIP127014 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Mouse drifting not smooth +// [RootCause] Bbecause Efi simple point protocol RelativeMovementX +// type is INT32. +// [Solution] Transfer data type to INT32. +// [Files] usbdef.h,usbhid.c,usbms.c,usbkbd.h +// +// 21 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 +// +// 20 3/07/13 8:52a Ryanchou +// [TAG] EIP113218 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB keyboard cannot work after ownership change back to +// BIOS +// [RootCause] The key repeat SMI does not generated because the HC is +// stopped. +// [Solution] Use the other HC to generate key repeat SMI +// [Files] usb.c, usbhid.c, usbkbd.c +// +// 19 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 18 11/29/12 7:47a Ryanchou +// [TAG] EIP107586 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Unplug USB keyboard does not uninstall EFI USB keyboard +// driver properly +// [RootCause] The EIP99431 changes clear DEV_INFO.bSubDeviceType in +// runtime keyboard driver, that cause EFI keyboard driver does not know +// what type of the device is. +// [Solution] Do not clear DEV_INFO.bSubDeviceType in runtime keyboard +// driver. +// [Files] usb.c, usbhid.c, efiusbhid.c +// +// 17 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 +// +// 16 10/26/12 8:50a Roberthsu +// [TAG] EIP101990 +// [Category] Improvement +// [Description] Add check inpurt mode. +// [Files] usbhid.c,usbpoint.c +// +// 15 8/27/12 5:07a Roberthsu +// [TAG] EIP98251 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] RF KB NumLock/ScrollLock/CapsLock indicator is not +// available during post or BIOS setup menu +// [RootCause] Set led command lost report id. +// [Solution] Check report id exist. +// [Files] syskbc.c,usbhid.c +// +// 14 8/13/12 3:24a Roberthsu +// [TAG] EIP96010 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The KB can not work under bios. +// [RootCause] Usage count overflow. +// [Solution] Add usage count check. +// [Files] usbdef.h,usbhid.c +// +// 13 5/04/12 2:37a Roberthsu +// [TAG] EIP89279 +// [Category] Improvement +// [Description] Add check totalcount condition. +// [Files] usbhid.c +// +// 12 5/03/12 6:25a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 11 4/24/12 3:52a Roberthsu +// [TAG] EIP84336 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] When insert the touch board, it will block the function +// of rear USB ports. +// [RootCause] Report buffer size not enough. +// [Solution] Create Report buffer by report item count. +// [Files] usbhid.c +// +// 10 4/05/12 7:42a Wilsonlee +// [TAG] EIP86001 +// [Category] Improvement +// [Description] Free the chunk of memory allocated using the +// USBMem_Alloc call when we didn't use it. +// [Files] usbhid.c, ehci.c +// +// 9 4/03/12 5:52a Roberthsu +// [TAG] EIP80948 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] When insert the touch board, it will block the function +// of rear USB ports. +// [RootCause] Report item not enough. +// [Solution] Create buffer use report length. +// [Files] usbhid.c,usbdef.h +// +// 8 3/23/12 4:28a Roberthsu +// [TAG] EIP84264 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] After updating usb module, system will hang at BIOS +// LOGO display. +// [RootCause] Allocate memory not enough. +// [Solution] Allocate memory by report length +// [Files] usbhid.c +// +// 7 12/14/11 2:12a Ryanchou +// [TAG] EIP76397 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] ASSERT occurred when executing "reconnect -r" under shell +// [RootCause] The EIP63188 changes locate all USB controllers at one +// time, the "reconnect -r" will connect ConIn and ConOut first, so USB +// driver only locate a controller. +// [Solution] Rollback the EIP63188 changes to avoid this issue. +// [Files] amiusbhc.c, efiusbhid.c, efiusbkb.c, uhcd.c, uhcd.h, +// usbbus.c usbhid.c +// +// 6 10/21/11 2:35a Roberthsu +// [TAG] EIP71068 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Thermaltake mouse is not work +// [RootCause] Because some undefine usage page report. +// [Solution] Get all input report. +// [Files] usbhid.c +// +// 5 9/27/11 1:41a Roberthsu +// [TAG] EIP67400 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Microsoft wireless Media Desktop 1000 can¡¦t work normal. +// [RootCause] Wireless ms report data contains usage page keyboard.And +// output data not contains vaild report id. +// [Solution] Check usage page led to decide kb or ms.Check correct +// report id with report data. +// [Files] usbkbd.c,usbhid.c,usbms.c +// +// 4 9/27/11 12:05a Roberthsu +// [TAG] EIP65344 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Razer mouse will hang in post +// [RootCause] Razer has report keyboard interface.But not report led +// usage. +// [Solution] Check if not report led usage page.Do not send led +// command. +// [Files] syskbc.c,usbhid.c,usbdef.h +// +// 3 9/26/11 11:45p Roberthsu +// [TAG] EIP67230 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ntrig touch panel can not use on CedarTrail +// [RootCause] Because ntrig report data over than 512 byte.Control +// transfer check if over 512 than set length is 512. +// [Solution] Remove check transfer length. +// [Files] ohci.c,uhci.c,usbhid.c +// +// 2 8/05/11 7:32a Ryanchou +// [TAG] EIP66231 +// [Category] Improvement +// [Description] Remove token POINT_SUPPORT.Add token USB_DEV_POINT.Add +// check core version in point driver.Add check device descriptor to send +// get lang id command.Modify check button usage page. +// [Files] efiusbhid.c, efiusbpoint.c, usbbus.c, usbhid.c, usbpoint.c, +// usbsrc.sdl +// +// 1 7/15/11 6:16a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, efiusbpoint.c, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, +// usb.c, usbdef.h, usbhid.c, usbkbd.c, usbkbd.h, usbms.c, usbpoint.c, +// usbrt.cif, usbsb.c, usbsetup.c, usbsrc.sdl, xhci.c +// +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: usbhid.c +// +// Description: USB HID class device driver +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" + +extern USB_GLOBAL_DATA *gUsbData; + +UINT8 UsbControlTransfer(HC_STRUC*, DEV_INFO*, DEV_REQ, UINT16, VOID*); + +VOID USBHIDInitialize (VOID); +UINT8 USBHIDCheckForDevice (DEV_INFO*, UINT8, UINT8, UINT8); +DEV_INFO* USBHIDConfigureDevice (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT16); +UINT8 USBHIDProcessData ( HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 USBHIDDisconnectDevice (DEV_INFO*); + +UINT8 HidGetReportDescriptor(HC_STRUC*, DEV_INFO*, HID_DESC*); + +VOID USBMSInitialize (VOID); +DEV_INFO* USBMSConfigureDevice (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT16); +DEV_INFO* USBKBDConfigureDevice (DEV_INFO*); //(EIP84455) +DEV_INFO* USBAbsConfigureDevice (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT16); +VOID CheckInputMode(DEV_INFO *DevInfo, HID_REPORT_FIELD * Field); //(EIP101990) + +VOID +USBHIDFillDriverEntries (DEV_DRIVER *fpDevDriver) +{ + fpDevDriver->bDevType = BIOS_DEV_TYPE_HID; + fpDevDriver->bBaseClass = BASE_CLASS_HID; + fpDevDriver->bSubClass = 0; + fpDevDriver->bProtocol = 0; + fpDevDriver->pfnDeviceInit = USBHIDInitialize; + fpDevDriver->pfnCheckDeviceType = USBHIDCheckForDevice; + fpDevDriver->pfnConfigureDevice = USBHIDConfigureDevice; + fpDevDriver->pfnDisconnectDevice = USBHIDDisconnectDevice; + + return; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBHIDInitialize (VOID) +// +// Description: This function returns fills the host controller driver +// routine pointers in the structure provided +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBHIDInitialize (VOID) +{ + USBKBDInitialize(); + USBMSInitialize(); + USB_InstallCallBackFunction(USBHIDProcessData); + + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMSCheckForMouse +// +// Description: This routine checks for mouse type device from the +// interface data provided +// +// Input: bBaseClass USB base class code +// bSubClass USB sub-class code +// bProtocol USB protocol code +// +// Output: BIOS_DEV_TYPE_MOUSE type on success or 0FFH on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHIDCheckForDevice ( + DEV_INFO* fpDevInfo, + UINT8 bBaseClass, + UINT8 bSubClass, + UINT8 bProtocol +) +{ + // + // Check the BaseClass, SubClass and Protocol for a HID/Boot/Mouse device. + // + if (bBaseClass != BASE_CLASS_HID) { + return USB_ERROR; + } + + if ((BOOT_PROTOCOL_SUPPORT != 0) || + (fpDevInfo->wIncompatFlags & USB_INCMPT_HID_BOOT_PROTOCOL_ONLY)) { + if (bSubClass != SUB_CLASS_BOOT_DEVICE) { + return USB_ERROR; + } + + if (bProtocol != PROTOCOL_KEYBOARD && + bProtocol != PROTOCOL_MOUSE) { + return USB_ERROR; + } + } + + return BIOS_DEV_TYPE_HID; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHIDConfigureKeyboard +// +// Description: This routine checks an interface descriptor of the USB device +// detected to see if it describes a HID/Boot/Keyboard device. +// If the device matches the above criteria, then the device is +// configured and initialized +// +// Input: fpHCStruc HCStruc pointer +// fpDevInfo Device information structure pointer +// fpDesc Pointer to the descriptor structure +// wStart Offset within interface descriptor +// supported by the device +// wEnd End offset of the device descriptor +// +// Output: FPDEV_INFO New device info structure, 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + //(EIP84455+)> +DEV_INFO* +USBHIDConfigureDevice ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpDesc, + UINT16 wStart, + UINT16 wEnd) +{ + ENDP_DESC *fpEndpDesc; + INTRF_DESC *fpIntrfDesc; + UINT8 *DescEnd; + HID_DESC *HidDesc = NULL; + DEV_REQ Request = {0}; + + fpDevInfo->bDeviceType = (UINT8)BIOS_DEV_TYPE_HID; + fpDevInfo->HidDevType = 0; + fpDevInfo->IntInEndpoint = 0; + fpDevInfo->IntOutEndpoint = 0; + + MemSet(&fpDevInfo->HidReport, sizeof(fpDevInfo->HidReport), 0); + + USB_DEBUG(3, "USBHIDConfigureDevice... \n"); + + fpDevInfo->bCallBackIndex = USB_InstallCallBackFunction(USBHIDProcessData); + + fpIntrfDesc = (INTRF_DESC*)(fpDesc + wStart); + DescEnd = fpDesc + ((CNFG_DESC*)fpDesc)->wTotalLength; // Calculate the end of descriptor block + fpEndpDesc = (ENDP_DESC*)((char*)fpIntrfDesc + fpIntrfDesc->bDescLength); + + //Select correct endpoint + for (;(fpEndpDesc->bDescType != DESC_TYPE_INTERFACE) && ((UINT8*)fpEndpDesc < DescEnd); + fpEndpDesc = (ENDP_DESC*)((UINT8 *)fpEndpDesc + fpEndpDesc->bDescLength)){ + if(!(fpEndpDesc->bDescLength)) { + break; // Br if 0 length desc (should never happen, but...) + } + + if (fpEndpDesc->bDescType == DESC_TYPE_HID ) { + HidDesc = (HID_DESC*)fpEndpDesc; + continue; + } + + if (fpEndpDesc->bDescType != DESC_TYPE_ENDPOINT ) { + continue; + } + + // + // 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) { + if (fpDevInfo->IntInEndpoint == 0) { + fpDevInfo->IntInEndpoint = fpEndpDesc->bEndpointAddr; + fpDevInfo->IntInMaxPkt = fpEndpDesc->wMaxPacketSize; + fpDevInfo->bPollInterval = fpEndpDesc->bPollInterval; + } + } else { + if (fpDevInfo->IntOutEndpoint == 0) { + fpDevInfo->IntOutEndpoint = fpEndpDesc->bEndpointAddr; + fpDevInfo->IntOutMaxPkt = fpEndpDesc->wMaxPacketSize; + } + } + } + + if (fpDevInfo->IntInEndpoint == 0) { + return 0; + } + + //Set protocol (Option) + if ((BOOT_PROTOCOL_SUPPORT != 0) && + !(fpDevInfo->wIncompatFlags & USB_INCMPT_SET_BOOT_PROTOCOL_NOT_SUPPORTED) || + (fpDevInfo->wIncompatFlags & USB_INCMPT_HID_BOOT_PROTOCOL_ONLY)) { + // + // Send the set protocol command, wValue = 0 (Boot protocol) + // + Request.wRequestType = HID_RQ_SET_PROTOCOL; + Request.wValue = 0; // 0: Boot Protocol + Request.wIndex = fpDevInfo->bInterfaceNum; + Request.wDataLength = 0; + + UsbControlTransfer(fpHCStruc, fpDevInfo, Request, 100, NULL); + } + + //Send Set_Idle command + Request.wRequestType = HID_RQ_SET_IDLE; + Request.wValue = 0; + Request.wIndex = fpDevInfo->bInterfaceNum; + Request.wDataLength = 0; + + UsbControlTransfer(fpHCStruc, fpDevInfo, Request, 100, NULL); + + if ((BOOT_PROTOCOL_SUPPORT == 0) && + !(fpDevInfo->wIncompatFlags & USB_INCMPT_HID_BOOT_PROTOCOL_ONLY)) { + HidGetReportDescriptor(fpHCStruc, fpDevInfo, HidDesc); + fpDevInfo->HidReport.Flag |= HID_REPORT_FLAG_REPORT_PROTOCOL; + if (fpDevInfo->PollingLength < fpDevInfo->IntInMaxPkt) { + fpDevInfo->PollingLength = fpDevInfo->IntInMaxPkt; + } + } else { + fpDevInfo->PollingLength = fpDevInfo->IntInMaxPkt; + switch (fpDevInfo->bProtocol) { + case PROTOCOL_KEYBOARD: + fpDevInfo->HidDevType = HID_DEV_TYPE_KEYBOARD; + break; + + case PROTOCOL_MOUSE: + fpDevInfo->HidDevType = HID_DEV_TYPE_MOUSE; + break; + + default: + break; + } + } + + if (fpDevInfo->HidDevType & HID_DEV_TYPE_KEYBOARD) { + if (!(USBKBDConfigureDevice(fpDevInfo))) { + return 0; + } + } + +//Active polling + if ((fpDevInfo->PollingLength != 0) && (fpDevInfo->bPollInterval != 0)) { + if (!((fpDevInfo->HidDevType & HID_DEV_TYPE_MOUSE) && (gUsbData->dUSBStateFlag & USB_FLAG_EFIMS_DIRECT_ACCESS))) { + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDActivatePolling)(fpHCStruc,fpDevInfo); + } + } + + + return fpDevInfo; +} + //<(EIP84455+) +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBHIDDisconnectDevice +// +// Description: This routine disconnects the keyboard by freeing +// the USB keyboard device table entry +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// +// Output: USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHIDDisconnectDevice ( + DEV_INFO *DevInfo +) +{ + HC_STRUC *HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + UINT16 Index; + + // Stop polling the endpoint + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDDeactivatePolling)(HcStruc, DevInfo); + DevInfo->IntInEndpoint = 0; + + if (DevInfo->HidDevType & HID_DEV_TYPE_KEYBOARD) { + USBKBDDisconnectDevice(DevInfo); + } + + if (DevInfo->HidReport.Fields != NULL) { + for (Index = 0; Index < DevInfo->HidReport.FieldCount; Index++) { + if (DevInfo->HidReport.Fields[Index]->Usages != NULL) { + USB_MemFree(DevInfo->HidReport.Fields[Index]->Usages, + GET_MEM_BLK_COUNT(DevInfo->HidReport.Fields[Index]->UsageCount * sizeof(UINT16))); + DevInfo->HidReport.Fields[Index]->Usages = NULL; + } + USB_MemFree(DevInfo->HidReport.Fields[Index], GET_MEM_BLK_COUNT(sizeof(HID_REPORT_FIELD))); + DevInfo->HidReport.Fields[Index] = NULL; + } + + USB_MemFree(DevInfo->HidReport.Fields, GET_MEM_BLK_COUNT(DevInfo->HidReport.FieldCount * sizeof(HID_REPORT_FIELD*))); + DevInfo->HidReport.Fields = NULL; + DevInfo->HidReport.ReportDescLen = 0; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: ExtractInputReportData +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +ExtractInputReportData ( + UINT8 *Report, + UINT16 Offset, + UINT16 Size +) +{ + UINT32 *Start; + UINT8 BitOffset; + UINT32 Data = 0; + + ASSERT(Data <= 32); + Start = (UINT32*)((UINTN)Report + (Offset >> 3)); + BitOffset = Offset & 0x7; + Data = (*Start >> BitOffset) & ((0x1 << Size) - 1); + return Data; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: GetItemData +// +// Description: This funtion copy data of the item to buffer. +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +GetItemData ( + HID_ITEM *Item, + VOID *Buffer, + UINT32 BufferSize +) +{ + UINT32 Size = Item->bSize > BufferSize ? BufferSize : Item->bSize; + MemSet(Buffer, BufferSize, 0); + MemCpy(Buffer, &Item->data, Size); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: AddUsage +// +// Description: This funtion adds usage into usage table. +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +AddUsage ( + HID_REPORT_FIELD *Field, + UINT16 Usage +) +{ + if (Field->UsageCount >= Field->MaxUsages) { + return; + } + + Field->Usages[Field->UsageCount++] = Usage; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: Add_Hid_Field +// +// Description: Add input or output item. +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + //(EIP84455+)> +VOID +AddField ( + HID_REPORT *Report, + HID_REPORT_FIELD *Field +) +{ + HID_REPORT_FIELD *NewField; + HID_REPORT_FIELD **Fields; + UINT16 Index; + + NewField = USB_MemAlloc(GET_MEM_BLK_COUNT(sizeof(HID_REPORT_FIELD))); + ASSERT(NewField != NULL); + if (NewField == NULL) { + return; + } + + if (Field->ReportId != 0) { + Report->Flag |= HID_REPORT_FLAG_REPORT_ID; + } + + MemCpy(NewField, Field, sizeof(HID_REPORT_FIELD)); + NewField->Usages = NULL; + + USB_DEBUG(4, "============================================== \n"); + USB_DEBUG(4, "Field index = %02x, \t", Report->FieldCount); + USB_DEBUG(4, "Flag = %02x\n", NewField->Flag); + USB_DEBUG(4, "UsagePage = %4x, \t", NewField->UsagePage); + USB_DEBUG(4, "ReportId = %02x\n", NewField->ReportId); + USB_DEBUG(4, "ReportCount = %02x, \t", NewField->ReportCount); + USB_DEBUG(4, "bReportSize = %02x\n", NewField->ReportSize); + USB_DEBUG(4, "LogicalMin = %4x, \t", NewField->LogicalMin); + USB_DEBUG(4, "LogicalMax = %4x\n", NewField->LogicalMax); + USB_DEBUG(4, "PhysicalMax = %4x, \t", NewField->PhysicalMax); + USB_DEBUG(4, "PhysicalMin = %4x\n", NewField->PhysicalMin); + USB_DEBUG(4, "UnitExponent = %2x, \t", NewField->UnitExponent); + USB_DEBUG(4, "UsageCount = %4x\n", NewField->UsageCount); + + if (NewField->UsageCount != 0) { + NewField->Usages = USB_MemAlloc (GET_MEM_BLK_COUNT(NewField->UsageCount * sizeof(UINT16))); + ASSERT(NewField->Usages != NULL); + if (NewField->Usages == NULL) { + return; + } + + MemCpy(NewField->Usages, Field->Usages, NewField->UsageCount * sizeof(UINT16)); + + USB_DEBUG(4, "Usages:\n"); + for (Index = 0; Index < NewField->UsageCount; Index++) { + if ((NewField->UsagePage == 0x01) && (NewField->Usages[Index] == 0x30)) { + if (NewField->Flag & HID_REPORT_FIELD_FLAG_RELATIVE) { + Report->Flag |= HID_REPORT_FLAG_RELATIVE_DATA; + } else { + Report->Flag |= HID_REPORT_FLAG_ABSOLUTE_DATA; + } + Report->AbsMaxX = NewField->LogicalMax; + } + if (NewField->Usages[Index] == 0x31) { + Report->AbsMaxY= NewField->LogicalMax; + } + USB_DEBUG(4, "%02X ", NewField->Usages[Index]); + if ((Index & 0xF) == 0xF) { + USB_DEBUG(4, "\n"); + } + } + } + USB_DEBUG(4, "\n============================================== \n"); + + Fields = USB_MemAlloc(GET_MEM_BLK_COUNT((Report->FieldCount + 1) * sizeof(HID_REPORT_FIELD*))); + ASSERT(Fields != NULL); + if (Fields == NULL) { + return; + } + + if (Report->Fields != NULL) { + MemCpy(Fields, Report->Fields, Report->FieldCount * sizeof(HID_REPORT_FIELD*)); + USB_MemFree(Report->Fields, GET_MEM_BLK_COUNT(Report->FieldCount * sizeof(HID_REPORT_FIELD*))); + } + + Report->Fields = Fields; + Report->Fields[Report->FieldCount++] = NewField; + + return; +} + //<(EIP84455+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidParserMain +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +HidParserMain ( + DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field, + HID_ITEM *Item +) +{ + UINT8 Data = 0; + //(EIP71068)> + switch (Item->bTag) { + case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: + GetItemData(Item, &Data, sizeof(Data)); + + // Check if it is application collection + if (Data == 0x01) { + if (Field->UsagePage == 0x01) { // Generic Desktop + switch (Field->Usages[Field->UsageCount - 1]) { + case 0x01: // Pointer + case 0x02: // Mouse + DevInfo->HidDevType |= HID_DEV_TYPE_MOUSE; + break; + case 0x06: // Keyboard + case 0x07: // KeyPad + DevInfo->HidDevType |= HID_DEV_TYPE_KEYBOARD; + break; + default: + break; + } + } else if (Field->UsagePage == 0x0D) { // Digitizer + if (Field->Usages[Field->UsageCount - 1] == 0x04) { + DevInfo->HidDevType |= HID_DEV_TYPE_POINT; + } + } + } + break; + + case HID_MAIN_ITEM_TAG_END_COLLECTION: + break; + + case HID_MAIN_ITEM_TAG_INPUT: + GetItemData(Item, &Field->Flag, sizeof(Field->Flag)); + Field->Flag = (Field->Flag & 7) | HID_REPORT_FIELD_FLAG_INPUT; + + // Microstep USB Keyboard (Sonix Technology Co chip) workaround + // The report descriptor has an error, Modifier keys is bitmap data, but + // it reports as array data. We force variable flag for Modifier keys input item. + if ((DevInfo->wVendorId == 0x0C45) && + ((DevInfo->wDeviceId == 0x7603) || (DevInfo->wDeviceId == 0x7624))) { + if ((Field->UsagePage == HID_UP_KEYBOARD) && + (Field->UsageMin == HID_UP_KEYBOARD_LEFT_CTRL) && + (Field->UsageMax == HID_UP_KEYBOARD_RIGHT_GUI)) { + Field->Flag |= HID_REPORT_FIELD_FLAG_VARIABLE; + } + } + + AddField(&DevInfo->HidReport, Field); + break; + + case HID_MAIN_ITEM_TAG_OUTPUT: + GetItemData(Item, &Field->Flag, sizeof(Field->Flag)); + Field->Flag &= 7; + //(EIP98251+)> + if (Field->UsagePage == 0x8) { + AddField(&DevInfo->HidReport, Field); + } //<(EIP98251+) + break; + + case HID_MAIN_ITEM_TAG_FEATURE: + CheckInputMode(DevInfo, Field); //(EIP101990) + break; + + default: + break; + } + //<(EIP71068) + //(EIP84455+)> +//Clear Local Item + MemSet(Field->Usages, Field->UsageCount * sizeof(UINT16), 0); + Field->UsageCount = 0; + Field->UsageMin = 0; + Field->UsageMax = 0; + + //<(EIP84455+) + return 0; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidParserGlobal +// +// Description: Parsing Global item +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 +HidParserGlobal ( + DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field, + HID_ITEM *Item +) +{ + switch (Item->bTag) { + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + GetItemData(Item, &Field->UsagePage, sizeof(Field->UsagePage)); + //(EIP65344+)> + //Get Led usage page + if (Field->UsagePage == 0x8) { + DevInfo->HidReport.Flag |= HID_REPORT_FLAG_LED_FLAG; + } + //<(EIP65344+) + break; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: + GetItemData(Item, &Field->LogicalMin, sizeof(Field->LogicalMin)); + break; + + case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: + GetItemData(Item, &Field->LogicalMax, sizeof(Field->LogicalMax)); + break; + //(EIP127014+)> + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: + GetItemData(Item, &Field->PhysicalMin, sizeof(Field->PhysicalMin)); + break; + + case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: + GetItemData(Item, &Field->PhysicalMax, sizeof(Field->PhysicalMax)); + break; + + case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: + GetItemData(Item, &Field->UnitExponent, sizeof(Field->UnitExponent)); + break; + //<(EIP127014+) + case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: + GetItemData(Item, &Field->ReportSize, sizeof(Field->ReportSize)); + break; + + case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: + GetItemData(Item, &Field->ReportCount, sizeof(Field->ReportCount)); + break; + + case HID_GLOBAL_ITEM_TAG_REPORT_ID: + GetItemData(Item, &Field->ReportId, sizeof(Field->ReportId)); + break; + + default: + break; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidParserLocal +// +// Description: Parsing Local item +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 +HidParserLocal ( + DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field, + HID_ITEM *Item +) +{ + UINT32 Data; + + GetItemData(Item, &Data, sizeof(Data)); + + switch (Item->bTag) { + case HID_LOCAL_ITEM_TAG_USAGE: + AddUsage(Field, Data); + break; + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + Field->UsageMin = Data; + break; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + Field->UsageMax = Data; + + // Medigenic-Esterline USB keboard (Advanced Input Devices chip) + // workaround. This device reports the wrong local minimum for + // keyboard data in its report descriptor, local minimum should be 0x00. + + if ((DevInfo->wVendorId == 0x059d) && (DevInfo->wDeviceId == 0x0708)) { + if ((Field->UsageMin == 0x01) && (Field->UsageMax == 0x65)) { + Field->UsageMin = 0x00; + } + } + + for (Data = Field->UsageMin; Data <= Field->UsageMax; Data++) { + AddUsage(Field, Data); + } + break; + + default: + break; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidParserReserved +// +// Description: Parsing Reserved item +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +HidParserReserved( + DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field, + HID_ITEM *Item +) +{ + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidParseReportDescriptor +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +HidParseReportDescriptor ( + DEV_INFO *DevInfo, + UINT8 *ReportDesc +) +{ + HID_REPORT *Report = &DevInfo->HidReport; + UINT8 *Start = ReportDesc; + UINT8 *End = Start + Report->ReportDescLen; + UINT16 Usages[0x300] = {0}; + HID_REPORT_FIELD Field = {0}; + HID_ITEM Item = {0}; + UINT8 Data; + UINT8 DataSize[] = {0, 1, 2, 4}; + + static UINT8 (*DispatchType[]) (DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field, HID_ITEM *Item) = { + HidParserMain, + HidParserGlobal, + HidParserLocal, + HidParserReserved + }; + + Field.Usages = Usages; + Field.MaxUsages = COUNTOF(Usages); + + while (Start < End) { + Data = *Start++; + + Item.bType = (Data >> 2) & 0x3; + Item.bTag = (Data >> 4) & 0xF; + Item.bSize = DataSize[Data & 0x3]; + + if ((Start + Item.bSize) > End) { + break; + } + + MemCpy(&Item.data.u32, Start, Item.bSize); + Start += Item.bSize; + DispatchType[Item.bType](DevInfo, &Field, &Item); + } + + return; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: CalculateInputReportDataLength +// +// Description: This function calculates max data length to be reported +// in the HID device. +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +CalculateInputReportDataLength ( + DEV_INFO *DevInfo +) +{ + UINT8 Index = 0; + HID_REPORT_FIELD *Field = NULL; + UINT16 ReportLen[256] = {0}; + UINT16 Length = 0; + UINT16 MaxLength = 0; + UINT16 ReportId = 0; + + for (Index = 0; Index < DevInfo->HidReport.FieldCount; Index++) { + Field = DevInfo->HidReport.Fields[Index]; + if (!(Field->Flag & HID_REPORT_FIELD_FLAG_INPUT)) { + continue; + } + + ReportId = Field->ReportId; + ReportLen[ReportId] += Field->ReportCount * Field->ReportSize; + } + + for (ReportId = 0; ReportId < COUNTOF(ReportLen); ReportId++) { + if (ReportLen[ReportId] == 0) { + continue; + } + + Length = (ReportLen[ReportId] + 7) >> 3; + if (ReportId != 0) { + Length++; + } + + MaxLength = MaxLength < Length ? Length : MaxLength; + } + + return MaxLength; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: HidGetReportDescriptor +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +HidGetReportDescriptor( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + HID_DESC *HidDesc +) +{ + UINT8 *ReportDesc = NULL; + UINT8 Index = 0; + UINT8 Status = USB_ERROR; + DEV_REQ Request = {0}; + + if (HidDesc == NULL) { + return USB_ERROR; + } + + if (HidDesc->bDescriptorLength == 0) { + return USB_SUCCESS; + } + + ReportDesc = USB_MemAlloc(GET_MEM_BLK_COUNT(HidDesc->bDescriptorLength)); + if (ReportDesc == NULL) { + return USB_ERROR; + } + + Request.wRequestType = HID_RQ_GET_DESCRIPTOR; + Request.wValue = DESC_TYPE_REPORT << 8; + Request.wIndex = DevInfo->bInterfaceNum; + Request.wDataLength = HidDesc->bDescriptorLength; + + for (Index = 0; Index < 3; Index++) { + Status = UsbControlTransfer(HcStruc, DevInfo, Request, USB_GET_REPORT_DESC_TIMEOUT_MS, ReportDesc); + if (Status == USB_SUCCESS) { + break; + } + } + + DevInfo->HidReport.ReportDescLen = HidDesc->bDescriptorLength ; + HidParseReportDescriptor(DevInfo, ReportDesc); + DevInfo->PollingLength = CalculateInputReportDataLength(DevInfo); + + USB_MemFree(ReportDesc, GET_MEM_BLK_COUNT(HidDesc->bDescriptorLength)); + return USB_SUCCESS; +} + //(EIP84455+)> + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: USBHIDProcessData +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHIDProcessData( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UINT8 DataType = 0; + UINT8 i; + UINT16 j; + HID_REPORT_FIELD *Field = NULL; + + DataType = DevInfo->bProtocol; + + if (DevInfo->HidReport.Flag & HID_REPORT_FLAG_REPORT_PROTOCOL) { + for (i = 0; i < DevInfo->HidReport.FieldCount; i++) { + Field = DevInfo->HidReport.Fields[i]; + + //Check is input? + if (!(Field->Flag & HID_REPORT_FIELD_FLAG_INPUT)) { + continue; + } + //if report id exist, check first byte + if (Field->ReportId != 0 && Field->ReportId != Buffer[0]) { + continue; + } + + if (Field->UsagePage == 7) { + DataType = HID_BTYPE_KEYBOARD; + } + //Check X,Y + if ((Field->UsagePage == 1) && (Field->UsageCount != 0)) { + for (j = 0; j < Field->UsageCount; j++) { + //find X + if (Field->Usages[j] == 0x30) { + if (Field->Flag & HID_REPORT_FIELD_FLAG_RELATIVE) { + DataType = HID_BTYPE_MOUSE; + } else { + DataType = HID_BTYPE_POINT; + } + } + + } + } + } + } + + switch(DataType) { + case HID_BTYPE_KEYBOARD: + USBKBDProcessKeyboardData(HcStruc, DevInfo, Td, Buffer, DataLength); + break; + case HID_BTYPE_MOUSE: + USBMSProcessMouseData(HcStruc, DevInfo, Td, Buffer, DataLength); + break; + case HID_BTYPE_POINT: + USBAbsProcessMouseData(HcStruc, DevInfo, Td, Buffer, DataLength); + break; + default: + break; + } + return USB_SUCCESS; +} + //<(EIP84455+) + + //(EIP101990+)> +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Input: CheckInputMode +// +// Description: +// +// intput: +// +// Output: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +CheckInputMode( + DEV_INFO *DevInfo, + HID_REPORT_FIELD *Field +) +{ + HC_STRUC *HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + DEV_REQ Request = {0}; + UINT8 *Buffer; + UINT16 Index; + + for (Index = 0; Index < Field->UsageCount; Index++) { + if (Field->UsagePage == 0xd) { + if (Field->Usages[Index] == 0x52 && Field->Usages[Index + 1] == 0x53) { + Request.wRequestType = HID_RQ_SET_REPORT; + Request.wValue = (0x03 << 8) | Field->ReportId; + Request.wIndex = DevInfo->bInterfaceNum; + Request.wDataLength = 3; + + Buffer = USB_MemAlloc (1); + Buffer[0] = Field->ReportId; + Buffer[1] = 2; + Buffer[2] = 0; + + UsbControlTransfer(HcStruc, DevInfo, Request, 100, Buffer); + + USB_MemFree(Buffer, 1); + break; + } + } + } +} + //<(EIP101990+) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + diff --git a/Core/EM/usb/rt/usbhub.c b/Core/EM/usb/rt/usbhub.c new file mode 100644 index 0000000..dda111d --- /dev/null +++ b/Core/EM/usb/rt/usbhub.c @@ -0,0 +1,1491 @@ + //**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbhub.c 54 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 54 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbhub.c $ +// +// 54 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 +// +// 53 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 +// +// 52 9/01/15 10:17p Wilsonlee +// [TAG] EIP235482 +// [Category] Improvement +// [Description] Select this alternate setting for multiple TTs hubs. +// [Files] usbhub.c, usb.c, amiusb.h, usbdef.h +// +// 51 5/11/15 4:32a Wilsonlee +// [TAG] EIP216986 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] BIOS can't find Realtek usb Lan dongle if this device is in +// some hubs. +// [RootCause] USB 3.0 hub may not set Connect Status Change bit. +// [Solution] Set the connect change flag if the BH Reset change or +// Reset change is set. +// [Files] usbhub.c +// +// 50 2/24/15 10:33p Wilsonlee +// [TAG] EIP204948 +// [Category] Improvement +// [Description] Reset the port if the link is Inactive. +// [Files] usbhub.c +// +// 49 2/05/15 5:46a Wilsonlee +// [TAG] EIP202436 +// [Category] Improvement +// [Description] Issues a SetPortFeature(PORT_POWER) request for hub +// ports over-current recovery. +// [Files] usbhub.c +// +// 48 1/22/15 10:19p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 47 6/20/14 3:14a Wilsonlee +// [TAG] EIP173968 +// [Category] Improvement +// [Description] Use MaxPacketSize of hubs to poll data for the device +// compatibility issue. +// [Files] usbhub.c +// +// 46 5/01/14 3:38a Ryanchou +// [TAG] EIP165208 +// [Category] Improvement +// [Description] Add 20 ms delay after port reset completed. +// [Files] usbhub.c +// +// 45 4/30/14 6:15a 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 +// +// 44 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 +// +// 43 11/26/13 4:18a Ryanchou +// [TAG] EIP143124 +// [Category] Improvement +// [Description] Added 1 ms delay after HUB port reset. +// [Files] usbhub.c +// +// 42 11/26/13 1:25a Wilsonlee +// [TAG] EIP143251 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] The usb mouse lost if it behinds TI TUSB8040A1 hub under +// BIOS. +// [RootCause] The device may connect later, then we clear connect +// change without setting the device is connected. +// [Solution] Don't get port status again before we clear the changes. +// [Files] usb.c, usbhub.c +// +// 41 7/22/13 10:31p Wilsonlee +// [TAG] EIP125357 +// [Category] Improvement +// [Description] Check if the port releases to a select host controller. +// [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h +// +// 40 6/30/13 11:40p Wilsonlee +// [TAG] EIP121374 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB flash is not recognized after re-plugged on DOS. +// [RootCause] Some devices need to wait for that they are being settle. +// [Solution] Delay for 50 ms allowing port to settle when pluged in +// devices. +// [Files] usbhub.c, usbdef.h +// +// 39 3/19/13 3:58a 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 +// +// 38 3/18/13 4:49a Ryanchou +// [TAG] EIP98377 +// [Category] Improvement +// [Description] Optimize USB controller timing. +// [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, +// usbdef.h, usbhub.c, xhci.c, uhcd.c +// +// 37 1/23/13 4:05a Wilsonlee +// [TAG] EIP111239 +// [Category] Improvement +// [Description] Handle the recovery state of the devces which are +// behind the USB3 hub. +// [Files] usbhub.c +// +// 36 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 35 12/07/12 3:04a Ryanchou +// +// 34 11/10/12 7:03a Ryanchou +// [TAG] EIP103966 +// [Category] Improvement +// [Description] Always issue set port power request to HiSpeed USB hub. +// [Files] usbhub.c +// +// 33 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 +// +// 32 9/28/12 2:39a 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 +// +// 31 5/03/12 6:26a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 30 3/04/12 4:40a Wilsonlee +// [TAG] EIP77526 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] BBS is not correct to detect BMC's USB virtual device +// [RootCause] It is failed to sets port feature for resetting hub +// ports. +// [Solution] We enlarge the timeout value for setting port feature. +// [Files] usbhub.c +// +// 29 8/08/11 5:18a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 28 6/21/11 11:04a Ryanchou +// [TAG] EIP59579 +// [Category] Improvement +// [Description] USB device information structure should be reserved for +// the UsbIO to use even install driver fail. +// [Files] usbmass.c, usbkbd.c, usbhub.c +// +// 27 3/30/11 8:14a Ryanchou +// [TAG] EIP54126 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Sometimes system hangs at checkpoint 0xB4. +// [RootCause] The bLength field of configuration descriptor is zero. +// [Solution] Check wether bLength field is zero before paring next +// descriptor. +// [Files] usb.c, usbbus.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c +// +// 26 3/29/11 10:56p Ryanchou +// [TAG] EIP55401 +// [Category] Improvement +// [Description] Improve the USB 3.0 device compatibility. +// [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, +// xhci.c +// +// 25 2/22/11 5:07a Ryanchou +// [TAG] EIP53108 +// [Category] Improvement +// [Description] Change the order of the request "Set Hub Depth". +// [Files] usbhub.c +// +// 24 2/18/11 1:50a Ryanchou +// [TAG] EIP52299 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB device can't detected after warm reset. +// [RootCause] If configure device fail first time, the connect status +// change will be clear, and second time port reset will not be issued. +// [Solution] Remove check connect status change. +// [Files] usbhub.c +// +// 23 11/11/10 11:37p Ryanchou +// [TAG] EIP45578 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB 3.0 device can't be detected. +// [RootCause] Address Device Command fails. +// [Solution] Reset the device and attempt the Address Device Command +// again. +// [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c +// +// 22 10/20/10 10:24a Ryanchou +// EIP44702: Added USB 3.0 hub support. +// +// 21 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 20 7/13/10 5:10a Ryanchou +// EIP39838: Fixed configure USB hub fail. +// +// 19 6/28/10 2:55a Ryanchou +// Add back 50ms delay after reseting a USB device. +// +// 18 6/22/10 9:30a Ryanchou +// EIP39374: Fixed USB key hot plug issue. +// +// 17 4/19/10 1:53p Olegi +// +// 16 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 15 5/22/09 1:47p Olegi +// Added the special treatment for in-built hubs. +// +// 14 5/08/09 8:58a Olegi +// Bugfix in USBHub_ProcessHubData. +// +// 13 12/16/08 10:49a Olegi +// Correction in the return values: 0 changed to NULL. EIP#17767. +// +// 11 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 10 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 9 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 8 3/20/07 12:19p Olegi +// +// 7 12/20/06 2:30p Olegi +// +// 5 10/26/06 4:01p Andriyn +// +// 4 7/10/06 2:58p Andriyn +// Fix: code simplifications +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 3/06/06 6:24p Olegi +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbHub.c +// +// Description: AMI USB Hub support implementation +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" + +extern USB_GLOBAL_DATA *gUsbData; + +VOID* USB_MemAlloc(UINT16); +UINT8 USB_MemFree(void _FAR_*, UINT16); +DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +UINT8 USB_StopDevice (HC_STRUC*, UINT8, UINT8); +VOID FixedDelay(UINTN); +UINT8 USB_ProcessPortChange (HC_STRUC*, UINT8, UINT8, UINT8); +UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC pfnCallBackFunction); +UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +UINT8 UsbControlTransfer(HC_STRUC*, DEV_INFO*, DEV_REQ, UINT16, VOID*); + +UINT8 USBHUBDisconnectDevice (DEV_INFO*); +UINT8 USBHub_EnablePort(HC_STRUC*, UINT8, UINT8); +UINT8 USBHub_DisablePort(HC_STRUC*, UINT8, UINT8); +UINT8 USBHub_ResetPort(HC_STRUC*, UINT8, UINT8); + +VOID UsbHubDeviceInit(VOID); +UINT8 USBHubCheckDeviceType (DEV_INFO*, UINT8, UINT8, UINT8); +UINT8 USBHub_ProcessHubData(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +DEV_INFO* USBHUBConfigureDevice (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT16); +UINT8 UsbHubResetPort(HC_STRUC*, DEV_INFO*, UINT8, BOOLEAN); + +UINT8 UsbHubCearHubFeature(HC_STRUC*, DEV_INFO*, HUB_FEATURE); +UINT8 UsbHubClearPortFeature(HC_STRUC*, DEV_INFO*, UINT8, HUB_FEATURE); +UINT8 UsbHubGetHubDescriptor(HC_STRUC*, DEV_INFO*, VOID*, UINT16); +UINT8 UsbHubGetHubStatus(HC_STRUC*, DEV_INFO*, UINT32*); +UINT8 UsbHubGetPortStatus(HC_STRUC*, DEV_INFO*, UINT8, UINT32*); +UINT8 UsbHubGetErrorCount(HC_STRUC*, DEV_INFO*, UINT8, UINT16*); +UINT8 UsbHubSetHubDescriptor(HC_STRUC*, DEV_INFO*, VOID*, UINT16); +UINT8 UsbHubSetHubFeature(HC_STRUC*, DEV_INFO*, HUB_FEATURE); +UINT8 UsbHubSetHubDepth(HC_STRUC*, DEV_INFO*, UINT16); +UINT8 UsbHubSetPortFeature(HC_STRUC*, DEV_INFO*, UINT8, HUB_FEATURE); + +PUBLIC +void +USBHubFillDriverEntries (DEV_DRIVER *fpDevDriver) +{ + fpDevDriver->bDevType = BIOS_DEV_TYPE_HUB; +// fpDevDriver->bBaseClass = BASE_CLASS_HUB; +// fpDevDriver->bSubClass = SUB_CLASS_HUB; + fpDevDriver->bProtocol = 0; + fpDevDriver->pfnDeviceInit = UsbHubDeviceInit; + fpDevDriver->pfnCheckDeviceType = USBHubCheckDeviceType; + fpDevDriver->pfnConfigureDevice = USBHUBConfigureDevice; + fpDevDriver->pfnDisconnectDevice = USBHUBDisconnectDevice; +} + + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHUBConfigureDevice +// +// Description: This function checks an interface descriptor of a device +// to see if it describes a USB hub. If the device is a hub, +// then it is configured and initialized. +// +// Input: pHCStruc HCStruc pointer +// pDevInfo Device information structure pointer +// pDesc Pointer to the descriptor structure +// supported by the device +// wStart Start offset of the device descriptor +// wEnd End offset of the device descriptor +// +// Output: New device info structure, 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBHUBConfigureDevice ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpDesc, + UINT16 wStart, + UINT16 wEnd) +{ + UINT8 bPortNum; + UINTN DelayValue; + UINT8* fpBuffer; + HUB_DESC *fpHubDesc; + UINT8 Status; + DEV_INFO* ParentHub; + BOOLEAN SetPortPower = FALSE; + ENDP_DESC *fpEndpDesc; + INTRF_DESC *fpIntrfDesc; + INTRF_DESC *AltIntrfDesc; + UINT16 DescLength; + UINT16 TotalLength; + + USB3_HUB_PORT_STATUS* Usb3HubPortSts = (USB3_HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + + // + // Set the BiosDeviceType field in DeviceTableEntry[0]. This serves as a flag + // that indicates a usable interface has been found in the current + // configuration. This is needed so we can check for other usable interfaces + // in the current configuration (i.e. composite device), but not try to search + // in other configurations. + // + fpDevInfo->bDeviceType = BIOS_DEV_TYPE_HUB; + fpDevInfo->bCallBackIndex = USB_InstallCallBackFunction(USBHub_ProcessHubData); + + fpIntrfDesc = (INTRF_DESC*)(fpDesc + wStart); + + // Check if the hub supports multiple TTs. + if (fpDevInfo->Flag & DEV_INFO_ALT_SETTING_IF) { + DescLength = wStart; + TotalLength = ((CNFG_DESC*)fpDesc)->wTotalLength; + for (;DescLength < TotalLength;) { + AltIntrfDesc = (INTRF_DESC*)(fpDesc + DescLength); + if ((AltIntrfDesc->bDescLength == 0) || + ((AltIntrfDesc->bDescLength + DescLength) > TotalLength)) { + break; + } + if ((AltIntrfDesc->bDescType == DESC_TYPE_INTERFACE) && (AltIntrfDesc->bAltSettingNum != 0)) { + if ((AltIntrfDesc->bBaseClass == BASE_CLASS_HUB) && + (AltIntrfDesc->bSubClass == SUB_CLASS_HUB) && + (AltIntrfDesc->bProtocol == PROTOCOL_HUB_MULTIPLE_TTS)) { + fpDevInfo->bProtocol = AltIntrfDesc->bProtocol; + fpDevInfo->bAltSettingNum = AltIntrfDesc->bAltSettingNum; + fpIntrfDesc = AltIntrfDesc; + break; + } + } + if (AltIntrfDesc->bDescLength) { + DescLength += (UINT16)AltIntrfDesc->bDescLength; + } else { + break; + } + } + } + + fpDesc+=((CNFG_DESC*)fpDesc)->wTotalLength; // Calculate the end of descriptor block + fpEndpDesc = (ENDP_DESC*)((char*)fpIntrfDesc + fpIntrfDesc->bDescLength); + + for( ;(fpEndpDesc->bDescType != DESC_TYPE_INTERFACE) && ((UINT8*)fpEndpDesc < fpDesc); + fpEndpDesc = (ENDP_DESC*)((UINT8 *)fpEndpDesc + fpEndpDesc->bDescLength)){ + + if(!(fpEndpDesc->bDescLength)) { + break; // Br if 0 length desc (should never happen, but...) + } + + if( fpEndpDesc->bDescType != DESC_TYPE_ENDPOINT ) { + continue; + } + + // + // 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; + break; + } + } + + if ((fpHCStruc->dHCFlag & HC_STATE_CONTROLLER_WITH_RMH) && + (fpDevInfo->bHubDeviceNumber & BIT7)) { + fpDevInfo->wIncompatFlags |= USB_INCMPT_RMH_DEVICE; + } + + fpDevInfo->HubDepth = 0; + ParentHub = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, + NULL, fpDevInfo->bHubDeviceNumber, NULL); + if(ParentHub) { + fpDevInfo->HubDepth = ParentHub->HubDepth + 1; + } + + if(fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + UsbHubSetHubDepth(fpHCStruc, fpDevInfo, fpDevInfo->HubDepth); + } + + // + // Allocate memory for getting hub descriptor + // + fpBuffer = USB_MemAlloc(sizeof(MEM_BLK)); + if (!fpBuffer) { + //USB_AbortConnectDev(fpDevInfo); //(EIP59579-) + return NULL; + } + + Status = UsbHubGetHubDescriptor(fpHCStruc, fpDevInfo, fpBuffer, sizeof(MEM_BLK)); + if(Status != USB_SUCCESS) { // Error + USB_MemFree(fpBuffer, sizeof(MEM_BLK)); + //USB_AbortConnectDev(fpDevInfo); //(EIP59579-) + return NULL; + } + fpHubDesc = (HUB_DESC*)fpBuffer; + fpDevInfo->bHubNumPorts = fpHubDesc->bNumPorts; + fpDevInfo->bHubPowerOnDelay = fpHubDesc->bPowerOnDelay; // Hub's ports have not been enumerated + + if (fpDevInfo->Flag & DEV_INFO_ALT_SETTING_IF) { + if (fpDevInfo->bAltSettingNum != 0) { + // Select this alternate setting for multiple TTs. + UsbSetInterface(fpHCStruc, fpDevInfo, fpDevInfo->bAltSettingNum); + } + } + + // + // Turn on power to all of the hub's ports by setting its port power features. + // This is needed because hubs cannot detect a device attach until port power + // is turned on. + // + for (bPortNum = 1; bPortNum <= fpDevInfo->bHubNumPorts; bPortNum++) + { + if (fpDevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE && + bPortNum == fpHCStruc->DebugPort) + { + continue; + } + + if (fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + UsbHubGetPortStatus(fpHCStruc, fpDevInfo, bPortNum, &gUsbData->dHubPortStatus); + if (Usb3HubPortSts->PortStatus.Power == 1) { + continue; + } + } + + UsbHubSetPortFeature(fpHCStruc, fpDevInfo, bPortNum, PortPower); + SetPortPower = TRUE; + } + + // + // Delay the amount of time specified in the PowerOnDelay field of + // the hub descriptor: in ms, add 30 ms to the normal time and multiply + // by 64 (in 15us). + // + if(SetPortPower) { + if (!(fpDevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE)) { + if (gUsbData->PowerGoodDeviceDelay == 0) { + DelayValue = (UINTN)fpDevInfo->bHubPowerOnDelay * 2 * 1000; // "Auto" + } else { + DelayValue = (UINTN)gUsbData->PowerGoodDeviceDelay * 1000* 1000; // convert sec->15 mcs units + } + FixedDelay(DelayValue); + } + } + + fpDevInfo->fpPollTDPtr = 0; + fpDevInfo->fpPollEDPtr = 0; + + // + // Free the allocated buffer + // + USB_MemFree(fpBuffer, sizeof(MEM_BLK)); + + fpDevInfo->HubPortConnectMap = 0; + + // + // Check for new devices behind the hub + // + for (bPortNum = 1; bPortNum <= fpDevInfo->bHubNumPorts; bPortNum++) { + USBCheckPortChange(fpHCStruc, fpDevInfo->bDeviceAddress, bPortNum); + } + + fpDevInfo->PollingLength = fpDevInfo->IntInMaxPkt; + + // Start polling the new device's interrupt endpoint. + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDActivatePolling) + (fpHCStruc, fpDevInfo); + + return fpDevInfo; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHubDisconnect +// +// Description: This routine disconnects the hub by disconnecting all the +// devices behind it +// +// Input: pDevInfo Device info structure pointer +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHUBDisconnectDevice (DEV_INFO* fpDevInfo) +{ + HC_STRUC* fpHCStruc = gUsbData->HcTable[fpDevInfo->bHCNumber - 1]; + UINT8 bPort; + + // Stop polling the endpoint + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(fpHCStruc->bHCType)].pfnHCDDeactivatePolling)(fpHCStruc,fpDevInfo); + fpDevInfo->IntInEndpoint = 0; + + // + // A hub device is being disconnected. For each of the hub's ports disconnect + // any child device connected. + // + fpHCStruc = gUsbData->HcTable[fpDevInfo->bHCNumber - 1]; + + for (bPort = 1; bPort <= (UINT8)fpDevInfo->bHubNumPorts; bPort++) + { + if (fpDevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE && + bPort == fpHCStruc->DebugPort) + { + continue; + } + + USB_StopDevice (fpHCStruc, fpDevInfo->bDeviceAddress, bPort); + } + + return USB_SUCCESS; + +} + +VOID +UsbHubDeviceInit( + VOID +) +{ + USB_InstallCallBackFunction(USBHub_ProcessHubData); + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHubCheckDeviceType +// +// Description: This routine checks for hub type device from the +// interface data provided +// +// Input: bBaseClass USB base class code +// bSubClass USB sub-class code +// bProtocol USB protocol code +// +// Output: BIOS_DEV_TYPE_HUB type on success or 0FFH on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHubCheckDeviceType( + DEV_INFO *DevInfo, + UINT8 BaseClass, + UINT8 SubClass, + UINT8 Protocol +) +{ + if (BaseClass == BASE_CLASS_HUB) { + return BIOS_DEV_TYPE_HUB; + } else { + return USB_ERROR; + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHub_GetPortStatus +// +// Description: This routine returns the hub port status +// +// Input: fpDevInfo USB device - the hub whose status has changed +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// bPortNum Port number +// pHCStruc HCStruc of the host controller +// +// Output: Port status flags (Refer USB_PORT_STAT_XX equates) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHub_GetPortStatus ( + HC_STRUC* HcStruc, + UINT8 HubAddr, + UINT8 PortNum, + BOOLEAN ClearChangeBits +) +{ + UINT8 PortSts = USB_PORT_STAT_DEV_OWNER; + UINT8 Status; + DEV_INFO *DevInfo; + HUB_FEATURE Feature; + UINT16 PortChange; + UINT8 i = 0; + + HUB_PORT_STATUS* HubPortSts = (HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + USB3_HUB_PORT_STATUS* Usb3HubPortSts = (USB3_HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, NULL, HubAddr, HcStruc); + ASSERT(DevInfo); + if (DevInfo == NULL) { + return 0; + } + + if (DevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE && + PortNum == HcStruc->DebugPort){ + return 0; + } + + Status = UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + if (Status == USB_ERROR) { + return USB_ERROR; + } + + USB_DEBUG(DEBUG_LEVEL_3, "Hub port[%d] status: %08x\n", PortNum, gUsbData->dHubPortStatus); + + if (DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + for (i = 0; i < 20; i++) { + if (Usb3HubPortSts->PortStatus.Reset == 0) { + break; + } + FixedDelay(10 * 1000); // 10ms + UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + } + + switch (Usb3HubPortSts->PortStatus.LinkState) { + case USB3_HUB_PORT_LINK_U0: + case USB3_HUB_PORT_LINK_RXDETECT: + break; + case USB3_HUB_PORT_LINK_RECOVERY: + for (i = 0; i < 20; i++) { + FixedDelay(10 * 1000); + UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + if (Usb3HubPortSts->PortStatus.LinkState != USB3_HUB_PORT_LINK_RECOVERY) { + break; + } + } + break; + case USB3_HUB_PORT_LINK_POLLING: + for (i = 0; i < 50; i++) { + FixedDelay(10 * 1000); + UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + if (Usb3HubPortSts->PortStatus.LinkState != USB3_HUB_PORT_LINK_POLLING) { + break; + } + } + if (Usb3HubPortSts->PortStatus.LinkState == USB3_HUB_PORT_LINK_U0 || + Usb3HubPortSts->PortStatus.LinkState == USB3_HUB_PORT_LINK_RXDETECT) { + break; + } + case USB3_HUB_PORT_LINK_INACTIVE: + // A downstream port can only exit from this state when directed, + // or upon detection of an absence of a far-end receiver termination + // or upon a Warm Reset. + // The Timeout of SS.Inactive.Quiet is 12 ms. + FixedDelay(12 * 1000); + UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + if (Usb3HubPortSts->PortStatus.LinkState == USB3_HUB_PORT_LINK_RXDETECT) { + break; + } + case USB3_HUB_PORT_LINK_COMPLIANCE_MODE: + UsbHubResetPort(HcStruc, DevInfo, PortNum, TRUE); + break; + default: + PortSts |= USB_PORT_STAT_DEV_CONNECTED; + break; + } + if (Usb3HubPortSts->PortChange.ConnectChange) { + PortSts |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + DevInfo->HubPortConnectMap &= (UINT16) (~(1 << PortNum)); + //UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, PortConnectChange); + } + if (Usb3HubPortSts->PortStatus.Connected) { + DevInfo->HubPortConnectMap |= (UINT16) (1 << PortNum); + PortSts |= USB_PORT_STAT_DEV_CONNECTED | USB_PORT_STAT_DEV_SUPERSPEED; + + // USB 3.0 hub may not set Connect Status Change bit, + // set the connect change flag if the BH Reset change or Reset change is set. + if (Usb3HubPortSts->PortChange.BhResetChange || Usb3HubPortSts->PortChange.ResetChange) { + PortSts |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + } + if (Usb3HubPortSts->PortStatus.Enabled) { + PortSts |= USB_PORT_STAT_DEV_ENABLED; + } + } + if (Usb3HubPortSts->PortChange.OverCurrentChange) { + if ((Usb3HubPortSts->PortStatus.OverCurrent == 0) && + (Usb3HubPortSts->PortStatus.Power == 0)) { + UsbHubSetPortFeature(HcStruc, DevInfo, PortNum, PortPower); + FixedDelay((UINTN)(DevInfo->bHubPowerOnDelay * 2 * 1000)); + } + } + } else { + if (HubPortSts->PortChange.ConnectChange) { + PortSts |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + //UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, PortConnectChange); + DevInfo->HubPortConnectMap &= (UINT16) (~(1 << PortNum)); + //if(HubPortSts->PortStatus.Connected) { + // Delay for 100ms allowing power to settle. + //FixedDelay(gUsbData->UsbTimingPolicy.HubPortConnect * 1000); // 50ms + //} + } + if (HubPortSts->PortStatus.Connected) { + PortSts |= USB_PORT_STAT_DEV_CONNECTED; + DevInfo->HubPortConnectMap |= (UINT16) (1 << PortNum); + if (HubPortSts->PortStatus.LowSpeed) { + PortSts |= USB_PORT_STAT_DEV_LOWSPEED; + } else if (HubPortSts->PortStatus.HighSpeed) { + PortSts |= USB_PORT_STAT_DEV_HISPEED; + } else { + PortSts |= USB_PORT_STAT_DEV_FULLSPEED; + } + if (HubPortSts->PortStatus.Enabled) { + PortSts |= USB_PORT_STAT_DEV_ENABLED; + } + } + if (HubPortSts->PortChange.OverCurrentChange) { + if ((HubPortSts->PortStatus.OverCurrent == 0) && + (HubPortSts->PortStatus.Power == 0)) { + UsbHubSetPortFeature(HcStruc, DevInfo, PortNum, PortPower); + FixedDelay((UINTN)(DevInfo->bHubPowerOnDelay * 2 * 1000)); + } + } + } + + // Clear all port status change + //UsbHubGetPortStatus(HcStruc, DevInfo, PortNum, &gUsbData->dHubPortStatus); + if (ClearChangeBits == TRUE) { + PortChange = (*((UINT16*)&HubPortSts->PortChange)); + for (Feature = PortConnectChange; Feature <= PortResetChange; Feature++) { + if (PortChange & 1) { + UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, Feature); + } + PortChange >>= 1; + } + + if (DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + if (Usb3HubPortSts->PortChange.LinkStateChange) { + UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, PortLinkStateChange); + } + if (Usb3HubPortSts->PortChange.ConfigErrorChange) { + UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, PortConfigErrorChange); + } + if (Usb3HubPortSts->PortChange.BhResetChange) { + UsbHubClearPortFeature(HcStruc, DevInfo, PortNum, BhPortResetChange); + } + } + } + + return PortSts; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHub_DisablePort +// +// Description: This routine disables the hub port +// +// Input: bHubAddr USB device address of the hub whose status +// has changed +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// bPortNum Port number +// pHCStruc HCStruc of the host controller +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHub_DisablePort( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bPortNum) +{ + DEV_INFO* fpDevInfo; + + HUB_PORT_STATUS* HubPortSts = (HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + + // + // Get DeviceInfo pointer + // + fpDevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, + (DEV_INFO*)0, + bHubAddr, + fpHCStruc); +// +// Disable the hub/port by clearing its Enable feature +// + if (fpDevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE && + bPortNum == fpHCStruc->DebugPort) + { + return USB_SUCCESS; + } + + if(fpDevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) return USB_SUCCESS; + + UsbHubGetPortStatus(fpHCStruc, fpDevInfo, bPortNum, &gUsbData->dHubPortStatus); + + // Perform control transfer with device request as HUB_RQ_CLEAR_PORT_FEATURE, + // wIndex = Port number, wValue = HUB_FEATURE_PORT_ENABLE, + // fpBuffer = 0 and wlength = 0 + // + if(HubPortSts->PortStatus.Enabled) { + UsbHubClearPortFeature(fpHCStruc, fpDevInfo, bPortNum, PortEnable); + } + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHub_EnablePort +// +// Description: This routine enables the hub port +// +// Input: bHubAddr USB device address of the hub whose status +// has changed +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// bPortNum Port number +// pHCStruc HCStruc of the host controller +// +// Output: USB_SUCCESS if the hub port is enabled. USB_ERROR otherwise +// +// Modified: Nothing +// +// Referrals: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHub_EnablePort( + HC_STRUC* fpHCStruc, + UINT8 bHubAddr, + UINT8 bPortNum) +{ + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHub_ResetPort +// +// Description: This routine resets the hub port +// +// Input: HCStruc HCStruc of the host controller +// HubAddr USB device address of the hub whose status +// has changed +// bit 7 : 1 - Root hub, 0 for other hubs +// bit 6-0 : Device address of the hub +// PortNum Port number +// +// Output: USB_SUCCESS if the hub port is enabled. USB_ERROR otherwise +// +// Modified: Nothing +// +// Referrals: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHub_ResetPort( + HC_STRUC* HcStruc, + UINT8 HubAddr, + UINT8 PortNum) +{ + UINT8 Status; + DEV_INFO* DevInfo; + + // + // Get DeviceInfo pointer + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, + (DEV_INFO*)0, HubAddr, HcStruc); + if (DevInfo == NULL) return USB_ERROR; + + if ((DevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE) && + (PortNum == HcStruc->DebugPort)) { + return USB_SUCCESS; + } + Status = UsbHubResetPort(HcStruc, DevInfo, PortNum, FALSE); + + return Status; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBHub_ProcessHubData +// +// Description: This routine is called with USB hub status change +// report data +// +// Input: pHCStruc Pointer to HCStruc +// pDevInfo Pointer to device information structure +// pTD Pointer to the polling TD +// pBuffer Pointer to the data buffer +// +// +// Notes: The status change data is an array of bit flags: +// Bit Description +// ---------------------------------------------------------- +// 0 Indicate connect change status for all ports +// 1 Indicate connect change status for port 1 +// 2 Indicate connect change status for port 2 +// ... .............. +// n Indicate connect change status for port n +// ----------------------------------------------------------- +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBHub_ProcessHubData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength + ) +{ + UINT8 PortNum; + UINT16 PortMap; + BOOLEAN ConnectDelay = FALSE; + + USB_DEBUG(DEBUG_LEVEL_3, "USBHub_ProcessHubData, gUsbData->bEnumFlag = %d\n", gUsbData->bEnumFlag); + // + // Check for enum flag and avoid hub port enumeration if needed + // + if (gUsbData->bEnumFlag == TRUE) return USB_SUCCESS; + + for (PortNum = 1; PortNum <= DevInfo->bHubNumPorts; PortNum++) { + PortMap = (UINT16)(1 << PortNum); + if (*(UINT16*)Buffer & PortMap) { + if (!ConnectDelay && ((~DevInfo->HubPortConnectMap) & PortMap)) { + //Delay for 50 ms allowing port to settle. + FixedDelay(50 * 1000); + ConnectDelay = TRUE; + } + // + // Set enumeration flag so that another device will not get enabled + // + gUsbData->bEnumFlag = TRUE; + + USBCheckPortChange(HcStruc, DevInfo->bDeviceAddress, PortNum); + + // + // Reset enumeration flag so that other devices can be enumerated + // + gUsbData->bEnumFlag = FALSE; + } + } + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubResetPort +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubResetPort( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 Port, + BOOLEAN WarmReset) +{ + UINT8 Status; + UINT8 i; + BOOLEAN IsResetChange; + + HUB_PORT_STATUS* HubPortSts = (HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + USB3_HUB_PORT_STATUS* Usb3HubPortSts = (USB3_HUB_PORT_STATUS*)&gUsbData->dHubPortStatus; + + if (WarmReset && DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + Status = UsbHubSetPortFeature(HcStruc, DevInfo, Port, BhPortReset); + if(Status != USB_SUCCESS) return USB_ERROR; + + for(i = 0; i < 10; i++) { + FixedDelay(10 * 1000); + Status = UsbHubGetPortStatus(HcStruc, DevInfo, Port, &gUsbData->dHubPortStatus); + if(Status != USB_SUCCESS) return USB_ERROR; + + if(Usb3HubPortSts->PortChange.BhResetChange) break; + } + if (!Usb3HubPortSts->PortChange.BhResetChange) { + return USB_ERROR; + } + + Status = UsbHubClearPortFeature(HcStruc, DevInfo, Port, BhPortResetChange); + if(Status != USB_SUCCESS) return USB_ERROR; + + Status = UsbHubClearPortFeature(HcStruc, DevInfo, Port, PortResetChange); + if(Status != USB_SUCCESS) return USB_ERROR; + + } else { + Status = UsbHubSetPortFeature(HcStruc, DevInfo, Port, PortReset); + if(Status != USB_SUCCESS) return USB_ERROR; + + // The duration of the Resetting state is nominally 10 ms to 20 ms + FixedDelay(20 * 1000); // 20 ms delay + + for(i = 0; i < 10; i++) { + Status = UsbHubGetPortStatus(HcStruc, DevInfo, Port, &gUsbData->dHubPortStatus); + if(Status != USB_SUCCESS) return USB_ERROR; + + if(DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) { + IsResetChange = Usb3HubPortSts->PortChange.ResetChange ? TRUE : FALSE; + } else { + IsResetChange = HubPortSts->PortChange.ResetChange ? TRUE : FALSE; + } + + if(IsResetChange) break; + + FixedDelay(5 * 1000); // 5 ms delay + } + if (!IsResetChange) { + return USB_ERROR; + } + + Status = UsbHubClearPortFeature(HcStruc, DevInfo, Port, PortResetChange); + if(Status != USB_SUCCESS) return USB_ERROR; + + if (DevInfo->bEndpointSpeed != USB_DEV_SPEED_SUPER) { + if (!(DevInfo->wIncompatFlags & USB_INCMPT_RMH_DEVICE)) { + FixedDelay(20 * 1000); // 20 ms + } else if (HubPortSts->PortStatus.LowSpeed == 1) { + // 1 ms delay for Low-Speed device + FixedDelay(1 * 1000); + } + } + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubCearHubFeature +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubCearHubFeature( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + HUB_FEATURE HubFeature) +{ + return USB_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubClearPortFeature +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubClearPortFeature( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 Port, + HUB_FEATURE PortFeature) +{ + DEV_REQ DevReq; + + DevReq.wRequestType = HUB_RQ_CLEAR_PORT_FEATURE; + DevReq.wValue = PortFeature; + DevReq.wIndex = Port; + DevReq.wDataLength = 0; + + return UsbControlTransfer(HcStruc, DevInfo, DevReq, 50, NULL); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubGetHubDescriptor +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubGetHubDescriptor( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + VOID* Buffer, + UINT16 Length) +{ + DEV_REQ DevReq; + + DevReq.wRequestType = USB_RQ_GET_CLASS_DESCRIPTOR; + DevReq.wValue = DevInfo->bEndpointSpeed == + USB_DEV_SPEED_SUPER ? DESC_TYPE_SS_HUB << 8 : DESC_TYPE_HUB << 8; + DevReq.wIndex = 0; + DevReq.wDataLength = Length; + + return UsbControlTransfer(HcStruc, DevInfo, DevReq, 150, Buffer); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubGetHubStatus +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubGetHubStatus( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT32* HubStatus) +{ + return USB_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubGetPortStatus +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubGetPortStatus( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 Port, + UINT32* PortStatus) +{ + DEV_REQ DevReq; + + DevReq.wRequestType = HUB_RQ_GET_PORT_STATUS; + DevReq.wValue = 0; + DevReq.wIndex = Port; + DevReq.wDataLength = 4; + + return UsbControlTransfer(HcStruc, DevInfo, DevReq, 150, PortStatus); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubGetErrorCount +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubGetErrorCount( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 Port, + UINT16* ErrorCount) +{ + return USB_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubSetHubDescriptor +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubSetHubDescriptor( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + VOID* Buffer, + UINT16 Length) +{ + return USB_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubSetHubFeature +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubSetHubFeature( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + HUB_FEATURE HubFeature) +{ + return USB_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubSetHubDepth +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubSetHubDepth( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT16 HubDepth) +{ + DEV_REQ DevReq; + + DevReq.wRequestType = HUB_RQ_SET_HUB_DEPTH; + DevReq.wValue = HubDepth; + DevReq.wIndex = 0; + DevReq.wDataLength = 0; + + return UsbControlTransfer(HcStruc, DevInfo, DevReq, 50, NULL); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UsbHubSetPortFeature +// +// Description: +// +// Input: +// +// Output: USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbHubSetPortFeature( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 Port, + HUB_FEATURE PortFeature) +{ + DEV_REQ DevReq; + + DevReq.wRequestType = HUB_RQ_SET_PORT_FEATURE; + DevReq.wValue = PortFeature; + DevReq.wIndex = Port; + DevReq.wDataLength = 0; + + return UsbControlTransfer(HcStruc, DevInfo, DevReq, 100, NULL); //(EIP77526) +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbkbd.c b/Core/EM/usb/rt/usbkbd.c new file mode 100644 index 0000000..e7240ad --- /dev/null +++ b/Core/EM/usb/rt/usbkbd.c @@ -0,0 +1,1315 @@ +#pragma warning(disable: 4001) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbkbd.c 70 10/16/16 10:11p Wilsonlee $ +// +// $Revision: 70 $ +// +// $Date: 10/16/16 10:11p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbkbd.c $ +// +// 70 10/16/16 10:11p 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 +// +// 69 7/21/16 11:00p Wilsonlee +// Build error if USB_HID_KEYREPEAT_USE_SETIDLE is 1. +// +// 68 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 +// +// 67 12/24/14 9:33p Wilsonlee +// [TAG] EIP194683 +// [Category] Improvement +// [Description] Add the flag "USB_INCMPT_HID_BOOT_PROTOCOL_ONLY" of usb +// bad device table to keep devices use boot protocol. +// [Files] usbkbd.c, usbms.c, usbhid.c, usbdef.h +// +// 66 11/23/14 9:24p Wilsonlee +// [TAG] EIP190127 +// [Category] Improvement +// [Description] Remove scan code algorithm update. +// [Files] usbkbd.c +// +// 65 11/23/14 9:10p Wilsonlee +// [TAG] EIP188119 +// [Category] Improvement +// [Description] Disconnect devices and uninstall usb device related +// protocols if we call stop api for the host controllers. +// [Files] usbkbd.c, usbbus.c, uhcd.h, uhcd.c +// +// 64 8/07/14 2:20a Wilsonlee +// [TAG] EIP176549 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Microstep USB Keyboard issue. +// [RootCause] The report descriptor of Microstep USB Keyboard (Sonix +// Technology Co chip) has an error, Modifier keys is bitmap data, but it +// reports as array data. +// [Solution] We need to force variable flag for Modifier keys input +// item. +// [Files] usbhid.c, usbkbd.c, usbdef.h +// +// 63 7/04/14 7:31a Wilsonlee +// [TAG] EIP176044 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] NEC USB keyboard doesn't work +// [RootCause] When we extract input report data, the report offset is +// incorrect if ReportId isn't 0. +// [Solution] Adjust report offset. +// [Files] usbkbd.c +// +// 62 5/15/14 5:41a Wilsonlee +// Fix the code check error result. +// +// 61 5/06/14 5:15a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 60 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 +// +// 59 11/05/13 4:47a Ryanchou +// [TAG] EIP135636 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] NumLock LED cannot be on/off properly. +// [RootCause] It is the side effect of EIP #107429 changes, the +// keyboard does not generate break code when pressing NumLock. +// [Solution] Remove the EIP #107429 changes. +// [Files] amiusb.c, usbkbd.c, efiusbkb.c +// +// 58 3/07/13 8:53a Ryanchou +// [TAG] EIP113218 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB keyboard cannot work after ownership change back to +// BIOS +// [RootCause] The key repeat SMI does not generated because the HC is +// stopped. +// [Solution] Use the other HC to generate key repeat SMI +// [Files] usb.c, usbhid.c, usbkbd.c +// +// 57 1/23/13 4:35a Wilsonlee +// [TAG] EIP109538 +// [Category] Improvement +// [Description] Fix the code check error result. +// [Files] usbkbd.c, usbCCID.c, usbbus.c, efiusbccid.c +// +// 56 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 55 1/07/13 12:56a Wilsonlee +// [TAG] EIP111305 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] It is failed at reloading the usb keyboard driver. +// [RootCause] The DEV_INFO_VALID_STRUC and DEV_INFO_DEV_PRESENT flag +// were cleared when the usb driver is disconnecting. +// [Solution] We should not clear the DEV_INFO_VALID_STRUC and +// DEV_INFO_DEV_PRESENT flag at USBKBDDisconnectDevice. +// [Files] usbkbd.c, usbbus.c +// +// 54 12/19/12 3:38a Roberthsu +// [TAG] EIP107262 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] CHOC keyboard can not work. +// [RootCause] Usage offset error. +// [Solution] Count correct usage offset.Ceck correct usage offset. +// [Files] usbkbd.c +// +// 53 12/02/12 10:34p Roberthsu +// [TAG] EIP102150 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Push key and unplug KB , character repeat can not. +// stop +// [RootCause] Because repeat key does not clear when usb keyboard +// unplug. +// [Solution] When keyboard disconnrct, clear keyboard device id with +// device id buffer and scancode buffer. +// [Files] amiusb.c,syskbc.c,uhcd.c,usbkbd.c +// +// 52 11/20/12 9:08p Wilsonlee +// [TAG] EIP90887 +// [Category] New Feature +// [Description] Add a hook to check keyboard buffer for speicial chars. +// [Files] usb.sdl, usbrt.mak, usbkbd.c +// +// 51 11/14/12 4:26a Roberthsu +// [TAG] EIP105587 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Rapoo keyboard press key have some garbage key. +// [RootCause] Get report descriptor need skip constant data. +// [Solution] Skip constant data. +// [Files] usbkbd.c +// +// 50 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 +// +// 49 8/07/12 4:47a Roberthsu +// [TAG] EIP93637 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Keyboard operate incorrectly in BIOS +// [RootCause] When keyboard disconnect.Usb keyboard buffer does not +// clear. +// [Solution] Clear usb keyboard buffer and repeat key. +// [Files] usbkbd.c +// +// 48 8/06/12 11:53p Roberthsu +// [TAG] EIP95349 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Roccat ISKU Keyboard can not work +// [RootCause] Variable value overflow. +// [Solution] Change variable type. +// [Files] usbkbd.c +// +// 47 5/23/12 7:56a Roberthsu +// [TAG] EIP90797 +// [Category] Improvement +// [Description] Fix keyboard buffer transfer error +// [Files] usbkbd.c +// +// 46 5/03/12 6:27a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 45 4/24/12 3:40a Roberthsu +// [TAG] EIP83888 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Can not catch F8 key event on Keyboard +// [RootCause] OS only call readkeystroke once.If OS get break key +// readkeystroke will return EFI_NOT_READY. +// [Solution] UsbKbdReadKeyStroke will serach available key in usb +// data buffer.Fixed key repeat can not work when efi to legacy or legacy +// to efi. +// [Files] efiusbkb.c,usbkbd.c +// +// 44 3/05/12 1:26a Rameshr +// [TAG] EIP81057 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Stall after RAID BIOS +// [RootCause] Make code and break code handled by different environment +// ( EFI, Legacy) +// [Solution] If the Makecode processed by Legacy, the breakcode also +// send to Legacy. The same applies for EFI also. +// [Files] UsbKbd.c +// +// 43 1/04/12 6:56a Ryanchou +// [TAG] EIP72505 +// [Category] Improvement +// [Description] Clear the legacy USB keyboard buffer when switching +// between EFI and legacy. +// [Files] syskbc.c, uhcd.c, usbkbd.c +// +// 42 12/22/11 6:36a Roberthsu +// [TAG] EIP77936 +// [Category] Improvement +// [Description] Chang set_idle command timeout to 1sec +// [Files] usbkbd.c +// +// 41 11/03/11 11:51p Roberthsu +// [TAG] EIP73685 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ducky keyboard can not work. +// [RootCause] Ducky keyboard report key usage is by usage keyboard +// arrow. +// [Solution] Get start offset by keyboard usage page . +// [Files] usbkbd.c +// +// 40 9/27/11 1:37a Roberthsu +// [TAG] EIP67400 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Microsoft wireless Media Desktop 1000 can¡¦t work normal. +// [RootCause] Wireless ms report data contains usage page keyboard.And +// output data not contains vaild report id. +// [Solution] Check usage page led to decide kb or ms.Check correct +// report id with report data. +// [Files] usbkbd.c,usbhid.c,usbms.c +// +// 39 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 38 7/13/11 3:32a Ryanchou +// [TAG] EIP63973 +// [Category] Improvement +// [Description] Change the order of Set Protocol command and Set Idle +// command. +// [Files] usbkbd.c +// +// 37 6/21/11 11:02a Ryanchou +// [TAG] EIP59579 +// [Category] Improvement +// [Description] USB device information structure should be reserved for +// the UsbIO to use even install driver fail. +// [Files] usbmass.c, usbkbd.c, usbms.c +// +// 36 3/30/11 8:17a Ryanchou +// [TAG] EIP54126 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Sometimes system hangs at checkpoint 0xB4. +// [RootCause] The bLength field of configuration descriptor is zero. +// [Solution] Check wether bLength field is zero before paring next +// descriptor. +// [Files] usb.c, usbbus.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c +// +// 35 2/10/11 7:40a Ryanchou +// [TAG] EIP52206 +// [Category] Improvement +// [Description] Remote wakeup command should be sent before sleep, +// comment out the command. +// [Files] usbkbd.c, usbms.c +// +// 34 1/17/11 4:34a Ryanchou +// [TAG] EIP51108 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Some HID devices that has two interfaces can't work. +// [RootCause] BIOS using the wrong endpoint to poll KBD/MS data. +// [Solution] Get the first interrupt in endpoint when parsing +// descriptors. +// [Files] usbkbd.c, usbms.c +// +// 33 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 32 3/11/10 9:41a Olegi +// +// 31 11/24/09 11:38a Olegi +// EIP#29733 - BIOS adds an USB API (Block KBC Access) +// +// 30 11/13/09 9:13a Olegi +// EIP31023: key repeat rates are defined by SDL tokens. +// +// 29 9/15/09 12:21p Olegi +// Added KEY_REPEAT_LOGIC functionality. EIP#25841 +// +// 28 5/05/09 10:21a Olegi +// Modification in USBKBDConnectKeyboard. Resolves the problem of device +// being reconnected using the SW (DisconnectController->ConnectController +// sequence). EIP#21456. +// +// 27 4/20/09 9:26a Olegi +// Completion of the fix for EIP#19563. +// +// 26 3/27/09 10:15a Olegi +// Modifications in USBKBDProcessKeyboardData: keypress and key release +// are synchronized between the modes (EFI/Legacy). If key is pressed in +// one mode and released in the other, then keypress is discarded. This +// fixes the problem of accidental key repeat sequence due to the mode +// change. EIP #19563. +// +// 25 9/19/08 4:44p Olegi +// Bugfix in USBKBDPeriodicInterruptHandler (EIP#16452) that takes care of +// the key release situation. +// +// 24 9/05/08 4:19p Olegi +// Removed calls to fpCallbackNotify functions, they are implemented in +// SMI. +// +// 23 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 21 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 20 30/10/07 2:02p Anandakrishnanl +// Updated USBKBDPeriodicInterruptHandler to see if CallbackNotify2 is not +// NULL beforfe calling it. +// +// 19 30/10/07 12:20p Anandakrishnanl +// Updated USBKBDPeriodicInterruptHandler to see if CallbackNotify3 is not +// NULL beforfe calling it. +// +// 18 9/27/07 4:12p Olegi +// +// 17 3/20/07 12:17p Olegi +// Legacy free related changes. +// +// 15 10/18/06 9:40a Andriyn +// Fix: race condition on hot-plug in / plug-off +// +// 14 5/17/06 3:52p Fredericko +// Fix: Mouse Button events get lost: no auto-repeat +// +// 13 4/26/06 12:26p Olegi +// +// 12 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 11 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 10 3/06/06 6:23p Olegi +// +// 9 3/01/06 3:50p Olegi +// ProcessKeyboardData is change to use USB_FLAG_RUNNING_UNDER_OS flag. +// +// 8 2/06/06 9:34a Andriyn +// +// 7 8/26/05 12:25p Andriyn +// Simulate Mouse Sampling rate by disabling Mouse Polling (reduce USB +// SMI# generation) +// +// 6 8/25/05 7:19p Andriyn +// USB Keyboard and mouse to use EMUL 60/64 for passing data to KBC. +// Fall-back when EMUL 60/64 is not present +// +// 5 8/11/05 9:53a Olegi +// 60/64 port emulation related fixes for EMU6064 driver. +// +// 4 8/04/05 5:58p Andriyn +// Legacy over LegacyFree +// +// 2 6/01/05 5:22p Olegi +// Debug message shortened. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbKbd.c +// +// Description: USB keyboard driver SMI routines +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "USBKBD.H" +#include <UsbDevDriverElinks.h> //(EIP90887+) + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gKeyRepeatStatus; +extern UINT16 gKbcSetTypeRate11CharsSec; +extern UINT16 gKbcSetTypeDelay500MSec; +UINT8 gLastKeyCodeArray[8]={0,0,0,0,0,0,0,0}; + +//---------------------------------------------------------------------------- +// Typematic rate delay table will have counts to generate key repeat delays. +// Since the periodic interrupt is set to 8msec the following repeat times +// will generate necessary delay. +// First three numbers are meant to define the frequency of the repeated keys; +// four other numbers are used to define the amount of delay between the first +// keypress-and-hold til the key actually starts repeating; the appropriate values +// of this table are selected using the equates defined in UsbKbd.h +// +UINT8 aTypematicRateDelayTable[] = {2, 4, 8, 16, 32, 48, 64, 96}; + +// +// The global data variables are stored in USB_GLOBAL_DATA structure and can be accessed through +// gUsbData->xxx +// + +LEGACY_USB_KEYBOARD mLegacyKeyboard; + +extern UINT8 IsKbcAccessBlocked; //(EIP29733+) +extern VOID USBKB_LEDOn(); + +BOOLEAN gEfiMakeCodeGenerated=FALSE; +BOOLEAN gLegacyMakeCodeGenerated=FALSE; + +extern EFI_EMUL6064KBDINPUT_PROTOCOL* gKbdInput ; + +UINT8 UsbControlTransfer(HC_STRUC*, DEV_INFO*, DEV_REQ, UINT16, VOID*); + +UINT32 ExtractInputReportData (UINT8 *Report, UINT16 Offset, UINT16 Size); + //(EIP90887+)> +typedef BOOLEAN (KBD_BUFFER_CHECK_FUNCTIONS)( + DEV_INFO* DevInfo, + UINT8 *Buffer + ); +extern KBD_BUFFER_CHECK_FUNCTIONS KBD_BUFFER_CHECK_ELINK_LIST EndOfInitList; +KBD_BUFFER_CHECK_FUNCTIONS* KbdBufferCheckFunctionsList[] = {KBD_BUFFER_CHECK_ELINK_LIST NULL}; + //<(EIP90887+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBDInitialize (VOID) +// +// Description: This function returns fills the host controller driver +// routine pointers in the structure provided +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKBDInitialize (VOID) +{ + UINT8 bTemp; + + // + // Initialize the typematic rate to 500 ms, 10.9 Char/Sec and auto repeat flag + // to disabled + // + gUsbData->wUSBKBC_StatusFlag |= ((gKbcSetTypeRate11CharsSec << KBC_TYPE_RATE_BIT_SHIFT) + + (gKbcSetTypeDelay500MSec << KBC_TYPE_DELAY_BIT_SHIFT)); + + USB_DEBUG (DEBUG_LEVEL_5, "USBKBDInitialize: CodeBufferStart : %lx\n", gUsbData->aKBCScanCodeBufferStart); + + // + // Initialize the scanner buffer + // + gUsbData->fpKBCScanCodeBufferPtr = gUsbData->aKBCScanCodeBufferStart; + gUsbData->bLastUSBKeyCode = 0; + + // + // Initialize the character buffer + // + gUsbData->fpKBCCharacterBufferHead = gUsbData->aKBCCharacterBufferStart; + gUsbData->fpKBCCharacterBufferTail = gUsbData->aKBCCharacterBufferStart; + + // + // Initialize the USB Data buffer + // + gUsbData->aKBCUsbDataBufferHead = gUsbData->aKBCUsbDataBufferStart; + gUsbData->aKBCUsbDataBufferTail = gUsbData->aKBCUsbDataBufferStart; + + gUsbData->fpKeyRepeatDevInfo=NULL; + + // + // Set scan code set to 2 in the scanner flag + // + gUsbData->wUSBKBC_StatusFlag |= KBC_SET_SCAN_CODE_SET2; + + gUsbData->bUSBKBShiftKeyStatus = 0; + + // + // Get the keyboard controller command byte (CCB) and store it locally + // + //USBKBC_GetAndStoreCCB(); + gUsbData->bCCB = 0x40; + + for (bTemp=0; bTemp<6; bTemp++) mLegacyKeyboard.KeyCodeStorage[bTemp] = 0; + mLegacyKeyboard.KeyToRepeat = 0; + + return; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBKBDConfigureKeyboard +// +// Description: This routine checks an interface descriptor of the USB device +// detected to see if it describes a HID/Boot/Keyboard device. +// If the device matches the above criteria, then the device is +// configured and initialized +// +// Input: fpHCStruc HCStruc pointer +// fpDevInfo Device information structure pointer +// fpDesc Pointer to the descriptor structure +// wStart Offset within interface descriptor +// supported by the device +// wEnd End offset of the device descriptor +// +// Output: FPDEV_INFO New device info structure, 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + //(EIP84455+)> +DEV_INFO* +USBKBDConfigureDevice ( + DEV_INFO* DevInfo +) +{ + UINT16 Index; + + DevInfo->fpPollTDPtr = 0; + Index = USBKBDFindUSBKBDeviceTableEntry(DevInfo); + if (Index == 0xFFFF) { + Index = USBKBDFindUSBKBDeviceTableEntry(NULL); + } + if (Index != 0xFFFF) { + gUsbData->aUSBKBDeviceTable[Index] = DevInfo; + if (!(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI)) { + if (BOOT_PROTOCOL_SUPPORT || (DevInfo->HidReport.Flag & HID_REPORT_FLAG_LED_FLAG) || + (DevInfo->wIncompatFlags & USB_INCMPT_HID_BOOT_PROTOCOL_ONLY)) { + USBKB_LEDOn(); + } + } + } else { + return 0; + } + + return DevInfo; +} + //<(EIP84455+) +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBDFindUSBKBDeviceTableEntry +// +// Description: This routine searches for the HID table entry which matches +// the provided device info structure +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// +// Output: offset of the HID table for the requested fpDevinfo +// 0xFFFF -on error +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBKBDFindUSBKBDeviceTableEntry(DEV_INFO* fpDevinfo) +{ + UINT16 wCount ; + + for (wCount = 0; wCount < USB_DEV_HID_COUNT; wCount++) + { + if(gUsbData->aUSBKBDeviceTable[wCount] == fpDevinfo ) + return wCount; + } + USB_DEBUG (DEBUG_LEVEL_3, "No Free KBD DevInfo Entry\n"); + return 0xFFFF; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBDDisconnectDevice +// +// Description: This routine disconnects the keyboard by freeing +// the USB keyboard device table entry +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// +// Output: USB_SUCCESS/USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKBDDisconnectDevice ( + DEV_INFO* DevInfo +) +{ + UINT16 Index; + //(EIP93637+)> + UINT8 ScanCodeCount = (UINT8)(gUsbData->fpKBCScanCodeBufferPtr - + (UINT8*)gUsbData->aKBCScanCodeBufferStart); //(EIP102150+) + UINT8 i = 0; + UINT8 CurrentDeviceId; + UINT8 Key; + + USB_KB_BUFFER *KeyboardBuffer; + KeyboardBuffer = gUsbData->EfiKeyboardBuffer; + + Index = USBKBDFindUSBKBDeviceTableEntry(DevInfo); + if (Index == 0xFFFF) { + USBLogError(USB_ERR_KBCONNECT_FAILED); + return USB_ERROR; + } else { + CurrentDeviceId = (UINT8)(1 << ((DevInfo->bDeviceAddress) -1)); + while ((i < ScanCodeCount) && (ScanCodeCount != 0)) { + if (gUsbData->aKBCDeviceIDBufferStart[i] & CurrentDeviceId) { + gUsbData->aKBCDeviceIDBufferStart[i] &= ~CurrentDeviceId; + if (gUsbData->aKBCDeviceIDBufferStart[i] == 0) { + Key = gUsbData->aKBCScanCodeBufferStart[i]; + if ((Key == HID_UP_KEYBOARD_RIGHT_SHIFT) || + (Key == HID_UP_KEYBOARD_LEFT_SHIFT)) { + gUsbData->bUSBKBShiftKeyStatus &= ~(KB_RSHIFT_KEY_BIT_MASK+KB_LSHIFT_KEY_BIT_MASK); + } + USBKB_DiscardCharacter(&gUsbData->aKBCShiftKeyStatusBufferStart[i]); + gUsbData->fpKBCScanCodeBufferPtr--; + ScanCodeCount--; + continue; + } + } + i++; + } + if (gUsbData->fpKeyRepeatDevInfo == DevInfo) { + for (i = 0; i < 8; i++) { + *(gLastKeyCodeArray + i) = 0; + } + if(KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode == gUsbData->RepeatKey) + { + gUsbData->RepeatKey = 0; + KeyboardBuffer->bHead = KeyboardBuffer->bTail; + } + } + gUsbData->aUSBKBDeviceTable[Index] = 0; + return USB_SUCCESS; + } + //<(EIP93637+) +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_CheckCharacterBufferFull +// +// Description: This routine checks whether the character buffer can hold +// 'N'+1 character +// +// Input: bCount Space needed in the buffer (in characters) +// +// Output: 0 If buffer is full +// <> 0 If buffer is not full +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 +USBKBC_CheckUsbDataBufferFull (UINT8 bCount) +{ + UINT8 *dHead, *dTail, *dStart, *dEnd; + + dHead = gUsbData->aKBCUsbDataBufferHead; + dTail = gUsbData->aKBCUsbDataBufferTail; + dStart = gUsbData->aKBCUsbDataBufferStart; + dEnd = dStart + sizeof (gUsbData->aKBCUsbDataBufferStart); + ++bCount; + do { + ++dHead; + if(dHead == dEnd) dHead = dStart; + if(dHead == dTail) return 0; + --bCount; + } while(bCount); + + return 0xFF; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBC_SendToCharacterBuffer +// +// Description: This routine puts a character into the character buffer. +// Character buffer pointers are also updated +// +// Input: Nothing +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void +USBKBC_SendToUsbDataBuffer (UINT8 *fpSrc) +{ + UINT8 *fPointer; + UINT8 *fPtrEnd; + UINT8 i; + + fPtrEnd = ( gUsbData->aKBCUsbDataBufferStart + + sizeof (gUsbData->aKBCUsbDataBufferStart)); + + fPointer = gUsbData->aKBCUsbDataBufferHead; + + for (i = 0; i < 8; i++) { + *fPointer++ = *fpSrc++; + } + + if(fPointer == fPtrEnd) { + fPointer = gUsbData->aKBCUsbDataBufferStart; + } + + gUsbData->aKBCUsbDataBufferHead = fPointer; + + return; + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBDProcessKeyboardData +// +// Description: This routine is called with USB keyboard report data. This +// routine handles the translation of USB keyboard data +// into PS/2 keyboard data, and makes the PS/2 data available +// to software using ports 60/64h by communicating with +// PS/2 keyboard controller. +// +// Input: fpHCStruc Pointer to HCStruc +// fpDevInfo Pointer to device information structure +// fpTD Pointer to the polling TD +// fpBuffer Pointer to the data buffer +// +// Output: Nothing +// +// Notes: TD's control status field has the packet length (0 based). +// It could be one of three values 0,1 or 7 indicating packet +// lengths of 1, 2 & 8 repectively. +// The format of 8 byte data packet is as follow: +// Byte Description +// ----------------------------------------------------------- +// 0 Modifier key (like shift, cntr & LED status) +// 1 Reserved +// 2 Keycode of 1st key pressed +// 3 Keycode of 2nd key pressed +// 4 Keycode of 3rd key pressed +// 5 Keycode of 4th key pressed +// 6 Keycode of 5th key pressed +// 7 Keycode of 6th key pressed +// ----------------------------------------------------------- +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBKBDProcessKeyboardData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UINT8 Count = 8; + HID_REPORT_FIELD *Field = NULL; + UINT8 FieldIndex = 0; + UINT32 BitOffset = 0; + BOOLEAN ValidData = FALSE; + UINT8 Data = 0; + UINT16 Index = 0; + UINT8 UsageBuffer[32] = {0}; + UINT16 UsageIndex = 0; + UINT8 i; + UINTN OemHookIndex; + + if (DevInfo->HidReport.Flag & HID_REPORT_FLAG_REPORT_PROTOCOL) { + for (FieldIndex = 0; FieldIndex < DevInfo->HidReport.FieldCount; FieldIndex++) { + Field = DevInfo->HidReport.Fields[FieldIndex]; + + // Check if the field is input report. + if (!(Field->Flag & HID_REPORT_FIELD_FLAG_INPUT)) { + continue; + } + + //if report id exist, check first byte + if ((Field->ReportId != 0) && (Field->ReportId != Buffer[0])) { + continue; + } + + // Check if the field is contant. + if (Field->Flag & HID_REPORT_FIELD_FLAG_CONSTANT) { + BitOffset += Field->ReportCount * Field->ReportSize; + continue; + } + + //find start offset + if (Field->UsagePage == HID_UP_KEYBOARD) { + ValidData = TRUE; + + // If Report ID tags are used in the report descriptor, the first byte is + // report id, we offset 8 bits to get data. + if (Field->ReportId != 0) { + BitOffset += 8; + } + + for (Index = 0; Index < Field->ReportCount; Index++) { + Data = ExtractInputReportData(Buffer, + BitOffset + (Index * Field->ReportSize), Field->ReportSize); + + if ((Data < Field->LogicalMin) || (Data > Field->LogicalMax)) { + continue; + } + + Data = Field->Flag & HID_REPORT_FIELD_FLAG_VARIABLE ? + (Data != 0 ? Field->Usages[Index] : Data) : + Field->Usages[Data - Field->LogicalMin]; + + if ((Data != 0) && (UsageIndex < COUNTOF(UsageBuffer))) { + UsageBuffer[UsageIndex++] = Data; + } + } + if (Field->ReportId != 0) { + BitOffset -= 8; + } + } + BitOffset += Field->ReportCount * Field->ReportSize; + } + + if (ValidData == FALSE) { + return USB_SUCCESS; + } + + MemSet(Buffer, 8, 0); + + // Translate the report data to boot protocol data. + + // 0 Modifier key (like shift, cntr & LED status) + // 1 Reserved + // 2 Keycode of 1st key pressed + // 3 Keycode of 2nd key pressed + // 4 Keycode of 3rd key pressed + // 5 Keycode of 4th key pressed + // 6 Keycode of 5th key pressed + // 7 Keycode of 6th key pressed + + for (Index = 0, i = 0; Index < UsageIndex; Index++) { + if (UsageBuffer[Index] >= HID_UP_KEYBOARD_LEFT_CTRL && + UsageBuffer[Index] <= HID_UP_KEYBOARD_RIGHT_GUI) { + Buffer[0] |= 1 << (UsageBuffer[Index] - HID_UP_KEYBOARD_LEFT_CTRL); + } else { + if (i < 6) { + Buffer[i + 2] = UsageBuffer[Index]; + i++; + } + } + } + } + //(EIP90887+)> + // Call all the OEM hooks that wants to check KBD buffer + for (OemHookIndex = 0; KbdBufferCheckFunctionsList[OemHookIndex]; OemHookIndex++) { + if (KbdBufferCheckFunctionsList[OemHookIndex](DevInfo, Buffer)) { + return USB_SUCCESS; + } + } + //<(EIP90887+) + //Is KBC access allowed? + if (IsKbcAccessBlocked) { + if (!(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) || !gEfiMakeCodeGenerated) { + return USB_SUCCESS; + } + MemSet(Buffer, 8, 0); + } + + // + // Save the device info pointer for later use + // + gUsbData->fpKeyRepeatDevInfo = DevInfo; + + for (i = 0, Count = 8; i < 8; i++, Count--) { + if (Buffer[i]) { + break; + } + } + + if ((gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI)) { + if (Count==0) { + gEfiMakeCodeGenerated=FALSE; + } else { + gEfiMakeCodeGenerated=TRUE; + gLegacyMakeCodeGenerated=FALSE; + } + } else { + if (Count==0) { + gLegacyMakeCodeGenerated=FALSE; + } else { + gLegacyMakeCodeGenerated=TRUE; + gEfiMakeCodeGenerated=FALSE; + } + } + + // + // checks for new key stroke. + // if no new key got, return immediately. + // + for (i = 0; i < 8; i ++) { + if (Buffer[i] != gLastKeyCodeArray[i]) { + break; + } + } + +#if USB_HID_KEYREPEAT_USE_SETIDLE == 1 + if ((i == 8) && gKeyRepeatStatus) { + USBKBDPeriodicInterruptHandler(HcStruc); + return USB_SUCCESS; + } +#endif + + // + // Update LastKeycodeArray[] buffer in the + // Usb Keyboard Device data structure. + // + for (i = 0; i < 8; i ++) { + gLastKeyCodeArray[i] = Buffer[i]; + } + + if ((!(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) || gLegacyMakeCodeGenerated) &&(!gEfiMakeCodeGenerated)) + { + if (Count==0) { + gLegacyMakeCodeGenerated=FALSE; + } + UsbScanner(DevInfo, Buffer); + } else { + if(Count==0) { + gEfiMakeCodeGenerated=FALSE; + } + + if(USBKBC_CheckUsbDataBufferFull(8) == 0) { + return EFI_SUCCESS; + } + + USBKBC_SendToUsbDataBuffer(Buffer); + + // + // Reload the typematic rate value + // + gUsbData->wRepeatRate = aTypematicRateDelayTable[ + (gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_DELAY_BIT_MASK) >> + KBC_TYPE_DELAY_BIT_SHIFT]; + gUsbData->wRepeatCounter = 0; + + // + // Enable periodic interrupt to catch the repeat key + // + if (Count==0) { + USBKeyRepeat(NULL, 1); // Disable Key repeat + } else { + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBDPeriodicInterruptHandler +// +// Description: This routine is called every 16ms and is used to send +// the characters read from USB keyboard to the keyboard +// controller for legacy operation. Also this function updates +// the keyboard LED status +// +// Input: fpHCStruc Pointer to the HCStruc structure +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKBDPeriodicInterruptHandler (HC_STRUC* fpHcStruc) +{ + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + //(EIP83888+)> + if (!(*(UINT32*)gLastKeyCodeArray || + *(UINT32*)(gLastKeyCodeArray + 4))) { //(EIP93637) + //<(EIP83888+) + // + // Keyboard data is zero, the key is released - stop repeating the key + // + USBKeyRepeat(NULL, 1); // Disable Key repeat + return; + } else { + // + // Check whether keyboard buffer is not empty; + // Execute Efi callback function if repeat counter is expired + // + gUsbData->wRepeatCounter++; + if (gUsbData->wRepeatCounter >= gUsbData->wRepeatRate) { + // + // Repeat rate is reached. + // Reload repeat delay counter with keyrepeat delay value; original + // type delay value will be restored in ProcessKeyboardData + // + gUsbData->wRepeatRate = aTypematicRateDelayTable[ + (gUsbData->wUSBKBC_StatusFlag & KBC_TYPE_RATE_BIT_MASK) >> + KBC_TYPE_RATE_BIT_SHIFT]; + gUsbData->wRepeatCounter = 0; + + USBKBKeyrepeatCallback(); + } + // + // Reenable periodic interrupt handler + // + USBKeyRepeat(NULL, 2); // Enable Key repeat + } + } else { // Not under EFI + LegacyAutoRepeat(fpHcStruc); + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbScanner +// +// Description: This routine is executed to convert USB scan codes into PS/2 +// make/bread codes. +// +// Input: fpDevInfo - USB keyboard device +// fpBuffer - USB scan codes data buffer +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UsbScanner( + DEV_INFO *fpDevInfo, + UINT8 *fpBuffer +) +{ + if(gUsbData->kbc_support || ((gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_ON) + && (gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_IRQ_SUPPORT))) { + USBKBC_GetAndStoreCCB(); + USBKB_Scanner (fpDevInfo, fpBuffer); + USBKB_UpdateLEDState (0xFF); + }else { + USBKB_Int9(fpBuffer); + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: LegacyAutoRepeat +// +// Description: This routine is called periodically based on 8ms TD and used +// to implement the key repeat. +// +// Input: Hc Pointer to the HCStruc structure +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +LegacyAutoRepeat( + HC_STRUC *Hc +) +{ + if(gUsbData->kbc_support || ((gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_ON) + && (gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_IRQ_SUPPORT))) { + SysKbcAutoRepeat(Hc); + } else { + SysNoKbcAutoRepeat(); + } +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBKBKeyrepeatCallback +// +// Description: This routine is called every time the key repeat is requested +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBKBKeyrepeatCallback() +{ + USB_KEY UsbKey; + USB_KB_BUFFER *KeyboardBuffer; + + if(!gUsbData->RepeatKey) return; // Do nothing when there is no repeat key. + + KeyboardBuffer = gUsbData->EfiKeyboardBuffer; + + // + // If keyboard buffer is full, throw the first key out of the keyboard buffer. + // + if (((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)) == KeyboardBuffer->bHead) { + + UsbKey.KeyCode = KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode; + UsbKey.Down = KeyboardBuffer->buffer[KeyboardBuffer->bHead].Down; + + // + // adjust the head pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bHead = (UINT8)((KeyboardBuffer->bHead + 1) % (MAX_KEY_ALLOWED + 1)); + } + + KeyboardBuffer->buffer[KeyboardBuffer->bTail].KeyCode = gUsbData->RepeatKey; + KeyboardBuffer->buffer[KeyboardBuffer->bTail].Down = 1; + + // + // adjust the tail pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bTail = (UINT8)((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)); + +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbKbdSetLed +// +// Description: This routine set the USB keyboard LED status. +// +// Input: DevInfo Pointer to device information structure +// LedStatus LED status +// +// Output: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbKbdSetLed ( + DEV_INFO *DevInfo, + UINT8 LedStatus +) +{ + HC_STRUC *HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + DEV_REQ DevReq = {0}; + UINT8 Status; + UINT8 ReportId = 0; + UINT16 ReportLen; + UINT8 *ReportData = NULL; + UINT8 Index; + + if ((DevInfo->HidReport.Flag & HID_REPORT_FLAG_REPORT_PROTOCOL) && + !(DevInfo->HidReport.Flag & HID_REPORT_FLAG_LED_FLAG)) { + return USB_ERROR; + } + + ReportData = USB_MemAlloc(GET_MEM_BLK_COUNT(4)); + if (ReportData == NULL) return USB_ERROR; + + ReportLen = 1; + ReportData[0] = LedStatus & 0x7; + + if (DevInfo->HidReport.Flag & HID_REPORT_FLAG_REPORT_PROTOCOL) { + if (DevInfo->HidReport.Fields == NULL) { + USB_MemFree(ReportData, GET_MEM_BLK_COUNT(4)); + return USB_ERROR; + } + for (Index = 0; Index < DevInfo->HidReport.FieldCount; Index++) { + //find start offset + if ((DevInfo->HidReport.Fields[Index]->UsagePage == 0x8) && + (DevInfo->HidReport.Fields[Index]->ReportId != 0) && + (DevInfo->HidReport.Fields[Index]->Usages[0] == 1)) { + ReportId = DevInfo->HidReport.Fields[Index]->ReportId; + ReportData[1] = ReportData[0]; + ReportData[0] = ReportId; + ReportLen++; + } + } + } + if (DevInfo->IntOutEndpoint == 0) { + DevReq.wRequestType = HID_RQ_SET_REPORT; + DevReq.wValue = (0x02 << 8) | ReportId; // Output + DevReq.wIndex = DevInfo->bInterfaceNum; + DevReq.wDataLength = ReportLen; + + Status = UsbControlTransfer(HcStruc, DevInfo, DevReq, USB_KBD_SET_LED_TIMEOUT_MS, ReportData); + } else { + Status = UsbInterruptTransfer(HcStruc, DevInfo, DevInfo->IntOutEndpoint, + DevInfo->IntOutMaxPkt, ReportData, ReportLen, USB_KBD_SET_LED_TIMEOUT_MS); + } + + USB_MemFree(ReportData, GET_MEM_BLK_COUNT(4)); + return Status; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbkbd.h b/Core/EM/usb/rt/usbkbd.h new file mode 100644 index 0000000..674a2f8 --- /dev/null +++ b/Core/EM/usb/rt/usbkbd.h @@ -0,0 +1,436 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbkbd.h 20 3/18/16 12:03a Wilsonlee $ +// +// $Revision: 20 $ +// +// $Date: 3/18/16 12:03a $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbkbd.h $ +// +// 20 3/18/16 12:03a Wilsonlee +// [TAG] EIP257506 +// [Category] Improvement +// [Description] Add USB_KEYREPEAT_INTERVAL token to change the key +// repeat interval. +// [Files] usb.sdl, xhci.h, usbkbd.h, uhci.c, ohci.c, ehci.c +// +// 19 3/02/16 9:42p 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 +// +// 18 2/24/15 5:50a Wilsonlee +// [TAG] EIP149716 +// [Category] Improvement +// [Description] Error Handling in USB mouse data. +// [Files] usbms.c, usbkbd.h, syskbc.c, xhci.c +// +// 17 5/06/14 5:16a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 16 2/26/14 1:56a 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 +// +// 15 12/30/13 3:42a Wilsonlee +// [TAG] EIP148411 +// [Category] Improvement +// [Description] Check if CCB_MOUSE_INTRPT is set before we sent mouse +// data. +// [Files] usbkbd.h, syskbc.c +// +// 14 7/04/13 5:49a Roberthsu +// [[TAG] EIP127014 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Mouse drifting not smooth +// [RootCause] Bbecause Efi simple point protocol RelativeMovementX +// type is INT32. +// [Solution] Transfer data type to INT32. +// [Files] usbdef.h,usbhid.c,usbms.c,usbkbd.h +// +// 13 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 12 5/22/12 10:57a Jittenkumarp +// [TAG] EIP87959 +// [Category] New Feature +// [Description] Proper Error path in the USB driver, incase KBC Input +// buffer is full +// [Files] usbkbd.h, syskbc.c +// +// 11 5/03/12 6:28a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 10 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 9 9/16/09 11:10a Olegi +// +// 8 9/15/09 12:21p Olegi +// Added KEY_REPEAT_LOGIC functionality. EIP#25841 +// +// 7 9/05/08 4:22p Olegi +// +// 6 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 5 3/20/07 12:21p Olegi +// +// 3 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 2 8/25/05 7:19p Andriyn +// USB Keyboard and mouse to use EMUL 60/64 for passing data to KBC. +// Fall-back when EMUL 60/64 is not present +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbKbd.h +// +// Description: AMI USB keyboard support header +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +// Avoid including multiple instance of this file +#ifndef __USBKBD_H +#define __USBKBD_H + +#include "token.h" + +// Make/break code equates + +#define KBC_AUTO_REPEAT_BIT_MASK (0x01 << 9) +#define KBC_PASSWORD_FLAG_BIT_MASK (0x01 << 10) +#define KBC_SCANNER_STATUS_BIT_MASK (0x01 << 11) +#define KBC_PORT6064_TRAP_BIT_MASK (0x01 << 12) +#define KBC_MK_BRK_CODE_BIT_MASK (0x01 << 13) + +#define USB_GEN_MAKE_CODE 0x020 +#define USB_GEN_BREAK_CODE 0x030 + + +// Equates used by keyboard controller scanner code +#define LEFT_ALT 0x011 // Left-ALT scan code (set 2) +#define LEFT_CTRL 0x014 // Left-CTRL scan code (set 2) +#define LEFT_SHIFT 0x012 // Left-SHIFT scan code (set 2) +#define RIGHT_SHIFT 0x059 // Right-SHIFT scan code (set 2) + +// Extended status flag bit definitions +#define KBCEXT_LED_UPDATE_IN_PROGRESS_BIT BIT0 + +// Scan code for base case only +#define RIGHT_ALT 0x011+0x80 // Local code id (scan-2) +#define RIGHT_CTRL 0x014+0x80 // Local code id (scan-2) +#define LEFT_MS_KEY 0x01F+0x80 // Microsoft left key +#define RIGHT_MS_KEY 0x027+0x80 // Microsoft right key +#define APP_MS_KEY 0x02F+0x80 // Microsoft application key +#define RIGHT_ENTER 0x05A+0x80 // Local code id (scan-2) + +// Equates for KB shift key status information +#define KB_FUNCTION_BIT 7 // Function key LED bit +#define KB_FUNCTION_BIT_MASK (1 << KB_FUNCTION_BIT) +#define KB_SCROLL_LOCK_BIT 6 // Scroll key LED bit +#define KB_SCROLL_LOCK_BIT_MASK (1 << KB_SCROLL_LOCK_BIT) +#define KB_CAPS_LOCK_BIT 5 // CAPS lock key LED bit +#define KB_CAPS_LOCK_BIT_MASK (1 << KB_CAPS_LOCK_BIT) +#define KB_NUM_LOCK_BIT 4 // NUM lock key LED bit +#define KB_NUM_LOCK_BIT_MASK (1 << KB_NUM_LOCK_BIT ) +#define KB_ALT_KEY_BIT 3 // ALT key status bit +#define KB_ALT_KEY_BIT_MASK (1 << KB_ALT_KEY_BIT ) +#define KB_CTRL_KEY_BIT 2 // CTRL key status bit +#define KB_CTRL_KEY_BIT_MASK (1 << KB_CTRL_KEY_BIT ) +#define KB_LSHIFT_KEY_BIT 1 // LSHIFT key status bit +#define KB_LSHIFT_KEY_BIT_MASK (1 << KB_LSHIFT_KEY_BIT) +#define KB_RSHIFT_KEY_BIT 0 // RSHIFT key status bit +#define KB_RSHIFT_KEY_BIT_MASK (1 << KB_RSHIFT_KEY_BIT) + +#define KBC_SCAN_CODE_SET_BIT_SHIFT 0 +#define KBC_SET_SCAN_CODE_SET2 (0x02 << KBC_SCAN_CODE_SET_BIT_SHIFT) +#define KBC_SCAN_CODE_SET_BIT_MASK (0x03 << KBC_SCAN_CODE_SET_BIT_SHIFT) + +#if USB_KEYREPEAT_INTERVAL +#define REPEAT_INTERVAL 16 +#define KBC_TYPE_RATE_BIT_SHIFT 1 +#define KBC_TYPE_RATE_BIT_MASK (0x05 << KBC_TYPE_RATE_BIT_SHIFT) + +#define KBC_TYPE_DELAY_BIT_SHIFT 4 +#define KBC_TYPE_DELAY_BIT_MASK (0x05 << KBC_TYPE_DELAY_BIT_SHIFT) + +#else +#define REPEAT_INTERVAL 8 +#define KBC_TYPE_RATE_BIT_SHIFT 2 +#define KBC_TYPE_RATE_BIT_MASK (0x07 << KBC_TYPE_RATE_BIT_SHIFT) + +#define KBC_TYPE_DELAY_BIT_SHIFT 6 +#define KBC_TYPE_DELAY_BIT_MASK (0x07 << KBC_TYPE_DELAY_BIT_SHIFT) +#endif + + +// Scan code common to all the cases (base, control, shift and alt cases) +#define PRINT_SCREEN (0x07C + 0x80) // Local code id (scan-2) + +// Scan code common to base and control cases +#define PAUSE_KEY (0x07E + 0x80) // Local code id (scan-2) + +// Scan code common to base and shift cases +#define SLASH_KEY (0x4A + 0x80) // Local code id (scan-2) + +// Scan code common to base, shift and num lock cases +#define END_KEY (0x069 + 0x80) // Local code id (scan-2) +#define LEFT_KEY (0x06B + 0x80) // Local code id (scan-2) +#define HOME_KEY (0x06C + 0x80) // Local code id (scan-2) +#define INSERT_KEY (0x070 + 0x80) // Local code id (scan-2) +#define DEL_KEY (0x071 + 0x80) // Local code id (scan-2) +#define DOWN_KEY (0x072 + 0x80) // Local code id (scan-2) +#define RIGHT_KEY (0x074 + 0x80) // Local code id (scan-2) +#define UP_KEY (0x075 + 0x80) // Local code id (scan-2) +#define PAGE_DOWN_KEY (0x07A + 0x80) // Local code id (scan-2) +#define PAGE_UP_KEY (0x07D + 0x80) // Local code id (scan-2) + +#define CCB_TRANSLATE_SCAN_CODE_BIT_MASK BIT6 +#define KBC_COMMAND_REG 0x64 +#define KBC_SUBCOMMAND_REG 0x60 +#define KBC_STATUS_REG 0x64 +#define KBC_DATA_REG 0x60 + +#define MOUSE_ENABLED_BIT 7 +#define MOUSE_ENABLED_BIT_MASK (1 << MOUSE_ENABLED_BIT) +#define MOUSE_DATA_READY_BIT 6 +#define MOUSE_DATA_READY_BIT_MASK (1 << MOUSE_DATA_READY_BIT) +#define MOUSE_DATA_FROM_USB_BIT 5 +#define MOUSE_DATA_FROM_USB_BIT_MASK (1 << MOUSE_DATA_FROM_USB_BIT) + // Mouse data size = 1:4byte data, 0:3byte data +#define MOUSE_4BYTE_DATA_BIT 4 +#define MOUSE_4BYTE_DATA_BIT_MASK (1 << MOUSE_4BYTE_DATA_BIT) + +#define KBC_DATA_TX_ORDER_BIT_MASK 0x03 << 14 +#define KBC_DATA_TX_ORDER_INC_VALUE 0x01 << 14 +#define KBC_DATA_TX_ORDER_KB_FIRST 0x02 << 14 + +#define CCB_KEYBOARD_INTRPT BIT0 +#define CCB_MOUSE_INTRPT BIT1 +#define CCB_KEYBOARD_DISABLED BIT4 +#define CCB_MOUSE_DISABLED BIT5 +#define CCB_TRANSLATE_SCAN_CODE_BIT_MASK BIT6 + +#ifndef USB_KBD_SET_LED_TIMEOUT_MS +#define USB_KBD_SET_LED_TIMEOUT_MS 100 +#endif + +UINT8 ByteReadIO(UINT16); +void ByteWriteIO(UINT16, UINT8); + +UINT8 USBMouse_GetFromMouseBuffer (); +void USBKeyRepeat(HC_STRUC*, UINT8); +UINT8 USBKBC_GetFromCharacterBuffer(); + +UINT8 USBKB_ConvertSet2CodeToSet1Code(UINT8); +void USBKBC_SendToCharacterBuffer(UINT8); +UINT8 USBTrap_GetCurrentScanCodeSetNumber(); +UINT8 USBKB_ConvertScanCodeBetweenCodeSet(UINT8, UINT8*); +//void SYSKBC_UpdateLEDState(UINT8); +UINT8 KBC_WaitForInputBufferToBeFree( ); +UINT8 KBC_WaitForOutputBufferToBeFilled( ); +void USBKB_GenerateType1MakeCode( ); +void USBKB_GenerateType1BreakCode( ); +void USBKB_GenerateType2MakeCode( ); +void USBKB_GenerateType2BreakCode( ); +UINT8 USBTrap_GetOverrunCode( ); +void USBKB_DiscardCharacter(UINT8*); +UINT16 USBKB_CheckForExtendedKey(UINT8); +UINT16 USBKB_CheckForNumericKeyPadKey(UINT8); +UINT8 USBKBC_CheckCharacterBufferFull(UINT8); +void USBKB_UpdateLEDState(UINT8); +UINT8 USBKB_ConvertUSBKeyCodeToScanCodeSet2 (UINT8); +UINT16 USBKB_CheckModifierKeyPress (UINT8); +UINT8 KBC_WriteCommandByte(UINT8); +UINT8 KBC_ReadDataByte(UINT8 *); +void KBC_WriteSubCommandByte(UINT8); +EFI_STATUS SYSKBC_SendKBCData(); + +extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); + +extern DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*,UINT8, HC_STRUC*); +extern UINT8 USBLogError(UINT16); +extern void USBKeyRepeat(HC_STRUC*, UINT8); +#if USB_DEV_MOUSE +extern UINT8 USBMSSendMouseData(); +extern void USBMSUpdateMouseInterface(); +#endif + +void USBKBDInitialize (void); +UINT8 USBKBDDisconnectDevice (DEV_INFO*); + +void USBKBC_GetAndStoreCCB(); +DEV_INFO* USBKBDConfigureDevice (DEV_INFO*); //(EIP84455) +UINT16 USBKBDFindUSBKBDeviceTableEntry(DEV_INFO*); +UINT16 USBKBDConnectKeyboard(DEV_INFO*); +UINT8 USBKBDProcessKeyboardData ( HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 UsbKbdSetLed(DEV_INFO*, UINT8); + +void USBKB_GenerateScanCode ( UINT8, UINT8, UINT16 ); + +VOID UsbScanner(DEV_INFO*, UINT8*); +VOID USBKB_Scanner (DEV_INFO*, UINT8*); +VOID USBKB_Int9(UINT8*); + +VOID ProcessKeyCode(UINT8); + +VOID LegacyAutoRepeat(HC_STRUC*); +VOID SysKbcAutoRepeat(HC_STRUC*); +VOID SysNoKbcAutoRepeat(); +VOID USBKBKeyrepeatCallback(); +VOID USBKBDPeriodicInterruptHandler(HC_STRUC*); + //(EIP84455+)> +UINT8 USBHIDProcessData( HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 USBMSProcessMouseData ( HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 USBAbsProcessMouseData ( HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); + //<(EIP84455+) + +typedef struct _LEGACY_USB_KEY_MODIFIERS { + UINT8 ScrlLock : 1; + UINT8 NumLock : 1; + UINT8 CapsLock : 1; + UINT8 Ctrl : 1; + UINT8 Alt : 1; + UINT8 Shift : 1; +} LEGACY_USB_KEY_MODIFIERS; + +typedef struct _LEGACY_USB_KEYBOARD { + UINT8 KeyCodeStorage[6]; + LEGACY_USB_KEY_MODIFIERS KeyModifierState; + UINT8 KeyToRepeat; +} LEGACY_USB_KEYBOARD; + + //(EIP38434+)> +typedef struct { + union { + UINT8 Modifier; + struct { + UINT8 KB_RSHIFT : 1;// RSHIFT key status bit + UINT8 KB_LSHIFT : 1;// LSHIFT key status bit + UINT8 KB_CTRL : 1;// CTRL key status bit + UINT8 KB_ALT : 1;// ALT key status bit + UINT8 KB_NUM_LOCK : 1;// NUM lock key LED bit + UINT8 KB_CAPS_LOCK : 1;// CAPS lock key LED bit + UINT8 KB_SCROLL_LOCK : 1;// Scroll key LED bit + UINT8 KB_FUNCTION : 1;// Function key LED bit + } Modify; + }; + UINT8 Reserved; + UINT8 Keycode[6]; +}USBKBD_DATA; + +// 0 Bit Description +// ------------------------------------------- +// 0 If set, button 1 is pressed +// 1 If set, button 2 is pressed +// 2 If set, button 3 is pressed +// 3-7 Reserved +// ------------------------------------------- +// 1 X displacement value +// 2 Y displacement value +typedef struct { + union { + UINT8 ButtonByte; + struct { + UINT8 BUTTON1 : 1;// RSHIFT key status bit + UINT8 BUTTON2 : 1;// LSHIFT key status bit + UINT8 BUTTON3 : 1;// CTRL key status bit + UINT8 RESERVED : 5;// ALT key status bit + } BUTTON; + }; + UINT8 X; + UINT8 Y; + UINT8 Z; + UINT16 EfiX; //(EIP127014) + UINT16 EfiY; //(EIP127014) + UINT8 FillUsage; //(EIP127014) +}USBMS_DATA; + +typedef struct { + UINT8 Button; + UINT16 X; + UINT16 Y; + UINT16 Pressure; +}USBABS_DATA; + //<(EIP38434+) +#endif // __USB_H + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbmass.c b/Core/EM/usb/rt/usbmass.c new file mode 100644 index 0000000..0bdb683 --- /dev/null +++ b/Core/EM/usb/rt/usbmass.c @@ -0,0 +1,5506 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbmass.c 174 10/20/16 11:19p Wilsonlee $ +// +// $Revision: 174 $ +// +// $Date: 10/20/16 11:19p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbmass.c $ +// +// 174 10/20/16 11:19p Wilsonlee +// [TAG] EIP297268 +// [Category] Improvement +// [Description] Update Media information only in EfiUsbMass driver when +// Media is changed. +// [Files] usbmass.c, efiusbmass.c +// +// 173 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 +// +// 172 7/22/16 3:51a 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 +// +// 171 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 +// +// 170 4/08/16 3:54a Wilsonlee +// [TAG] EIP260113 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] We return success for writing data to to the +// write-protected device. +// [RootCause] Command Block Status is Command Failed when we send the +// write command to the write-protected device. +// [Solution] When CSW isn't Valid, we should issue a REQUEST SENSE +// command to receive the sense data describing what caused the error +// condition. +// [Files] usbmass.c +// +// 169 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 +// +// 168 2/14/16 9:46p Wilsonlee +// [TAG] EIP254924 +// [Category] Improvement +// [Description] Issue a Set TR Dequeue Pointer Command after issuing +// for a ClearFeature(ENDPOINT_HALT) request to device. +// [Files] usbmass.c, xhci.c +// +// 167 7/24/15 4:41a Wilsonlee +// [TAG] EIP226493 +// [Category] Improvement +// [Description] Block to process periodic list to prevent that we might +// send the wrong command sequences to the same device. +// [Files] usbmass.c, ehci.c, xhci.h, xhci.c, usbdef.h, uhcd.c +// +// 166 5/27/15 2:13a Wilsonlee +// [TAG] EIP220162 +// [Category] Improvement +// [Description] The read / write request contain the latest LBA that +// are valid. +// [Files] usbmass.c, efiusbmass.c +// +// 165 4/29/15 11:26p Wilsonlee +// [TAG] EIP215031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Transcend USB 3.0 HDD is disappeared in the setup menu by +// cold boot. +// [RootCause] We only can get SerialNumber string descriptor before +// setting configuration for this device, otherwise it is failed at +// getting this descriptor and inquiry command is also failed. +// [Solution] Retry inquiry command. +// [Files] usb.c, usbmass.c, efiusbmass.c, usbbus.c, usbdef.h +// +// 164 1/15/15 9:54p Wilsonlee +// [TAG] EIP198806 +// [Category] Improvement +// [Description] Send "RequestSense" command only if "TestUnitReady" +// command is failed. +// [Files] usbmass.c +// +// 163 12/24/14 1:08a Wilsonlee +// [TAG] EIP192517 +// [Category] Improvement +// [Description] SB Driver handles 0x100 NumHeads as a valid value. +// [Files] usbmass.c, usbdef.h, UsbInt13.c, UsbInt13.h, UI13.bin, +// Bfiusb.equ, Bfiusb.asm +// +// 162 11/30/14 10:30p Wilsonlee +// [TAG] EIP193829 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Ghost on multiple USB dvd rom span (Legacy Dos )fails if +// boot disk is smaller than second disk. +// [RootCause] RWVCommand gets one byte data after we change Media, but +// data isn't correct. +// [Solution] Check if data length processed is correct. +// [Files] usbmass.c +// +// 161 11/24/14 12:56a Wilsonlee +// [TAG] EIP192326 +// [Category] Improvement +// [Description] Check that division by zero exception doesn't occur. +// [Files] usbmass.c +// +// 160 11/23/14 10:53p Wilsonlee +// [TAG] EIP186754 +// [Category] Improvement +// [Description] The minimum of sector should be 1. +// [Files] usbmass.c +// +// 159 11/23/14 10:36p Wilsonlee +// [TAG] EIP188492 +// [Category] Improvement +// [Description] Create a token to keep usb mass storage devices are +// RemovableMedia. +// [Files] usbmass.c, usb.sdl +// +// 158 9/02/14 4:09a Wilsonlee +// [TAG] EIP183522 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Heads, Sectors and Cylinders aren't correct if usb mass +// storages report media change. +// [RootCause] We update CHS from read capacity parameters if media +// change. +// [Solution] We already update CHS from boot record and legacy boot +// doesn't support dynamic media insertion, we should not update it from +// read capacity parameters. +// [Files] usbmass.c +// +// 157 8/07/14 5:35a Wilsonlee +// [TAG] EIP180686 +// [Category] Improvement +// [Description] Right shifts 64bit values that should be using Shr64(). +// [Files] usbmass.c +// +// 156 7/04/14 5:23a Wilsonlee +// [TAG] EIP175485 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB key can't be save during secure boot key. +// [RootCause] The usb key, MSI 8G Team, has two luns. One is CD-ROM, it +// always reports there is no media until we send "Get_Configuration" +// command to it, then it causes the other lun will report media change +// when we read/write data later. +// [Solution] Send "Get_Configuration" command for CD/DVD devices. +// [Files] usbmass.c +// +// 155 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 +// +// 154 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 153 4/30/14 1:59a Wilsonlee +// [TAG] EIP162993 +// [Category] Improvement +// [Description] We need to return success on INT 13 func 2 even if +// there is no media. +// [Files] usbmass.c, UI13.bin, Bfiusb.asm +// +// 152 4/29/14 8:55p Wilsonlee +// [TAG] EIP165610 +// [Category] Improvement +// [Description] We still need to try readformatcapacity command even if +// the subclass isn't UFI. +// [Files] usbmass.c +// +// 151 4/29/14 8:47p Wilsonlee +// [TAG] EIP152539 +// [Category] Improvement +// [Description] If the pervious device status is that media not present +// and current device status comes as media present, modified the code to +// report as media changed along with current status in the usbmass.c. +// [Files] usbmass.c +// +// 150 4/07/14 2:07a Wilsonlee +// [TAG] EIP156126 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] The power Format of UEFI can not be identified when we +// install OS from USB CD-ROM. +// [RootCause] The media information is incorrect when we install +// BlockIoProtocol for usb CD / DVD devices. +// [Solution] Get the media status before we install BlockIoProtocol. +// [Files] usbmass.c, usbdef.h, efiusbmass.c +// +// 149 4/03/14 3:32a Wilsonlee +// [TAG] EIP161240 +// [Category] Improvement +// [Description] Use Div64 if variables is UINT64. +// [Files] usbmass.c +// +// 148 2/25/14 10:15p Wilsonlee +// [TAG] EIP155805 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] WinCE loader can't boot. +// [RootCause] It can't boot if the mass storage doesn't have validate +// partition table. +// [Solution] We should set the type to FORCED_FDD if it's not a Floppy +// and doesn't have validate partition table. +// [Files] usbmass.c +// +// 147 12/23/13 1:56a Ryanchou +// [TAG] EIP147532 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Dynamic DVD Insertion failed to Read the files +// [RootCause] The Last Block is not updated properly when the new CD is +// inserted. +// [Solution] Update geometry if media is changed. +// [Files] usbmass.c +// +// 146 12/15/13 10:16p Wilsonlee +// [TAG] EIP136594 +// [Category] New Feature +// [Description] Support 64 bits LBA of usb mass storages. +// [Files] Bfiusb.asm, Bfiusb.equ, UsbInt13.c, UsbInt13.h, amiusb.c, +// usbdef.h, usbmass.c, UsbMass.h, efiusbmass.c, UI13.bin +// +// 145 10/20/13 11:32p Wilsonlee +// [TAG] EIP139719 +// [Category] Improvement +// [Description] Ignore the bulk data if the status transport causes +// time out. +// [Files] usbmass.c +// +// 144 9/04/13 5:35a Wilsonlee +// [TAG] EIP135036 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] MultilUN deviices don't install successfully after hotplug +// in shell. +// [RootCause] We skip to get maximum LUN if this mass storage is +// already registered. +// [Solution] Get maximum LUN even if this mass storage is already +// registered. +// [Files] usbmass.c +// +// 143 9/04/13 4:49a Wilsonlee +// [TAG] EIP133270 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Sony MS card reader sometimes cause system hang at 0xD5. +// [RootCause] This device may return the wrong data when we send "read +// format capacities" command. +// [Solution] Return error if capacity list header is wrong. +// [Files] usbmass.c +// +// 142 8/23/13 5:41a Ryanchou +// [TAG] EIP131624 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB mass storage configured fails +// [RootCause] USB Mass Storage driver canot find the correct DeviccInfo +// structure if it is a multiple interface device and the first interface +// is not mass storage class +// [Solution] Compare the DeviceInfo pointer to find the correct one, +// not device address +// [Files] usbmass.c +// +// 141 8/02/13 6:17a Ryanchou +// +// 140 7/29/13 5:21a Roberthsu +// [TAG] EIP126741 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Cannot boot to uefi usb device with Sophos software. +// [RootCause] When boot into tool. Ownership to os event occur.Usb +// will disconnect device.And record this disconnect event. Then ownership +// to bios,bios will connect all device.Run legacy to efi function. Bios +// run disconnect event first.Then reconnect device.Because usb key behind +// hub. So usb key disconnect also. +// [Solution] Check device when device reconnect.If device and port +// number the same.Use the same device info. +// [Files] usb.c,usbmass.c,efiusbmass.c,uhcd.c +// +// 139 7/23/13 11:50a Pats +// [TAG] EIP128964 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Int 13 Function 08 doesn't work right for USB mass storage +// devices. +// [RootCause] The default Head and Sector values for USB mass storage +// devices are fixed, resulting in a Cylinder value that is too large for +// the CHS format, when the device is over 2095104 sectors in size. +// [Solution] Modify function USBMassSetDefaultGeometry() to use Head and +// Sector values based ot total size. +// [Files] usbmass.c +// +// 138 7/23/13 2:14a Wilsonlee +// [TAG] EIP127941 +// [Category] Improvement +// [Description] Replace UI13HDDFunc08 with UI13FDDFunc08 if the media +// descriptor is a fixed disk. +// [Files] UsbInt13.h, UsbInt13.c, usbmass.c, usbdef.h, Bfiusb.asm, +// Bfiusb.equ +// +// 137 7/03/13 4:48a Ryanchou +// [TAG] EIP127800 +// [Category] Improvement +// [Description] Add non-bootable device type handing +// [Files] usbmass.c, efiusbmass.c +// +// 136 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 +// +// 135 3/08/13 4:04a Roberthsu +// [TAG] EIP113379 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB MBR data read with 125MB USB key will get wrong +// value +// [RootCause] When device emu force floppy.Read command will clear +// some information when read mbr. +// [Solution] If device emu force floppy.Only change mbr data when +// legacy. +// [Files] usbmass.c +// +// 134 1/22/13 5:10a Wilsonlee +// [TAG] EIP110635 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] ReadOnly attribute is not properly updated for USB FDD. +// [RootCause] The Media change status never gets refelected in +// AmiUsbBlkIoReadWrite function. +// [Solution] We should pass this information if the media has changed. +// [Files] usbmass.c +// +// 133 1/22/13 3:09a Wilsonlee +// [TAG] EIP112938 +// [Category] Improvement +// [Description] Create a header file for usb mass storage driver. +// [Files] UsbMass.h, usbmass.c, usbdef.h, amiusb.c, efiusbmass.c +// +// 132 1/22/13 2:38a Wilsonlee +// [TAG] EIP110305 +// [Category] Improvement +// [Description] Set the device address after we send the first +// get-device-descriptor command. +// [Files] usbmass.c, usb.c, usbdef.h, usbbus.c, efiusbmass.c, uhcd.c, +// usbport.c +// +// 131 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 130 12/24/12 1:43a Roberthsu +// [TAG] EIP107198 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Run gdisk.exe fail +// [RootCause] Device no media, gdisk call int13 get worng geometry. +// [Solution] If device no present.Do not return geometry. +// [Files] usbmass.c +// +// 129 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 +// +// 128 10/03/12 5:40a Wilsonlee +// [TAG] EIP101623 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Fingerprint reader causes system waiting a long period at +// PC B4. +// [RootCause] The fingerprint reader returns sense key 0x02 instead of +// 0x00 if it doesn't have error sense key for request sense command. +// Which causes our code to repeatly wait for correct sense key. +// [Solution] We should send the request sense command only if the CSW +// is failed. However, current architecture has side-effect with this +// method. So we skip the sense key 0x02 as a workaround here. +// [Files] usbmass.c +// +// 127 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 +// +// 126 9/04/12 8:03a Wilsonlee +// [TAG] EIP99882 +// [Category] New Feature +// [Description] Add the usb setup item and usbpolicyprotocol to enable +// or disable the usb mass storage driver. +// [Files] UsbPolicy.h, usb.uni, usb.sd, usbmass.c, usbdef.h, +// efiusbmass.c, usbport.c, uhcd.c +// +// 125 8/13/12 2:10a Roberthsu +// [TAG] EIP94060 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB key can not boot to DOS after Ctrl+Alt+Del +// [RootCause] Because some device does not support mode sense +// command. +// [Solution] Send mode sense command when device type is UFI . +// [Files] usbmass.c +// +// 124 7/12/12 2:39a Roberthsu +// [TAG] EIP93460 +// [Category] Improvement +// [Description] Add token decide mass available under efi application +// when legacy support disabled. +// [Files] usb.sd,usb.uni,usbmass.c,usbsrc.sdl +// +// 123 6/28/12 10:21p Wilsonlee +// [TAG] EIP90503 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Plug USB card reader cause time too long to boot +// [RootCause] t sometimes happens "STALL" when data transport, then the +// next command will causes device timeout (20 seconds). +// [Solution] We perform reset recovery if there is the second "STALL" +// when we attempt to read CSW from Bulk-in endpoint. +// [Files] usbmass.c +// +// 122 6/14/12 2:59a Ryanchou +// [TAG] EIP91363 +// [Category] Improvement +// [Description] Correct the initial value of variable "bRetValue" in +// USBMassReadSector. +// [Files] usbmass.c +// +// 121 5/03/12 4:36a Ryanchou +// [TAG] EIP88240 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Disconnect and Connect USB Mass Driver will cause system +// hang up. +// [RootCause] The data toggle is not sync with device. +// [Solution] Remove the code that reset data toggle in +// USBMassConfigureStorageDevice. +// [Files] usbmass.c +// +// 120 5/02/12 8:12a Wilsonlee +// [TAG] EIP86793 +// [Category] New Feature +// [Description] Add the SDL token "USB_MASS_EMULATION_FOR_NO_MEDIA" for +// determine the USB mass storage device emulation type without media. +// [Files] usbmass.c, usbport.c, uhcd.c, usbdef.h, usbsrc.sdl +// +// 119 4/10/12 9:51p Wilsonlee +// [TAG] EIP84684 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Access SD Card In Auto Mode Test Fail - 1APUY012 BQA (F1) +// [RootCause] Usb module token MAX_SIZE_FOR_FLOPPY_EMULATION +// redefinition. +// [Solution] Change the token name to +// MAX_SIZE_FOR_USB_FLOPPY_EMULATION. +// [Files] usbmass.c, usbsrc.sdl +// +// 118 4/06/12 5:01a Ryanchou +// [TAG] EIP83321 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hangs at checkpoint 0xBd with specific USB key. +// [RootCause] The device report itself as floppy after reset, the +// subclass is UFI device and protocol is CBI with command completion +// interrupt, but there is the interrupt endpoint in the configuration +// descriptor. +// [Solution] Check if the interrupt is invalid, if it is invalid, skip +// the status transport. +// [Files] usbmass.c +// +// 116 4/05/12 7:28a Wilsonlee +// [TAG] EIP86125 +// [Category] Improvement +// [Description] Clear the flag ¡§USB_MASS_MEDIA_CHANGED¡¨when the +// sensekey is 0. +// [Files] usbmass.c +// +// 115 3/20/12 10:34p Wilsonlee +// [TAG] EIP83295 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System will hang at B2 when do S3/S4 long run test or DOS +// reboot test. +// [RootCause] It causes the stack problem when we call +// IsUSBKeyboardBufferEmpty function. +// [Solution] Change to use pointer as parameter to +// IsUSBKeyboardBufferEmpty function. +// [Files] efiusbkb.c, efisubkb.h, usbmass.c, ehci.c +// +// 114 1/14/12 6:39a Wilsonlee +// [TAG] EIP80382 +// [Category] New Feature +// [Description] Add the SDL token "USB_MASS_EMULATION_BY_SIZE" for +// determine the USB mass storage device emulation type by size only. +// [Files] usbmass.c, usbport.c, uhcd.c, usbdef.h, usbsrc.sdl +// +// 113 1/13/12 4:25a Ryanchou +// [TAG] EIP47348 +// [Category] New Feature +// [Description] Support for USB Port Reset function. +// [Files] amiusb.c, amiusb.h, amiusbhc.c, uhci.c, usb.c, usbbus.c, +// usbbus.h, usbmass.c +// +// 112 1/06/12 12:58a Rajeshms +// [TAG] EIP62737 +// [Category] Improvement +// [Description] Added USB Device number into USB mass device name +// string based on SDL Token. +// [Files] Usb.sdl, usbport.c, usbmass.c, UsbInt13.h, UsbInt13.c, +// usbbus.c, Bfiusb.equ +// +// 111 11/08/11 7:39a Ryanchou +// [TAG] EIP71262 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Sanyo ICR-PS401RM cause system hang at PC B4 +// [RootCause] The data length of Read Format Capacity command returned +// exceed allocation length. +// [Solution] Increase the allocation length to avoid this issue. +// [Files] usbmass.c +// +// 110 11/08/11 2:23a Ryanchou +// [TAG] EIP63706 +// [Category] Improvement +// [Description] Filter out the character if it is invisible. +// [Files] usbmass.c +// +// 109 11/05/11 7:36a Wilsonlee +// [TAG] EIP64781 +// [Category] New Feature +// [Description] Added SDL token +// SKIP_CARD_READER_CONNECT_BEEP_IF_NO_MEDIA that skip the connect beep if +// no media present in USB card reader. +// [Files] usbport.c, usbmass.c, usb.c, usbdef.h, uhcd.c, usbsrc.sdl +// +// 108 10/24/11 4:55a Ryanchou +// [TAG] EIP70814 +// [Category] Improvement +// [Description] Read a block size each time to avoid out of memory +// problem. +// [Files] usbmass.c +// +// 107 8/08/11 5:18a Ryanchou +// [TAG] EIP60561 +// [Category] New Feature +// [Description] Add USB timing policy protocol for timing override. +// [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, +// usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl +// +// 106 7/12/11 11:34p Ryanchou +// [TAG] EIP61388 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] FreeDOS will hang at USB storage device while selecting Force +// FDD. +// [RootCause] Hidden sector is not 0. +// [Solution] Force #of hidden sectors to 0 +// [Files] usbmass.c +// +// 105 7/12/11 6:32a Ryanchou +// [TAG] EIP63308 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] POST hang with USB WiMAX Dongle plugged on USB3.0 port +// [RootCause] The device always return invalid Command Status Wrapper. +// [Solution] Do nothing if CSW is invalid. +// [Files] usbmass.c +// +// 104 6/27/11 12:33a Ryanchou +// Correct EIP51158 changes. +// +// 103 6/22/11 1:45a Ryanchou +// [TAG] EIP59738 +// [Category] Improvement +// [Description] Support Block size other than 512 bytes USB HDD in UEFI +// mode. +// [Files] efiusbmass.c, uhci.c, usb.c, usbdef.h, usbmass.c +// +// 102 6/22/11 12:43a Ryanchou +// [TAG] EIP51158 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Samsung i7500 mobile phone can't be recognized +// [RootCause] The data packet length of UFI command is not same as SCSI +// command, the device stalls the UFI command. +// [Solution] Use SCSI command if the subclass code indicate the device +// support SCSI command set. +// [Files] usbmass.c +// +// 101 6/21/11 11:02a Ryanchou +// [TAG] EIP59579 +// [Category] Improvement +// [Description] USB device information structure should be reserved for +// the UsbIO to use even install driver fail. +// [Files] usbmass.c, usbkbd.c, usbms.c +// +// 100 6/21/11 10:54a Ryanchou +// [TAG] EIP60588 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] MS-DOS 7.1 boot by USB 2.0 Flash Drive will crash system at +// black screen. +// [RootCause] The LBA that will be read is greater than the max LBA. +// [Solution] Set the the starting LBA address to (the last LBA - number +// of blocks to process) if dStartLBA is greater than (dMaxLba - +// wNumBlks). +// [Files] usbmass.c +// +// 99 5/03/11 10:11a Ryanchou +// [TAG] EIP54283 +// [Category] Improvement +// [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery +// endpoint halt. +// [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c +// +// 98 5/03/11 8:29a Ryanchou +// [TAG] EIP43711 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB-FDD will be recognized as USB-HDD in BIOS Setup. +// [RootCause] The media reports valid partition which is same as HDD. +// [Solution] Check the device class to fix this issue. +// [Files] usbmass.c +// +// 97 5/03/11 7:51a Ryanchou +// [TAG] EIP53416 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Iomega Zip250 hang at StatusCode 0xB4 +// [RootCause] Fail to calculate CHS values from max LBA if device is +// not ready. +// [Solution] Should not get device geometry if device is not ready. +// [Files] usbmass.c +// +// 96 4/06/11 4:29a Ryanchou +// [TAG] EIP57573 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Can't boot to USB 3.0 device +// [RootCause] Some device haven't indicate Test Unit Ready command +// failure in the CSW status. +// [Solution] Undo the EIP55440 changes and send Test Unit Ready command +// again if the Sense key is MEDIUM ERROR. +// [Files] usbmass.c +// +// 95 3/30/11 8:15a Ryanchou +// [TAG] EIP54126 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Sometimes system hangs at checkpoint 0xB4. +// [RootCause] The bLength field of configuration descriptor is zero. +// [Solution] Check wether bLength field is zero before paring next +// descriptor. +// [Files] usb.c, usbbus.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c +// +// 94 3/26/11 4:13a Ryanchou +// [TAG] EIP55440 +// [Category] Improvement +// [Description] Request Sense command should be sent only if the CSW of +// the storage command isn't Success. +// [Files] usbmass.c +// +// 93 3/16/11 11:45p Ryanchou +// [TAG] EIP52719 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB 3.0 HDD is detected as USB FDD +// [RootCause] Fail to read MBR while configure the device. +// [Solution] Retry 10 times. +// [Files] usbmass.c +// +// 92 1/25/11 5:30p Olegi +// [TAG] EIP52205 +// [Category] Improvement +// [Description] System can not boot from a certain FD image. Changed +// MBR validation routine to check the valid partition(s) size. +// [Files] usbmass.c +// +// 91 12/28/10 4:45a Ryanchou +// [TAG] EIP50968 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] BIOS can't boot to WD My Book 3.0. +// [RootCause] The USB 3.0 device returns sense data 0x800000 when +// device is ready. +// [Solution] Ignore the ASC and ASCQ, check the Sense key only. +// [Files] usbmass.c, xhci.h +// +// 90 12/27/10 12:44a Ryanchou +// [TAG] EIP50458 +// [Category] Improvement +// [Description] If pre skip and post skip is not zero, allocate a +// buffer for data transfer. +// [Files] usbmass.c +// +// 89 12/12/10 11:14p Ryanchou +// [TAG] EIP48166 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] POST takes a long time if USB ODD is connected. +// [RootCause] USB driver determines media not present when Sense Data +// is 0x003A02. the USB ODD returns 0x013A02 for no media condition. +// [Solution] Check Sense key and ASC only for no media condition. +// +// 88 11/11/10 8:50a Ryanchou +// [TAG] EIP47638 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] The command block of read command is invalid +// [RootCause] The command block is destoyed in USBMassSendBOTCommand. +// [Solution] Reinitialize the command block. +// [Files] usbmass.c +// +// 87 10/28/10 12:25a Ryanchou +// EIP45643: Fixed system hangs when hot plug USB mass storage quickly on +// USB 3.0 port. +// +// 86 10/21/10 10:13a Ryanchou +// EIP45121: Added xHCI Supported Protocol Capability and fix the problem +// that USB 3.0 device can't be detected. +// +// 85 10/20/10 9:16a Ryanchou +// EIP44239: Delay for the device to get ready if sense key is 0x06. +// +// 84 10/20/10 12:56a Ryanchou +// EIP45828: If the flag DEV_INFO_MASS_DEV_REGD is set, check if the +// controller type is difference between old DevInfo and new one. +// +// 83 10/12/10 2:13a Rameshr +// [TAG]- EIP 44585 +// [Category]-IMPROVEMENT +// [Description]- Number of maximum supported USB Mass Storage device +// increased from 8 to 16. +// [Files]- Uin13.bin, UsbPort.c, UsbInt13.h, Usb.c, Usbdef.h, Uasbmass.c, +// Usb.sd, usb.uni, UsbSetup.c, UsbSrc.sdl, UsbPolicy.h +// +// 82 9/07/10 4:34a Tonylo +// Remove user tags for coding standard. +// +// 81 9/01/10 8:32a Ryanchou +// EIP42297: Fixed boot to hot plug USB HDD fail. +// +// 80 8/18/10 4:23p Olegi +// Klockwork related fixes; EIP37978 +// +// 79 7/15/10 4:40a Tonylo +// EIP21649 - USB mass storage device still appear in BBS menu when USB +// legacy support is disabled. +// +// 78 6/22/10 9:31a Ryanchou +// EIP39374: Fixed USB key hot plug issue. +// +// 77 6/10/10 11:27p Ryanchou +// The USB0089 patch is for card reader, floppy doesn't need. +// +// 76 5/05/10 12:02p Olegi +// Send Start Unit command to the device when sense data is 0x020402. +// EIP36909 +// +// 75 4/12/10 4:17p Olegi +// Slow MSD may return invalid block size and max lba when device is not +// ready. Check the value of block Size and max lba returned by Read +// Capacity Command. EIP37167. +// +// 74 3/02/10 9:52a Olegi +// Bugfix in USBMassUpdateCHSFromBootRecord, EIP34794. +// +// 73 2/08/10 10:03a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 72 12/18/09 12:12p Olegi +// Added SDL token USB_START_UNIT_BEFORE_MSD_ENUMERATION that controls the +// execution of bugfix for EIP25229. Disable by default. +// +// 71 11/30/09 11:33a Olegi +// Change in USBMassGetFreeMassDeviceInfoStruc, zero device info structure +// can not be returned. EIP27635. +// +// 70 10/02/09 10:49a Olegi +// Code cleanup. +// +// 69 9/09/09 11:28a Olegi +// Increased R/W command timeout delay from 10 to 20 swconds. EIP#24326 +// +// 68 8/26/09 11:52a Olegi +// xUbuntu on USB fix: Start unit command before access it. EIP#25229 +// (Core8 EIP#23581) +// +// 67 6/05/09 2:34p Olegi +// Do not enumerate device if it is not a CD-ROM and has the block size +// different from 512 Bytes. EIP#15595, iPod nano makes POST hang. +// +// 66 6/04/09 3:46p Olegi +// EIP21970: support for hotplug drives, re-inserting them to a different +// controller/port. +// +// 65 6/01/09 10:02a Olegi +// Fix for EIP#21681: The problem is in the Read Format Capacities command +// (0x23), the DataTransferLength is 0x40 in the CBW, but the Allocation +// Length is 0x80 in the CDB. Thus, the driver return Status = Phase +// Error. +// +// 64 5/21/09 5:12p Olegi +// Added HDD hotplug support. +// +// 63 5/15/09 5:50p Olegi +// EIP#21179 - failure of Transcend Card reader configuration fix. +// +// 62 4/24/09 9:32a Olegi +// Bugfix for EIP#20863. +// +// 61 2/17/09 9:18a Olegi +// +// 60 1/29/09 2:40p Olegi +// Added a check for Mass Storage device limit before creating a new LUN +// device. +// +// 59 1/23/09 10:17a Olegi +// Modified the resolution of EIP#18553 +// +// 58 1/16/09 4:04p Olegi +// - Removed the limitation of MAX_BULK_DATA_SIZE in +// USBMassIssueBulkTransfer. +// - Modified USBMassCheckDeviceReady, EIP18553. +// +// 57 11/20/08 1:12p Olegi +// EIP#17634 fix: added StartStopUnit command if TestUnitReady returns the +// value of 0x020402. +// Note: current fix is done only for the device VID 0x0DC4 DID 0x0207; in +// future we may want to extend this fix for other devices. This will +// require additional testing. +// +// 56 11/06/08 11:40a Olegi +// Fixed device configuration for multi-LUN devices. +// +// 55 9/05/08 5:39p Olegi +// +// 54 9/05/08 4:22p Olegi +// fpCallbackNotify4 is replaced with the call within SMI. +// +// 53 8/25/08 12:09p Olegi +// +// 52 8/25/08 12:00p Olegi +// Added USBMassReadCapacityBlockSizePatch function. +// +// 51 8/21/08 12:28p Olegi +// Modification in CreateLogicalUnits function: +// - At the point of the new unit creation, the Lun0 device might be +// locked by the bus driver (USBBUS.usbhc_on_timer); clear the lock +// indicator for the new LUN. +// +// 50 8/13/08 5:32p Olegi +// +// 49 8/13/08 5:27p Olegi +// Bugfix in USBMassGetFormatType. +// +// 48 7/04/08 1:08p Olegi +// Added REQUEST_SENSE command in the sequence of failed MODE_SENSE. +// +// 47 6/27/08 5:54p Olegi +// Mass Device name field is populated in DEV_INFO structure. +// +// 46 6/13/08 3:54p Olegi +// Additions related to 720KB floppy support. +// +// 45 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 44 1/30/08 12:43p Olegi +// - change in USBMassGetDeviceGeometry that returns default geometry for +// those devices with BlockSize reported as 0. +// - change in USBMassGetDeviceInfo that reports PCI bus/dev/function. +// +// 43 10/15/07 5:15p Olegi +// - Modification in USBMassCreateLogicalUnits that allows different +// emulation type for different LUNs +// - Bugfix in USBMassGetFormatType that clears bHiddenSectors field in +// multiple-LUN device +// +// 42 9/17/07 3:33p Olegi +// +// 41 7/10/07 10:25a Olegi +// +// 40 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 39 6/14/07 12:28p Olegi +// +// 38 5/29/07 6:11p Olegi +// +// 37 5/24/07 4:09p Olegi +// +// 36 5/18/07 10:53a Olegi +// Bugfix in USBMassGetDeviceGeometry that used the device ID instead of +// DEV_INFO index for USBMassGetDeviceStatus call. +// +// 35 5/05/07 1:54p Olegi +// Persistent DOS drives. +// +// 34 4/18/07 2:51p Fredericko +// Bugfix in USBMassUpdateDeviceGeometry, removed redundant code that +// corrupted memory. +// +// 32 4/17/07 11:05a Olegi +// +// 30 3/29/07 6:40p Olegi +// Modified USBMassUpdateDeviceGeometry to take care of USB floppy drive +// with no floppy in it. +// +// 29 3/20/07 12:19p Olegi +// +// 28 2/27/07 10:45a Olegi +// +// 27 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 26 12/20/06 3:38p Olegi +// +// 25 12/20/06 2:30p Olegi +// +// 24 12/12/06 12:32p Olegi +// +// 22 11/09/06 4:57p Olegi +// +// 18 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 17 3/21/06 12:01p Olegi +// +// 16 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 15 3/16/06 2:33p Olegi +// +// 14 3/06/06 6:25p Olegi +// Lun devices support modifications: supported using the index in +// DEV_INFO table, not through dedicated massLun table. +// +// 13 1/11/06 11:52a Olegi +// Setup related modifications. +// +// 12 12/19/05 10:17a Olegi +// DeviceDelayCount is Setup driven. +// +// 11 12/01/05 5:49p Olegi +// +// 10 11/10/05 11:11a Olegi +// +// 9 11/04/05 6:22p Olegi +// Multiple LUN support. +// +// 8 10/17/05 5:12p Olegi +// +// 7 9/22/05 6:28p Olegi +// +// 6 9/15/05 6:10p Andriyn +// Fix: Mass Storage name gets corrupted in setup +// +// 5 8/23/05 5:53p Olegi +// Latest USB mass storage updates from AMIBIOS USB module are applied. +// +// 4 6/03/05 9:31a Olegi +// MediaId update moved to EFI mass strorage driver. +// +// 3 5/17/05 7:51p Andriyn +// USB BUS pre-release +// +// 2 4/26/05 5:09p Olegi +// Modifications in USBMassRWVCommand, USBMassCheckDeviceReady to properly +// handle USB FDDs with no media in them. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbMass.c +// +// Description: AMI USB Mass Storage support implementation +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "UsbMass.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +VOID USBMassInitialize(VOID); +UINT8 USBMassCheckForStorageDevice(DEV_INFO*, UINT8, UINT8, UINT8); +DEV_INFO* USBMassConfigureStorageDevice(HC_STRUC*, DEV_INFO*, + UINT8*, UINT16, UINT16); +UINT8 USBMassDisconnectStorageDevice(DEV_INFO*); +UINT16 USBMassSendCBICommand(DEV_INFO*, MASS_XACT_STRUC*); +UINT32 USBMassProcessBulkData(DEV_INFO*, MASS_XACT_STRUC*); +UINT8 USBMassConsumeBulkData(DEV_INFO*,UINT8,UINT16); +UINT32 USBMassIssueBOTTransaction(DEV_INFO*, MASS_XACT_STRUC*); +VOID USBMassClearBulkEndpointStall(DEV_INFO*, UINT8); +VOID USBMassBOTResetRecovery(DEV_INFO*); +UINT16 USBMassSendBOTCommand(DEV_INFO*, MASS_XACT_STRUC*); +UINT8 USBMassGetBOTStatus(DEV_INFO*, MASS_XACT_STRUC*); +UINT16 USBMassCBIGetStatus(DEV_INFO*); +UINT32 USBMassIssueCBITransaction(DEV_INFO*, MASS_XACT_STRUC*); +UINT8 USBMassReadCapacity10Command(DEV_INFO*); +UINT32 USBMassCheckDeviceReady(DEV_INFO*); +UINT32 USBMassRequestSense(DEV_INFO* fpDevInfo); +VOID USBMassSenseKeyParsing(DEV_INFO* , UINT32); +MASS_INQUIRY *USBMassInquiryCommand(DEV_INFO*); +UINT8 USBMassUpdateDeviceGeometry( DEV_INFO* fpDevInfo ); +UINT16 USBMassBOTGetMaxLUN(DEV_INFO*); +VOID USBMassIdentifyDeviceType(DEV_INFO*, UINT8*); +UINT32 USBMassIssueBulkTransfer(DEV_INFO*, UINT8, UINT8*, UINT32); +VOID iPodShufflePatch(MASS_GET_DEV_INFO*); +VOID USBMassUpdateCylinderInfo(DEV_INFO*, UINT64); +UINT8 USBMassSetDefaultGeometry(DEV_INFO*, UINT64); +UINT8 USBMassValidatePartitionTable(MASTER_BOOT_RECORD*, UINT64, MBR_PARTITION*); +UINT16 USBMassSetDefaultType(DEV_INFO*, UINT64); +VOID USBMassGetPhysicalDeviceType(DEV_INFO*, UINT8*); +UINT8 USB_SetAddress(HC_STRUC*, DEV_INFO*, UINT8); +UINT32 dabc_to_abcd(UINT32); +DEV_INFO* USBGetProperDeviceInfoStructure(DEV_INFO*, UINT8); +UINT32 USBMassTestUnitReady(DEV_INFO*); +VOID StoreUsbMassDeviceName(DEV_INFO*, UINT8*); +extern VOID AddPortNumbertoDeviceString(DEV_INFO*); +UINT8 USBMassGetConfiguration(DEV_INFO*); + +VOID MemFill (UINT8*, UINT32, UINT8); +VOID MemCopy (UINT8*, UINT8*, UINT32); +VOID* USB_MemAlloc (UINT16); +DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +MASS_INQUIRY* USBMassGetDeviceParameters(DEV_INFO*); + +UINT8 USB_MemFree (VOID*, UINT16); +VOID FixedDelay(UINTN); +VOID SpeakerBeep (UINT8, UINT16, HC_STRUC*); //(EIP64781+) + +static char* IOMegaZIPString = "IOMEGA ZIP"; +#define IOMegaZIPStringLength 11 + +static char* MSysDiskOnKeyString = "M-Sys DiskOnKey"; +#define MSysDiskOnKeyStringLength 17 + +BOOLEAN CheckDeviceLimit(UINT8); + +VOID +USBMassFillDriverEntries (DEV_DRIVER *fpDevDriver) +{ + fpDevDriver->bDevType = BIOS_DEV_TYPE_STORAGE; + fpDevDriver->bProtocol = 0; + fpDevDriver->pfnDeviceInit = USBMassInitialize; + fpDevDriver->pfnCheckDeviceType = USBMassCheckForStorageDevice; + fpDevDriver->pfnConfigureDevice = USBMassConfigureStorageDevice; + fpDevDriver->pfnDisconnectDevice = USBMassDisconnectStorageDevice; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: USBMassInitialize +// +// DESCRIPTION: This function initializes mass storage device related data +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassInitialize () +{ + // + // Set default value for the delay. Selections are: 20,40,60,80 for 10,20,30,40 sec. + // + gUsbData->bUSBStorageDeviceDelayCount = (gUsbData->UsbMassResetDelay + 1)*10; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassCheckForStorageDevice +// +// DESCRIPTION: This routine checks for hub type device from the +// interface data provided +// +// PARAMETERS: bBaseClass USB base class code +// bSubClass USB sub-class code +// bProtocol USB protocol code +// +// RETURN: BIOS_DEV_TYPE_STORAGE type on success or 0FFH on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassCheckForStorageDevice ( + DEV_INFO* DevInfo, + UINT8 BaseClass, + UINT8 SubClass, + UINT8 Protocol +) +{ + if (BaseClass != BASE_CLASS_MASS_STORAGE) { + return USB_ERROR; + } + //(EIP99882+)> + if (!gUsbData->UsbSetupData.UsbMassDriverSupport) { + return USB_ERROR; + } + //<(EIP99882+) +//Skip USB mass storage devices enumeration when legacy is disabled + if (gUsbData->dUSBStateFlag & USB_FLAG_DISABLE_LEGACY_SUPPORT) { + if (LEGACY_USB_DISABLE_FOR_USB_MASS) { //(EIP93469) + return USB_ERROR; + } + } + // + // Base class is okay. Check the protocol field for supported protocols. + // Currently we support CBI, CB and BOT protocols. + // + if ((Protocol != PROTOCOL_CBI) && + (Protocol != PROTOCOL_CBI_NO_INT) && + (Protocol != PROTOCOL_BOT)) { + return USB_ERROR; + } + + return BIOS_DEV_TYPE_STORAGE; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetFreeMassDeviceInfoStruc +// +// Description: This function finds a free mass device info structure and +// returns the pointer to it +// +// Input: None +// +// Output: Pointer to the Mass Device Info (0 on failure) +// The number mass storage DeviceInfo structure (0-based) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBMassGetFreeMassDeviceInfoStruc( + DEV_INFO *DevInfo, + UINT8 *Indx +) +{ + DEV_INFO* Dev = &gUsbData->aDevInfoTable[1]; + UINT8 Count; + UINT8 MassDevIndx = 0; + + for (Count = 0; Count < (MAX_DEVICES-1); Count++, Dev++) { + if (!(Dev->Flag & DEV_INFO_VALID_STRUC)) { + continue; + } + if (Dev->bDeviceType == BIOS_DEV_TYPE_STORAGE) { + MassDevIndx++; + } + if (Dev == DevInfo) { + break; + } + } + if (Count == (MAX_DEVICES-1)) { + return NULL; + } + *Indx = MassDevIndx; + + return Dev; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassFindFreeMassDeviceInfo +// +// Description: This function finds a free mass device info structure and +// copies the current mass device info structure into it +// +// Input: Current mass device info structure +// +// Output: New mass device info +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBMassFindFreeMassDeviceInfo( + DEV_INFO* Dev, + UINT8 *EmulIndex +) +{ + UINT8 Indx = 0; + DEV_INFO *NewDev; + + // Get the free mass device info structure pointer + NewDev = USBMassGetFreeMassDeviceInfoStruc(Dev, &Indx); + + if (NewDev == NULL) { + return NULL; // No free entry found. + } + + // Get the emulation type setup question associated with this device + ASSERT(Indx>0 && Indx<17); + if ((Indx == 0) || (Indx > 16)) { + return NULL; + } + + Dev->wEmulationOption = gUsbData->USBMassEmulationOptionTable[Indx-1]; + USB_DEBUG(DEBUG_LEVEL_3, "USBMassFindFreeMassDeviceInfo-------- indx %d, emu %d\n", Indx, Dev->wEmulationOption); + + // Set default device type and emulation type to 0 + Dev->bStorageType = 0; + Dev->fpLUN0DevInfoPtr = 0; + Dev->Flag |= DEV_INFO_DEV_PRESENT; + + *EmulIndex = Indx-1; + + return Dev; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassCreateLogicalUnits +// +// Description: This function verifies the presence of logical units (LUN) +// in the USB mass device and creates appropriate device info +// structures for them +// +// Input: fpDevInfo - Device information structure pointer +// bMaxLun - Maximum number of logical units present (non-ZERO) +// +// Output: USB_ERROR On error +// USB_SUCCESS On successfull completion +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassCreateLogicalUnits( + DEV_INFO* DevInfo, + UINT8 MaxLun, + UINT8 EmulIndex +) +{ + UINT8 Lun; + DEV_INFO* NewDevInfo; + MASS_INQUIRY *Inq; + + for (Lun = 1; Lun <= MaxLun; Lun++) { + + if (CheckDeviceLimit(BASE_CLASS_MASS_STORAGE) == TRUE) { + break; + } + // + // Get the proper device info structure + // + NewDevInfo = USBGetProperDeviceInfoStructure(DevInfo, Lun); + if (!NewDevInfo) { + return USB_ERROR; + } + // + // Check whether this device is reconnected by checking the + // valid structure flag + // + if ((NewDevInfo->Flag & DEV_INFO_MASS_DEV_REGD)) { + // + // Indicate device as connected + // + NewDevInfo->Flag |= DEV_INFO_DEV_PRESENT; + + // Change the parent HC number and port number in the existing DEV_INFO + NewDevInfo->bHCNumber = DevInfo->bHCNumber; + NewDevInfo->bHubDeviceNumber = DevInfo->bHubDeviceNumber; + NewDevInfo->bHubPortNumber = DevInfo->bHubPortNumber; + NewDevInfo->bEndpointSpeed = DevInfo->bEndpointSpeed; + NewDevInfo->wEndp0MaxPacket = DevInfo->wEndp0MaxPacket; + NewDevInfo->DevMiscInfo = DevInfo->DevMiscInfo; + NewDevInfo->bDeviceAddress = DevInfo->bDeviceAddress; + NewDevInfo->bBulkInEndpoint = DevInfo->bBulkInEndpoint; + NewDevInfo->wBulkInMaxPkt = DevInfo->wBulkInMaxPkt; + NewDevInfo->bBulkOutEndpoint = DevInfo->bBulkOutEndpoint; + NewDevInfo->wBulkOutMaxPkt = DevInfo->wBulkOutMaxPkt; + NewDevInfo->IntInEndpoint = DevInfo->IntInEndpoint; + NewDevInfo->IntInMaxPkt = DevInfo->IntInMaxPkt; + NewDevInfo->bPollInterval = DevInfo->bPollInterval; + NewDevInfo->fpLUN0DevInfoPtr = DevInfo; + } else { // This is different device, it was not reconnected + // + // Copy the old device info structure into the new one + // + MemCopy((UINT8*)DevInfo, + (UINT8*)NewDevInfo, + sizeof (DEV_INFO)); + NewDevInfo->bLUN = Lun; // Change LUN number + NewDevInfo->wEmulationOption = gUsbData->USBMassEmulationOptionTable[EmulIndex + Lun]; + MemFill(NewDevInfo->DevNameString, 64, 0); + // + // Save the Lun0 device info pointer in the current LUN + // + NewDevInfo->fpLUN0DevInfoPtr = DevInfo; + + // + // The Lun0 device might have been already locked by the + // bus (USBBUS.usbhc_on_timer), clear it for current LUN. + // + NewDevInfo->Flag &= ~DEV_INFO_DEV_BUS; + + Inq = USBMassGetDeviceParameters(NewDevInfo); + ASSERT(Inq); + StoreUsbMassDeviceName(NewDevInfo, (UINT8*)Inq + 8); + if (NewDevInfo->bStorageType == USB_MASS_DEV_CDROM) { + USBMassGetConfiguration(NewDevInfo); + } + } + + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + if (!(NewDevInfo->Flag & DEV_INFO_IN_QUEUE)) { + USB_SmiQueuePut(NewDevInfo); + NewDevInfo->Flag |= DEV_INFO_IN_QUEUE; + } + } + } + + return USB_SUCCESS; +} + + +VOID +StoreUsbMassDeviceName( + DEV_INFO *Device, + UINT8 *Str +) +{ + UINT8 i; + UINT8 j; + + for (i = 0; i < 64; i++) { + if (Device->DevNameString[i] != 0) { + return; + } + } + + for (i = 0, j = 0; i < 32; i++) { + if (*Str == 0) { + Str++; j++; // supress leading zeroes + } + } + + for (i = 0; i < (32-j); i++, Str++) { + // supress spaces if more than one + if ((i>0) && (Device->DevNameString[i-1]==' ') && (*Str==' ')) { + i--; + continue; + } + //(EIP63706+)> + // Filter out the character if it is invisible. + if (((*Str != 0) && (*Str < 0x20)) || (*Str > 0x7E)) { + i--; + continue; + } + //<(EIP63706+) + + Device->DevNameString[i] = *Str; + } + + // + // Add Device number to the USB device string + // +#if USB_DIFFERENTIATE_IDENTICAL_DEVICE_NAME + AddPortNumbertoDeviceString(Device); +#endif +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassConfigureStorageDevice +// +// DESCRIPTION: This function checks an interface descriptor of a device +// to see if it describes a USB mass device. If the device +// is a mass storage device, then it is configured +// and initialized. +// +// PARAMETERS: pHCStruc HCStruc pointer +// pDevInfo Device information structure pointer +// pDesc Pointer to the descriptor structure +// wEnd End offset of the device descriptor +// +// RETURN: New device info structure, NULL on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBMassConfigureStorageDevice ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT8* fpDesc, + UINT16 wStart, + UINT16 wEnd) +{ + UINT8 bTemp; + UINT16 wRetValue; + ENDP_DESC *fpEndpDesc; + INTRF_DESC *fpIntrfDesc; + UINT8 bMaxLUN; + DEV_INFO* newDev; + MASS_INQUIRY *inq; + BOOLEAN checkFDDhotplug, checkCDROMhotplug, checkHDDhotplug; + UINT8 EmulIndex; + UINT8 i; //(EIP64781+) + + wRetValue = 0; + bMaxLUN = 0; + +// +// Set fpDevInfo->bDeviceType. This serves as a flag +// that indicates a usable interface has been found in the current +// configuration. This is needed so we can check for other usable interfaces +// in the current configuration (composite device) without trying to search +// in other configurations. +// + fpDevInfo->bDeviceType = BIOS_DEV_TYPE_STORAGE; + fpDevInfo->fpPollTDPtr = 0; + + USB_DEBUG (DEBUG_LEVEL_3, "USBMassConfigureDevice ....\n"); + + bTemp = 0x03; // bit 1 = Bulk In, bit 0 = Bulk Out + + fpDevInfo->bBulkOutEndpoint = 0; + fpDevInfo->bBulkInEndpoint = 0; + fpDevInfo->IntInEndpoint = 0; + + fpIntrfDesc = (INTRF_DESC*)(fpDesc + wStart); + fpDesc+=((CNFG_DESC*)fpDesc)->wTotalLength; // Calculate the end of descriptor block + fpEndpDesc = (ENDP_DESC*)((char*)fpIntrfDesc + fpIntrfDesc->bDescLength); + for( ;(fpEndpDesc->bDescType != DESC_TYPE_INTERFACE) && ((UINT8*)fpEndpDesc < fpDesc); + fpEndpDesc = (ENDP_DESC*)((char*)fpEndpDesc + fpEndpDesc->bDescLength)){ + + if(!(fpEndpDesc->bDescLength)) { + break; // Br if 0 length desc (should never happen, but...) + } + + 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; + USB_DEBUG(3, "bulk out endpoint addr: %x, max packet size: %x\n", + fpDevInfo->bBulkOutEndpoint, fpDevInfo->wBulkOutMaxPkt); + } + } 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; + USB_DEBUG(3, "bulk in endpoint addr: %x, max packet size: %x\n", + fpDevInfo->bBulkInEndpoint, fpDevInfo->wBulkInMaxPkt); + } + } + } + + // + // 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; + USB_DEBUG(3, "interrupt in endpoint addr: %x, max packet size: %x\n", + fpDevInfo->IntInEndpoint, fpDevInfo->IntInMaxPkt); + } + } + + // + // Check the compatibility flag for LUN support + // + if (!(fpDevInfo->wIncompatFlags & USB_INCMPT_SINGLE_LUN_DEVICE)) { + // + // If it is a BOT device, get maximum LUN supported + // + if (fpDevInfo->bProtocol == PROTOCOL_BOT) { + bMaxLUN = (UINT8)USBMassBOTGetMaxLUN(fpDevInfo); + } + } + + // + // Check whether the device is already registered. If so, proceed with current + // mass info structure + // + if (fpDevInfo->Flag & DEV_INFO_MASS_DEV_REGD) { + newDev = fpDevInfo; + + goto UMCM_MassDeviceOkay; + } + + // Find a new mass device info structure and copy the old one into the new one + // Note: this is called before GetDeviceParameters because it sets up dev->wEmulationOption + newDev = USBMassFindFreeMassDeviceInfo(fpDevInfo, &EmulIndex); + + if (newDev == NULL) goto UMCM_Error; + fpDevInfo = newDev; + + inq = USBMassGetDeviceParameters(fpDevInfo); + if (inq == NULL) goto UMCM_Error; + + // + // Do not enumerate device if it is not a CD-ROM and has the block size different from 512 Bytes + // EIP#15595, iPod nano makes POST hang. + // + //(EIP59738-)> + //if ( fpDevInfo->bPhyDevType!=USB_MASS_DEV_CDROM ) { + // if( fpDevInfo->wBlockSize!=0x200 && fpDevInfo->wBlockSize!=0xFFFF && fpDevInfo->wBlockSize!=0 ) + // goto UMCM_Error; + //} + //<(EIP59738-) + StoreUsbMassDeviceName(fpDevInfo, (UINT8*)inq+8); + + // Check for the hotplug devices current status, install the new one if needed + if ( !(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) ) { + // Find out if FDD/HDD/CDROM hotplugging is a valid option + checkFDDhotplug = ((gUsbData->fdd_hotplug_support == SETUP_DATA_HOTPLUG_ENABLED) || + ((gUsbData->fdd_hotplug_support == SETUP_DATA_HOTPLUG_AUTO) && + (gUsbData->NumberOfFDDs == 0))) && + !(BOOLEAN)(gUsbData->dUSBStateFlag & USB_HOTPLUG_FDD_ENABLED); + + checkHDDhotplug = ((gUsbData->hdd_hotplug_support == SETUP_DATA_HOTPLUG_ENABLED) || + ((gUsbData->hdd_hotplug_support == SETUP_DATA_HOTPLUG_AUTO) && + (gUsbData->NumberOfHDDs == 0))) && + !(BOOLEAN)(gUsbData->dUSBStateFlag & USB_HOTPLUG_HDD_ENABLED); + + checkCDROMhotplug = ((gUsbData->cdrom_hotplug_support == SETUP_DATA_HOTPLUG_ENABLED) || + ((gUsbData->cdrom_hotplug_support == SETUP_DATA_HOTPLUG_AUTO) && + (gUsbData->NumberOfCDROMs == 0))) && + !(BOOLEAN)(gUsbData->dUSBStateFlag & USB_HOTPLUG_CDROM_ENABLED); + + if ( checkFDDhotplug || checkCDROMhotplug || checkHDDhotplug ) { + USB_DEBUG(DEBUG_LEVEL_3, "connecting hotplug..."); +// inq = USBMassGetDeviceParameters(fpDevInfo); +// if (inq == NULL) goto UMCM_Error; + USB_DEBUG(DEBUG_LEVEL_3, "devtype phy %d, emu %d...", fpDevInfo->bPhyDevType, fpDevInfo->bEmuType); + + if ( checkFDDhotplug && + (fpDevInfo->bStorageType == USB_MASS_DEV_ARMD) ) { + newDev = &gUsbData->FddHotplugDev; + gUsbData->dUSBStateFlag |= USB_HOTPLUG_FDD_ENABLED; + } + + if ( checkHDDhotplug && (fpDevInfo->bEmuType == USB_EMU_HDD_ONLY) ) { + newDev = &gUsbData->HddHotplugDev; + gUsbData->dUSBStateFlag |= USB_HOTPLUG_HDD_ENABLED; + } + + if ( checkCDROMhotplug && (fpDevInfo->bPhyDevType == USB_MASS_DEV_CDROM) ) { + newDev = &gUsbData->CdromHotplugDev; + gUsbData->dUSBStateFlag |= USB_HOTPLUG_CDROM_ENABLED; + } + + fpDevInfo->Flag |= DEV_INFO_HOTPLUG; + *newDev = *fpDevInfo; // Copy device into DevInfo dedicated to hotplug + fpDevInfo->Flag &= ~DEV_INFO_VALIDPRESENT; // Release fpDevInfo + fpDevInfo = newDev; + } + } + +UMCM_MassDeviceOkay: + if ( (newDev->bEmuType == USB_EMU_FLOPPY_ONLY) || + (newDev->bEmuType == USB_EMU_FORCED_FDD) ) { + gUsbData->NumberOfFDDs++; + } + + if ( newDev->bEmuType == USB_EMU_HDD_ONLY ) { + gUsbData->NumberOfHDDs++; + } + +// if ( newDev->bPhyDevType == USB_EMU_HDD_OR_FDD ) { + if ( newDev->bPhyDevType == USB_MASS_DEV_CDROM ) { + gUsbData->NumberOfCDROMs++; + USBMassGetConfiguration(newDev); + } + + if (bMaxLUN) { + USBMassCreateLogicalUnits(newDev, bMaxLUN, EmulIndex); + } + + //(EIP64781+)> + if (gUsbData->dUSBStateFlag & USB_FLAG_SKIP_CARD_READER_CONNECT_BEEP) { + if ((newDev->bLastStatus & USB_MASS_MEDIA_PRESENT) || + newDev->bPhyDevType == USB_MASS_DEV_CDROM || + newDev->bPhyDevType == USB_MASS_DEV_FDD) { + SpeakerBeep(4, 0x1000, fpHCStruc); + } else if (bMaxLUN) { + for(i = 1; i < MAX_DEVICES; i++) { + if (gUsbData->aDevInfoTable[i].fpLUN0DevInfoPtr == newDev) { + if (gUsbData->aDevInfoTable[i].bLastStatus & USB_MASS_MEDIA_PRESENT) { + SpeakerBeep(4, 0x1000, fpHCStruc); + break; + } + } + } + } + } + //<(EIP64781+) + + return newDev; + +UMCM_Error: + //USB_AbortConnectDev(fpDevInfo); //(EIP59579-) + return NULL; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassDisconnectStorageDevice +// +// DESCRIPTION: This function disconnects the storage device +// +// PARAMETERS: pDevInfo Device info structure pointer +// +// RETURN: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassDisconnectStorageDevice ( + DEV_INFO* DevInfo +) +{ +// USB_DEBUG (DEBUG_LEVEL_5, "USBMassDisconnectDevice .... \n"); + + DevInfo->bBulkOutEndpoint = 0; + DevInfo->bBulkInEndpoint = 0; + DevInfo->IntInEndpoint = 0; + + if ((DevInfo->bEmuType == USB_EMU_FLOPPY_ONLY) || + (DevInfo->bEmuType == USB_EMU_FORCED_FDD)) { + gUsbData->NumberOfFDDs--; + } + + if (DevInfo->bEmuType == USB_EMU_HDD_ONLY) { + gUsbData->NumberOfHDDs--; + } + +// if ( newDev->bPhyDevType == USB_EMU_HDD_OR_FDD ) { + if ( DevInfo->bPhyDevType == USB_MASS_DEV_CDROM ) { + gUsbData->NumberOfCDROMs--; + } + + if (DevInfo->Flag & DEV_INFO_HOTPLUG) { + DevInfo->Flag &= ~DEV_INFO_HOTPLUG; + if (DevInfo == &gUsbData->FddHotplugDev) { + gUsbData->dUSBStateFlag &= ~USB_HOTPLUG_FDD_ENABLED; + } else if (DevInfo == &gUsbData->HddHotplugDev) { + gUsbData->dUSBStateFlag &= ~USB_HOTPLUG_HDD_ENABLED; + } else if (DevInfo == &gUsbData->CdromHotplugDev) { + gUsbData->dUSBStateFlag &= ~USB_HOTPLUG_CDROM_ENABLED; + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassClearMassXactStruc +// +// Description: This function clears the mass transaction structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassClearMassXactStruc( + MASS_XACT_STRUC *MassXactStruc +) +{ + UINT8 i; + UINT8* Cleaner = (UINT8*)MassXactStruc; + + for (i = 0; i < sizeof (MASS_XACT_STRUC); i++ ) { + *Cleaner++ = 0; + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassClearBulkEndpointStall +// +// Description: This function clears the bulk endpoint stall by sending +// CLEAR_FEATURE command to bulk endpoints +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// bDirec Endpoint direction +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassClearBulkEndpointStall( + DEV_INFO* DevInfo, + UINT8 Direc +) +{ + UINT8 Shift; + UINT16 EndPoint; + HC_STRUC *HcStruc; + HCD_HEADER *HcdDriver; + + HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + HcdDriver = &gUsbData->aHCDriverTable[GET_HCD_INDEX(HcStruc->bHCType)]; + + EndPoint = (UINT16)((DevInfo->bBulkInEndpoint) | BIT7); + + if (!(Direc & BIT7)) { + EndPoint = DevInfo->bBulkOutEndpoint; + } + // + // Issue clear port feature command + // + HcdDriver->pfnHCDControlTransfer(HcStruc, DevInfo, (UINT16)ENDPOINT_CLEAR_PORT_FEATURE, + EndPoint,(UINT16)ENDPOINT_HALT, 0, 0); + + //if (HcdDriver->pfnHCDClearEndpointState) { + // HcdDriver->pfnHCDClearEndpointState(HcStruc, DevInfo, (UINT8)EndPoint); + //} else { + + // + // Reset the toggle bit + // + Shift = (EndPoint & 0xF) - 1; + + if (Direc & BIT7) { + DevInfo->wDataInSync &= ~((UINT16)(1 << Shift)); + } else { + DevInfo->wDataOutSync &= ~((UINT16)(1 << Shift)); + } + + if (DevInfo->fpLUN0DevInfoPtr == NULL) { + return; + } + + if (Direc & BIT7) { + DevInfo->fpLUN0DevInfoPtr->wDataInSync &= ~((UINT16)(1 << Shift)); + } else { + DevInfo->fpLUN0DevInfoPtr->wDataOutSync &= ~((UINT16)(1 << Shift)); + } + //} + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassIssueMassTransaction +// +// Description: This function performs a mass storage transaction by +// invoking proper transaction protocol. +// +// Input: Pointer to DeviceInfo structure +// stMassXactStruc +// pCmdBuffer Pointer to command buffer +// bCmdSize Size of command block +// bXferDir Transfer direction +// fpBuffer Data buffer far pointer +// dwLength Amount of data to be transferred +// wPreSkip Number of bytes to skip before data +// wPostSkip Number of bytes to skip after data +// +// Output: Amount of data actually transferred +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT32 +USBMassIssueMassTransaction( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + UINT32 DataLength; + HC_STRUC *HcStruc; + + if ((DevInfo->bProtocol == PROTOCOL_CBI) || + (DevInfo->bProtocol == PROTOCOL_CBI_NO_INT)) { + return USBMassIssueCBITransaction(DevInfo, MassXactStruc); + } + + if (DevInfo->bProtocol == PROTOCOL_BOT) { + + // Block to process periodic list to prevent that we might send the wrong + // command sequences to the same device. + gUsbData->ProcessingPeriodicList = FALSE; + + DataLength = USBMassIssueBOTTransaction(DevInfo, MassXactStruc); + + // To process any pending periodic list. + gUsbData->ProcessingPeriodicList = TRUE; + HcStruc = gUsbData->HcTable[DevInfo->bHCNumber - 1]; + (*gUsbData->aHCDriverTable + [GET_HCD_INDEX(HcStruc->bHCType)].pfnHCDProcessInterrupt)(HcStruc); + + return DataLength; + } + + return 0; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetDeviceParameters +// +// Description: This function gets the USB mass device parameters such as +// max cylinder, head, sector, block size and +// +// Input: Pointer to DeviceInfo structure +// +// Output: Pointer to the temp buffer, NULL on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +MASS_INQUIRY* +USBMassGetDeviceParameters( + DEV_INFO* DevInfo +) +{ + MASS_INQUIRY *Inq; + UINT8 i; + + for (i = 0; i < 2; i++) { + Inq = USBMassInquiryCommand(DevInfo); + if (Inq) { + break; + } + if (!(gUsbData->bLastCommandStatus & USB_BULK_STALLED)) { + break; + } + } + + //USB_DEBUG(DEBUG_LEVEL_3, "fpMassInquiry = %x\n", Inq); + + if (!Inq) { + return NULL; + } + + DevInfo->wBlockSize = 0xFFFF; // Clear the cached block size + + // + // Find the device type and update the device type structure accordingly + // + USBMassIdentifyDeviceType(DevInfo, (UINT8*)Inq); + + return Inq; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ValidateDeviceName +// +// Description: This procedure check whether device return valid device name +// if no valid device name returned, assign default name for it +// +// Input: Inquiry Data +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID ValidateDeviceName ( + MASS_INQUIRY *InqData +) +{ + static UINT8 DefaultName[] = "USB Storage Device"; + UINT8 *Name = ((UINT8*)InqData) + 8; + UINT8 *DefName = DefaultName; + UINT8 Count; + + // check for a blank name + if (*Name) return; + +// for (Count = 0; Count < 28; Count++) { +// if (*(Name + Count)) return; // Not blank +// } + + // copy default name + for (Count = 0; Count < sizeof(DefaultName); Count++) { + *(Name + Count) = *(DefName + Count); + } +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetDeviceInfo +// +// Description: This function fills and returns the mass get device info +// structure +// +// Input: fpMassGetDevInfo Pointer to the mass get info struc +// bDevAddr USB device address of the device +// +// Output: USB_SUCCESS or USB_ERROR +// fpMassGetDevInfo Pointer to the mass get info struc +// dSenseData Sense data of the last command +// bDevType Device type byte (HDD, CD, Removable) +// bEmuType Emulation type used +// fpDevId Far pointer to the device ID +// +// Notes: Initially the bDevAddr should be set to 0 as input. This +// function returns the information regarding the first mass +// storage device (if no device found it returns bDevAddr as +// 0FFh) and also updates bDevAddr to the device address of +// the current mass storage device. If no other mass storage +// device is found then the routine sets the bit7 to 1 +// indicating current information is valid but no more mass +// device found in the system. The caller can get the next +// device info if bDevAddr is not 0FFh and bit7 is not set +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetDeviceInfo ( + MASS_GET_DEV_INFO *MassGetDevInfo +) +{ + DEV_INFO *DevInfo; + MASS_INQUIRY *MassInq; + UINT8 Dev = MassGetDevInfo->bDevAddr; + + // + // Get the total number of Mass Storage Devices + // + MassGetDevInfo->bTotalMassDev = (UINT8)(UINTN)USB_GetDeviceInfoStruc(USB_SRCH_DEV_NUM, + 0, BIOS_DEV_TYPE_STORAGE, 0); + + if (Dev == 0) { + iPodShufflePatch(MassGetDevInfo); + } + + if (Dev & BIT7) { + return USB_ERROR; // Check for device address validity + } + + // + // If bDev = 0 then get information about first mass storage device + // + if (!Dev) { + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_TYPE, 0, BIOS_DEV_TYPE_STORAGE, 0); + //USB_DEBUG(DEBUG_LEVEL_3, "Get Mass0 info: %x\n", DevInfo); + + if (!DevInfo) { // Set as no more device found + MassGetDevInfo->bDevAddr = 0xFF; + return USB_SUCCESS; + } + } else { // Not the first mass device + // + // Get the device info structure for the matching device index + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, Dev, 0); + ASSERT(DevInfo); + if ( (!DevInfo) || (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT)) ) { // Error + return USB_ERROR; + } + // + // Get device info structure for next device + // + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_TYPE, DevInfo, BIOS_DEV_TYPE_STORAGE, 0); + ASSERT(DevInfo); + if (!DevInfo) { // Error. Exit ! + return USB_ERROR; + } + } + MassInq = USBMassGetDeviceParameters(DevInfo); + + if (!MassInq) { + return USB_ERROR; + } + + MassGetDevInfo->bDevType = DevInfo->bPhyDevType; +// MassGetDevInfo->bPhyDevType = fpDevInfo->bPhyDevType; + MassGetDevInfo->bEmuType = DevInfo->bEmuType; + MassGetDevInfo->wPciInfo = + gUsbData->HcTable[DevInfo->bHCNumber - 1]->wBusDevFuncNum; + MassGetDevInfo->fpDevId = (UINT32)(UINTN)((UINT8*)MassInq + 8); +// MassGetDevInfo->fpDevId = USBMassAdjustIdString((UINT32)MassInq + 8); + + Dev = (UINT8)(UINTN)USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, DevInfo, 0, 0); + ASSERT(Dev); + + Dev |= BIT7; // Assume that no more mass device present + + // + // Check whether more mass device is present + // + if (USB_GetDeviceInfoStruc(USB_SRCH_DEV_TYPE, DevInfo, BIOS_DEV_TYPE_STORAGE, 0)) { + Dev &= ~BIT7; + } + + DevInfo->Flag |= DEV_INFO_MASS_DEV_REGD; + MassGetDevInfo->bDevAddr = Dev; + + *(UINTN*)MassGetDevInfo->Handle = *(UINTN*)DevInfo->Handle; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: iPodShufflePatch +// +// Description: This check whether iPod shuffle attached to system and move +// iPod shuffle to first initial device. +// +// Input: Pointer to the mass get info struc +// +// Output: None +// +// Notes: Attaching iPod shuffle and iPod mini to system causes BIOS POST +// stop. iPod shuffle must be initialized as early as possible. +// iPod mini cosumes about 2 seconds to complete initialization, +// init iPod shuffle first to fix problem. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +iPodShufflePatch( + MASS_GET_DEV_INFO *MassGetDevInfo +) +{ + //TO BE IMPLEMENTED +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetDeviceStatus +// +// Description: Get USB MassStorage device status. Include Media Informarion. +// Refer to USB_MASS_MEDIA_XXX in USBDEF.H +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR or USB_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetDeviceStatus ( + MASS_GET_DEV_STATUS *MassGetDevSts +) +{ + DEV_INFO* DevInfo; + UINT8 DevAddr = MassGetDevSts->bDevAddr; + UINT8 LastStatus; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + + ASSERT(DevInfo != NULL); + if (DevInfo == NULL) { + return USB_ERROR; + } + + LastStatus= DevInfo->bLastStatus; + + USBMassCheckDeviceReady(DevInfo); + + // When the Media is not present in the drive and insert the Media + // it's just sends the status as Media Present. So check the last status + // and if the media not present and current stauts is media present + // report it as Media changed + if ((LastStatus ^ DevInfo->bLastStatus) & USB_MASS_MEDIA_PRESENT) { + // Report the Last Status along with Media Changed status + DevInfo->bLastStatus |= USB_MASS_MEDIA_CHANGED; + } + + MassGetDevSts->bDeviceStatus = DevInfo->bLastStatus; + + if (DevInfo->bLastStatus & USB_MASS_MEDIA_CHANGED) { + // + // Clear Media Change Status. + // + DevInfo->bLastStatus &= (UINT8)(~USB_MASS_MEDIA_CHANGED); + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassCmdPassThru +// +// Description: This function issues the command/data sequence provided +// as input. This function can be used to send raw data +// to the USB mass storage device +// +// Input: fpDevInfo Pointer to Device Info structure +// fpMassCmdPassThru Pointer to the mass command pass +// through structure +// bDevAddr USB device address of the device +// dSenseData Sense data of the last command +// fpCmdBuffer Far pointer to the command buffer +// wCmdLength Command length +// fpDataBuffer Far pointer for data buffer +// wDataLength Data length +// bXferDir Data transfer direction +// +// Output: USB_SUCCESS or USB_ERROR +// dSenseData Sense data of the last command +// fpDataBuffer Updated with returned data if the transfer +// is an IN transaction +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassCmdPassThru ( + MASS_CMD_PASS_THRU *MassCmdPassThru +) +{ + UINT8 *CmdBuffer; + UINT8 *Src; + UINT8 *Dst; + DEV_INFO *DevInfo; +// UINT8 CommandRetried = FALSE; + UINT8 CmdBlkSize; + UINT8 Count; + UINT16 Data16; + UINT32 Data32; + UINT8 DevAddr = MassCmdPassThru->bDevAddr; + MASS_XACT_STRUC MassXactStruc; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + if ( (!DevInfo) || (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT)) ) { // Error + return USB_ERROR; + } + + CmdBlkSize = (UINT8)((MassCmdPassThru->wCmdLength + + USB_MEM_BLK_SIZE - 1) >> USB_MEM_BLK_SIZE_SHIFT); + + // + // Check whether the drive is ready for read TOC command + // + USBMassCheckDeviceReady(DevInfo); + + // + // Allocate memory for the command buffer + // + CmdBuffer = USB_MemAlloc((UINT8)GET_MEM_BLK_COUNT(CmdBlkSize)); + if (!CmdBuffer) { + return USB_ERROR; + } + + // + // Copy the command into (just allocated) mass command buffer + // + Src = (UINT8*)(UINTN)MassCmdPassThru->fpCmdBuffer; + Dst = CmdBuffer; + for (Count = 0; Count < MassCmdPassThru->wCmdLength; Count++) { + *Dst++ = *Src++; + } + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = CmdBuffer; + MassXactStruc.bCmdSize = (UINT8)MassCmdPassThru->wCmdLength; + MassXactStruc.bXferDir = MassCmdPassThru->bXferDir; + MassXactStruc.fpBuffer = (UINT8*)(UINTN)MassCmdPassThru->fpDataBuffer; + MassXactStruc.dLength = (UINT32)MassCmdPassThru->wDataLength; + + Data16 = (UINT16)USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + // + // Update the actual data length processed/returned + // + MassCmdPassThru->wDataLength = Data16; + + Data32 = USBMassRequestSense (DevInfo); + + MassCmdPassThru->dSenseData = Data32; + + // + // Check and free command buffer + // + if (!CmdBuffer) { + return USB_ERROR; + } + + USB_MemFree(CmdBuffer, (UINT16)GET_MEM_BLK_COUNT(CmdBlkSize)); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassReadCapacity16Command +// +// Description: This function issues read capacity of the mass storage +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR or USB_SUCCESS +// +// Notes: This routine will update the MassDeviceInfo structure +// with the block size & last LBA values obtained from the +// device +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassReadCapacity16Command ( + DEV_INFO* DevInfo +) +{ + UINT32 Data; + COMN_READ_CAPACITY_16_CMD *CmdBuffer; + MASS_XACT_STRUC MassXactStruc; + + if (!VALID_DEVINFO(DevInfo)) { + return USB_ERROR; + } + // + // Allocate memory for the command buffer + // + CmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_16_CMD)); + + if (!CmdBuffer) { + return USB_ERROR; + } + + CmdBuffer->OpCode = COMMON_READ_CAPACITY_16_OPCODE; + CmdBuffer->ServiceAction = 0x10; + CmdBuffer->AllocLength = 0x0C000000; + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + + // + // Change the bulk transfer delay to 10 seconds (For CDROM drives) + // + gUsbData->wBulkDataXferDelay = 10000; + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + + MassXactStruc.bCmdSize = sizeof(COMN_RWV_16_CMD); + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = gUsbData->fpUSBTempBuffer; + MassXactStruc.dLength = 0xC; + + USB_DEBUG (DEBUG_LEVEL_3, "rcc.."); + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + // + // Reset the delay back + // + gUsbData->wBulkDataXferDelay = 0; + + if (!Data) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_16_CMD)); + + USB_DEBUG (DEBUG_LEVEL_3, "err "); + return USB_ERROR; + } + + Data = *((UINT32*)(gUsbData->fpUSBTempBuffer + 8)); + + // + // Change little endian format to big endian(INTEL) format + // + Data = dabc_to_abcd(Data); + //(EIP37167+)> + if (!Data) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_16_CMD)); + USB_DEBUG (DEBUG_LEVEL_3, "err "); + return USB_ERROR; + } + + DevInfo->wBlockSize = (UINT16)Data; + + USB_DEBUG(3,"BlockSize %x\n", DevInfo->wBlockSize); + + // + // Store the last LBA number in the mass info structure + // + Data = *((UINT32*)(gUsbData->fpUSBTempBuffer)); + + Data = dabc_to_abcd(Data); + + DevInfo->MaxLba = Shl64(Data, 32); + + Data = *((UINT32*)(gUsbData->fpUSBTempBuffer + 4)); + + Data = dabc_to_abcd(Data); + + DevInfo->MaxLba |= Data; + + USB_DEBUG(3,"MaxLba %lx\n", DevInfo->MaxLba); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassReadCapacity10Command +// +// Description: This function issues read capacity of the mass storage +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR or USB_SUCCESS +// +// Notes: This routine will update the MassDeviceInfo structure +// with the block size & last LBA values obtained from the +// device +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassReadCapacity10Command ( + DEV_INFO* DevInfo +) +{ + UINT32 Data; + COMN_READ_CAPACITY_10_CMD *CmdBuffer; + MASS_XACT_STRUC MassXactStruc; + + if (!VALID_DEVINFO(DevInfo)) { + return USB_ERROR; + } + + if (Shr64(DevInfo->MaxLba, 32)) { + USBMassReadCapacity16Command(DevInfo); + return USB_SUCCESS; + } + // + // Allocate memory for the command buffer + // + CmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + + if (!CmdBuffer) { + return USB_ERROR; + } + + CmdBuffer->bOpCode = COMMON_READ_CAPACITY_10_OPCODE; + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + + // + // Change the bulk transfer delay to 10 seconds (For CDROM drives) + // + gUsbData->wBulkDataXferDelay = 10000; + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + //(EIP51158+)> + if (DevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x0A; //SBC-3_66 + } else { + MassXactStruc.bCmdSize = sizeof (COMN_READ_CAPACITY_10_CMD); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = gUsbData->fpUSBTempBuffer; + MassXactStruc.dLength = 8; + + USB_DEBUG (DEBUG_LEVEL_3, "rcc.."); + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + // + // Reset the delay back + // + gUsbData->wBulkDataXferDelay = 0; + + if (!Data) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + USB_DEBUG (DEBUG_LEVEL_3, "err "); + return USB_ERROR; + } + + USB_DEBUG(3,"Read Capacity 10 LBA %x\n", *(UINT32*)gUsbData->fpUSBTempBuffer); + + if (*(UINT32*)gUsbData->fpUSBTempBuffer == 0xFFFFFFFF) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + USBMassReadCapacity16Command(DevInfo); + return USB_SUCCESS; + } + + Data = *((UINT32*)(gUsbData->fpUSBTempBuffer + 4)); + + // + // Change little endian format to big endian(INTEL) format + // + Data = dabc_to_abcd(Data); + //(EIP37167+)> + if (!Data) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + USB_DEBUG(DEBUG_LEVEL_3, "err "); + return USB_ERROR; + } + //<(EIP37167+) + + DevInfo->wBlockSize = (UINT16)Data; +//USB_DEBUG(DEBUG_LEVEL_3, "succ: %x, %x\n", dData, fpDevInfo); + // + // Store the last LBA number in the mass info structure + // + Data = *((UINT32*)(gUsbData->fpUSBTempBuffer)); + + Data = dabc_to_abcd(Data); + + if (!Data) { + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + USB_DEBUG (DEBUG_LEVEL_3, "err "); + return USB_ERROR; + } + + DevInfo->MaxLba = Data + 1; // 1-based value + + USB_DEBUG(DEBUG_LEVEL_3, "%x ", DevInfo->MaxLba); + + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_CAPACITY_10_CMD)); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassReadFormatCapacity +// +// Description: This function sends read format capacity command to the USB +// mass storage device +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR or USB_SUCCESS +// +// Notes: This routine will update the MassDeviceInfo structure +// with the block size & last LBA values obtained from the +// device +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassReadFormatCapacity (DEV_INFO* fpDevInfo) +{ + COMN_READ_FMT_CAPACITY *fpCmdBuffer; + UINT32 dData; + UINT16 wData; + UINT8* DataBuffer; + UINT16 DataBufferSize = 0xFC; + MASS_XACT_STRUC MassXactStruc; + + // + // Allocate memory for the command buffer + // + fpCmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + + if(!fpCmdBuffer) { + return USB_ERROR; + } + + DataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(DataBufferSize)); + if (DataBuffer == NULL) { + return USB_ERROR; + } + + fpCmdBuffer->bOpCode = COMMON_READ_FORMAT_CAPACITY_OPCODE; + fpCmdBuffer->wAllocLength = (UINT16)((DataBufferSize << 8) + (DataBufferSize >> 8)); + + USBMassClearMassXactStruc(&MassXactStruc); // Clear the common bulk transaction structure + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)fpCmdBuffer; + //(EIP51158+)> + if (fpDevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x0A; + } else { + MassXactStruc.bCmdSize = sizeof (COMN_READ_FMT_CAPACITY); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = DataBuffer; +// MassXactStruc.dLength = MAX_TEMP_BUFFER_SIZE; +// +// Temp buffer 40h-64h was used as device name string buffer. +// Limit Transaction size to 40h to prevent name string display problem. +// + MassXactStruc.dLength = DataBufferSize; + +USB_DEBUG (DEBUG_LEVEL_5, "Issue ReadFormatCapacityCommand .... \n"); + + dData = USBMassIssueMassTransaction(fpDevInfo, &MassXactStruc); + + // + // The amount of data obtained should be atleast of read format capacity structure size + // + if (dData < sizeof (COMN_READ_FMT_CAPACITY)) { + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + return USB_ERROR; + } + + + if ((DataBuffer[0] != 0) || (DataBuffer[1] != 0) || (DataBuffer[2] != 0) || (DataBuffer[3] < 0x08)) { + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + return USB_ERROR; + } + + wData = *((UINT16*)(DataBuffer + 10)); // Offset 10 + if (wData == 0) { + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + return USB_ERROR; + } + fpDevInfo->wBlockSize = (UINT16)((wData << 8) + (wData >> 8)); + + dData = *((UINT32*)(DataBuffer + 4)); // Offset 4 + if (dData == 0) { + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + return USB_ERROR; + } + dData = dabc_to_abcd(dData); + fpDevInfo->MaxLba = dData; + + if (dData == USB_144MB_FDD_MAX_LBA) { + // + // Return parameters for 1.44MB floppy + // + fpDevInfo->Heads = USB_144MB_FDD_MAX_HEADS; + fpDevInfo->NonLBAHeads = USB_144MB_FDD_MAX_HEADS; + fpDevInfo->bSectors = USB_144MB_FDD_MAX_SECTORS; + fpDevInfo->bNonLBASectors = USB_144MB_FDD_MAX_SECTORS; + fpDevInfo->wCylinders = USB_144MB_FDD_MAX_CYLINDERS; + fpDevInfo->wNonLBACylinders = USB_144MB_FDD_MAX_CYLINDERS; + fpDevInfo->bMediaType = USB_144MB_FDD_MEDIA_TYPE; + } + + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_READ_FMT_CAPACITY)); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetConfiguration +// +// Description: This function sends get configuration command to the USB +// mass storage device +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR or USB_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetConfiguration( + DEV_INFO* DevInfo +) +{ + COMMON_GET_CONFIGURATION *CmdBuffer; + UINT32 Data; + UINT8 *DataBuffer; + UINT16 DataBufferSize = 0x8; + MASS_XACT_STRUC MassXactStruc; + + // + // Allocate memory for the command buffer + // + CmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMMON_GET_CONFIGURATION)); + + if (!CmdBuffer) { + return USB_ERROR; + } + + DataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(DataBufferSize)); + if (DataBuffer == NULL) { + return USB_ERROR; + } + + CmdBuffer->OpCode = COMMON_GET_CONFIGURATION_OPCODE; + CmdBuffer->AllocLength = (UINT16)((DataBufferSize << 8) + (DataBufferSize >> 8)); + + USBMassClearMassXactStruc(&MassXactStruc); // Clear the common bulk transaction structure + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + MassXactStruc.bCmdSize = sizeof (COMMON_GET_CONFIGURATION); + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = DataBuffer; + + MassXactStruc.dLength = DataBufferSize; + + USB_DEBUG(DEBUG_LEVEL_5, "Issue GetConfigurationCommand .... \n"); + + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + USB_MemFree(DataBuffer, GET_MEM_BLK_COUNT(DataBufferSize)); + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMMON_GET_CONFIGURATION)); + + if (Data) { + return USB_SUCCESS; + } else { + return USB_ERROR; + } + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassReadSector +// +// Description: This function a sector at the LBA specified +// +// Input: Pointer to DeviceInfo structure +// LBA to read +// DS:DI Data buffer pointer +// +// Output: USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassReadSector( + DEV_INFO* DevInfo, + UINT32 Lba, + UINT8* Buffer +) +{ + COMN_RWV_10_CMD *CmdBuffer; + UINT32 Data; + UINT8 Counter; + UINT8 RetValue = USB_ERROR; + MASS_XACT_STRUC MassXactStruc; + + // + // Allocate memory for the command buffer + // + CmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_RWV_10_CMD)); + + if (!CmdBuffer) { + return USB_ERROR; + } + + USBMassClearMassXactStruc(&MassXactStruc); + + Counter = 10; + do { + // + // Set opcode to read command + // + CmdBuffer->bOpCode = COMMON_READ_10_OPCODE; + CmdBuffer->wTransferLength = 0x100; // Big endian to little endian: 0x0001 -> 0x0100 + Data = Lba; + // + // Change LBA from big endian to little endian + // + Data = dabc_to_abcd(Data); + + CmdBuffer->dLba = Data; + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + //(EIP51158+)> + if (DevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x0A; //SBC-3_60 + } else { + MassXactStruc.bCmdSize = sizeof (COMN_RWV_10_CMD); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = Buffer; + MassXactStruc.dLength = DevInfo->wBlockSize; //(EIP59738) + MassXactStruc.wPreSkip = 0; + MassXactStruc.wPostSkip= 0; + + USB_DEBUG (DEBUG_LEVEL_5, "Read Sector .... \n"); + + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + if(Data) { + RetValue = USB_SUCCESS; + break; // Success + } + // + // May be drive error. Try to correct from it ! + // Check whether the drive is ready for read/write/verify command + // + Data = USBMassCheckDeviceReady(DevInfo); + if (Data) { // Device is not ready. + RetValue = USB_ERROR; + break; + } + MemFill((UINT8*)CmdBuffer, sizeof(COMN_RWV_10_CMD), 0); + } while (Counter--); + + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_RWV_10_CMD)); + + return RetValue; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassUpdateCHSFromBootRecord +// +// Description: This function parses the boot record and extract the CHS +// information of the formatted media from the boot record. +// This routine checks for DOS & NTFS formats only +// +// Input: Pointer to DeviceInfo structure +// Maximum LBA in the device +// Boot record of the device +// +// Output: USB_ERROR If the boot record is un-recognizable and CHS info +// is not extracted +// USB_SUCCESS If the boot record is recognizable and CHS info +// is extracted. CHS information is updated in the +// mass device info structure +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassUpdateCHSFromBootRecord( + DEV_INFO *DevInfo, + UINT64 MaxLba, + BOOT_SECTOR *BootSetor +) +{ + UINT32 OemName = 0; + UINT32 Fat16SysType = 0; + UINT32 Fat32SysType = 0; + + if (BootSetor->Signature != 0xAA55) { + return USB_ERROR; + } + + // + // Check for valid MSDOS/MSWIN/NTFS boot record + // + MemCopy((UINT8*)BootSetor->OEMName, (UINT8*)&OemName, sizeof(OemName)); + if ((OemName != 0x4F44534D) && // "ODSM", MSDO... + (OemName != 0x4957534D) && // "IWSM", MSWI... + (OemName != 0x5346544E)) { // "SFTN", NTFS + // + // Check for valid FAT,FAT16 or FAT32 boot records + // + BootSetor->Fat.Fat16.FilSysType[3] = 0x20; + MemCopy((UINT8*)BootSetor->Fat.Fat16.FilSysType, (UINT8*)&Fat16SysType, + sizeof(Fat16SysType)); + MemCopy((UINT8*)BootSetor->Fat.Fat32.FilSysType, (UINT8*)&Fat32SysType, + sizeof(Fat32SysType)); + if ((Fat16SysType != 0x20544146) && // " TAF", FAT + (Fat32SysType != 0x33544146)) { // "3TAF", FAT3 + + // + // None of the conditions met - boot record is invalid. Return with error + // + return USB_ERROR; + } + } + + // zero check added to prevent invalid sector/head information in BPB + if (BootSetor->SecPerTrk == 0) { + return USB_ERROR; + } + + DevInfo->bSectors = (UINT8)BootSetor->SecPerTrk; + DevInfo->bNonLBASectors = (UINT8)BootSetor->SecPerTrk; + + // Wrong BPB in MSI MegaStick 128; this is preformat usility issue, wrong BPB + // information built in device. + if (BootSetor->NumHeads == 0) { + return USB_ERROR; + } + + DevInfo->Heads = BootSetor->NumHeads; + DevInfo->NonLBAHeads = BootSetor->NumHeads; + DevInfo->BpbMediaDesc = BootSetor->Media; + + USBMassUpdateCylinderInfo(DevInfo, MaxLba); + + USB_DEBUG (DEBUG_LEVEL_4, "CHS: %x %x %x\n", + DevInfo->bSectors, + DevInfo->Heads, + DevInfo->wCylinders); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassUpdateCylinderInfo +// +// Description: This procedure update cylinder parameter for device geometry. +// head and sector paramaters are required before invoke this +// function. +// +// Input: Pointer to DeviceInfo structure +// Maximum LBA in the device +// dev->bHeads +// dev->bSectors +// +// Output: None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassUpdateCylinderInfo( + DEV_INFO* Dev, + UINT64 Lba +) +{ + UINT64 Data; + + if ((Dev->bSectors != 0) && (Dev->Heads != 0)) { + Data = Div64(Lba, (Dev->bSectors * Dev->Heads), NULL); + } else { + Data = 0; + } + + if (Data <= 1) { + Data++; + } + if (Data > 0xFFFF) { + Data = 0xFFFF; // DOS workaround + } + Dev->wCylinders = (UINT16)Data; + Dev->wNonLBACylinders = (UINT16)Data; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetFormatType +// +// Description: This function reads the first sector from the mass storage +// device and identifies the formatted type. +// +// Input: Pointer to DeviceInfo structure +// Maximum LBA of the device +// +// Output: USB_ERROR If could not identify the formatted type +// USB_SUCCESS If formatted type is identified +// MSB of emu - Emulation type +// LSB of emu - Device type (Floppy, Harddisk or CDROM) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetFormatType( + DEV_INFO* DevInfo, + UINT64 MaxLba, + UINT16 *Emu +) +{ + + MBR_PARTITION Partition = {0}; + + // + // Read the first sector of the device + // + if (USBMassReadSector(DevInfo, 0, gUsbData->fpUSBMassConsumeBuffer) == USB_ERROR) { + return USB_ERROR; + } + + DevInfo->bHiddenSectors = 0; + + // + // Check for validity of the partition table/boot record + // + if (*((UINT16*)(gUsbData->fpUSBMassConsumeBuffer + 0x1FE)) != 0xAA55) { + USBMassSetDefaultGeometry(DevInfo, MaxLba); + return USB_ERROR; + } + + if (USBMassValidatePartitionTable((MASTER_BOOT_RECORD*)gUsbData->fpUSBMassConsumeBuffer, + MaxLba, &Partition) == USB_SUCCESS) { + // + // Only one partition present, check the device size, if the device size + // is less than 530 MB assume FDD or else assume the emulation as HDD + // + + //if (((MaxLba >> 11) < MAX_SIZE_FOR_USB_FLOPPY_EMULATION) && //(EIP80382) + // !(gUsbData->dUSBStateFlag & USB_FLAG_MASS_NATIVE_EMULATION)) { + // emu_ = (UINT16)(USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + //}else { + // emu_ = (UINT16)(USB_EMU_HDD_ONLY << 8) + USB_MASS_DEV_HDD; + //} + // + // Read boot sector, set the LBA number to boot record LBA number + // + DevInfo->bHiddenSectors = Partition.StartingLba; + + if (USBMassReadSector(DevInfo, Partition.StartingLba, + gUsbData->fpUSBMassConsumeBuffer) == USB_ERROR) { + return USB_ERROR; + } + + if (USBMassUpdateCHSFromBootRecord(DevInfo, MaxLba, + (BOOT_SECTOR*)gUsbData->fpUSBMassConsumeBuffer) == USB_SUCCESS) { + if (((Shr64(MaxLba, 11)) < MAX_SIZE_FOR_USB_FLOPPY_EMULATION) && + !(gUsbData->dUSBStateFlag & USB_FLAG_MASS_NATIVE_EMULATION)) { + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + *Emu = (UINT16)(USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + } + } + return USB_SUCCESS; + } else { // Reset hidden sector value and return HDD emulation + USBMassSetDefaultGeometry(DevInfo, MaxLba); + DevInfo->bHiddenSectors = 0; + //(EIP43711)> + //don't emulate as HDD for UFI class even media has valid partition like HDD + if (gUsbData->dUSBStateFlag & USB_FLAG_MASS_SIZE_EMULATION) { + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + if ((Shr64(MaxLba, 11)) < MAX_SIZE_FOR_USB_FLOPPY_EMULATION) { + *Emu = (UINT16)(USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + } + } + } + //<(EIP43711) + return USB_SUCCESS; + } + } + + *Emu = USBMassSetDefaultType(DevInfo, MaxLba); + + if (USBMassUpdateCHSFromBootRecord(DevInfo, MaxLba, + (BOOT_SECTOR*)gUsbData->fpUSBMassConsumeBuffer) == USB_SUCCESS) { + //*emu = USBMassSetDefaultType(fpDevInfo, MaxLba); + if (gUsbData->dUSBStateFlag & USB_FLAG_MASS_SIZE_EMULATION) { + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + if ((Shr64(MaxLba, 11)) >= MAX_SIZE_FOR_USB_FLOPPY_EMULATION) { + *Emu = (UINT16)(USB_EMU_HDD_ONLY << 8) + USB_MASS_DEV_HDD; + } + } + } + return USB_SUCCESS; + } + USBMassSetDefaultGeometry(DevInfo, MaxLba); + + //*emu = USBMassSetDefaultType(fpDevInfo, MaxLba); + + if (((Shr64(MaxLba, 11)) >= MAX_SIZE_FOR_USB_FLOPPY_EMULATION) && + !(gUsbData->dUSBStateFlag & USB_FLAG_MASS_NATIVE_EMULATION)) { + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + *Emu = (UINT16)(USB_EMU_HDD_ONLY << 8) + USB_MASS_DEV_HDD; + } + DevInfo->bHiddenSectors = 0; + } + //*emu = emu_; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassSetDefaultType +// +// Description: This procedure set device type depend on device class. +// +// Input: Pointer to DeviceInfo structure +// Maximum LBA in the device (DWORD) +// +// Output: Device Type (WORD) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassSetDefaultType( + DEV_INFO* Dev, + UINT64 Lba +) +{ + UINT16 DevType = (UINT16)(USB_EMU_FLOPPY_ONLY << 8) + USB_MASS_DEV_ARMD; + + if (Dev->bSubClass != SUB_CLASS_UFI) { // Check whether UFI class device + // Assume force FDD emulation for non-UFI class device + DevType = (UINT16)(USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + } + return DevType; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassValidatePartitionTable +// +// Description: This procedure check whether partition table valid. +// +// Input: Partition table content +// Maximum LBA in the device +// +// Output: USB_SUCCESS - partion table is valid: +// Possible valid entry count(1-based) +// Table entry counts(0-based, 4 means all entries scaned) +// Activate entry offset(Absolute offset) +// USB_ERROR - Invalid partition table +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassValidatePartitionTable( + IN MASTER_BOOT_RECORD *Mbr, + IN UINT64 Lba, + OUT MBR_PARTITION *Partition) +{ + UINT8 Index = 0; + UINT8 ActivateIndex = 0; + + // The partition table area could be all 0's, and it would pass the below tests, + // So test for that here (test sector count for all partitions). + if ((Mbr->PartRec[0].SizeInLba == 0) && + (Mbr->PartRec[1].SizeInLba == 0) && + (Mbr->PartRec[2].SizeInLba == 0) && + (Mbr->PartRec[3].SizeInLba == 0)) { + return USB_ERROR; + } + + for (Index = 0; Index < 4; Index++) { + // Boot flag check added to ensure that boot sector will not be treated as + // a valid partation table. + if (Mbr->PartRec[Index].BootIndicator & 0x7F) { + return USB_ERROR; // BootFlag should be 0x0 or 0x80 + } + + // Check whether beginning LBA is reasonable + if (Mbr->PartRec[Index].StartingLba > Lba) { + return USB_ERROR; + } + + // Check whether the size is reasonable +#if HDD_PART_SIZE_CHECK + if (Mbr->PartRec[Index].SizeInLba > Lba) { + return USB_ERROR; + } +#endif + // Update activate entry offset + if (!(Mbr->PartRec[Index].BootIndicator & 0x80)) { + continue; + } + + ActivateIndex = Index; + } + + // If no activate partition table entry found use first entry + MemCopy((UINT8*)&Mbr->PartRec[ActivateIndex], (UINT8*)Partition, + sizeof(MBR_PARTITION)); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassSetDefaultGeometry +// +// Description: This procedure set default geometry for mass storage devices. +// +// Input: Pointer to DeviceInfo structure +// Maximum LBA in the device +// +// Output: USB_ERROR If could not identify the formatted type +// USB_SUCCESS If formatted type is identified +// Emulation type - bits 8..15 +// Device type (Floppy, Harddisk or CDROM) - bits 0..7 +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 USBMassSetDefaultGeometry(DEV_INFO* dev, UINT64 lba) +{ + if (dev->bSubClass == SUB_CLASS_UFI) { + dev->Heads = 0x02; + dev->NonLBAHeads = 0x02; + dev->bSectors = 0x12; + dev->bNonLBASectors = 0x12; + } + else { + dev->bSectors = 0x3F; + dev->bNonLBASectors = 0x3F; +// Use default heads that results in 1023 (3FF) cylinders or less for CHS + if (lba <= 0x1F7820) { + dev->Heads = 0x20; + dev->NonLBAHeads = 0x20; + } + else if ( (lba > 0x1F7820) && (lba <= 0x3EF040) ) { + dev->Heads = 0x40; + dev->NonLBAHeads = 0x40; + } + else if ( (lba > 0x3EF040) && (lba <= 0x7DE080) ) { + dev->Heads = 0x80; + dev->NonLBAHeads = 0x80; + } + else if (lba > 0x7DE080) { + dev->Heads = 0xFF; + dev->NonLBAHeads = 0xFF; + } + } + + USBMassUpdateCylinderInfo(dev, lba); + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassIdentifyDeviceType +// +// Description: This function identifies the type of the USB mass storage +// device attached from the INQUIRY data obtained from the drive +// +// Input: Pointer to DeviceInfo structure +// Pointer to the inquiry data (read from device) +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassIdentifyDeviceType( + DEV_INFO* DevInfo, + UINT8* InqData +) +{ + UINT16 EmulationType; + UINT16 ForceEmulationType = 0; + UINT32 Data = 0; + UINT8 Count; + static UINT16 UsbMassEmulationTypeTable[5] = { + 0, // Auto + (USB_EMU_FLOPPY_ONLY << 8) + USB_MASS_DEV_ARMD, // Floppy + (USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD, // Forced floppy + (USB_EMU_HDD_ONLY << 8) + USB_MASS_DEV_HDD, // HDD + (USB_EMU_HDD_OR_FDD << 8) + USB_MASS_DEV_CDROM }; // CDROM + + USBMassGetPhysicalDeviceType(DevInfo, InqData); + + // Note: at this point we assume that dev->wEmulationOption is filled in + // according to the setup question selection. + if (!(DevInfo->Flag & DEV_INFO_HOTPLUG) || DevInfo->wEmulationOption) { // not auto + EmulationType = UsbMassEmulationTypeTable[DevInfo->wEmulationOption]; + ForceEmulationType = UsbMassEmulationTypeTable[DevInfo->wEmulationOption]; + } + + //USB_DEBUG(DEBUG_LEVEL_3, ">>-- IdentifyDeviceType:: Device #%d, Emul#: %d, Emul: %x\n", + // DevInfo->bDeviceAddress, DevInfo->wEmulationOption, EmulationType); +#if USB_STORAGE_DEVICE_RMB_CHECK + if (*(InqData + 1) & 0x80) { // Check RMB status + DevInfo->bLastStatus |= USB_MASS_MEDIA_REMOVEABLE; + } +#else + DevInfo->bLastStatus |= USB_MASS_MEDIA_REMOVEABLE; +#endif + DevInfo->bLastStatus |= USB_MASS_MEDIA_PRESENT; // Assume Media Present + + if (*InqData == 5) { // CDROM + // Set the type as CDROM and emulation as HDD or FDD + DevInfo->wBlockSize = 0x800; + EmulationType = (UINT16)(USB_EMU_HDD_OR_FDD << 8) + USB_MASS_DEV_CDROM; + goto UMIDT_DeviceTypeOver; + } +// ;(EIP25229+)> +#if USB_START_UNIT_BEFORE_MSD_ENUMERATION +// Start unit command before access it + USBMassStartUnitCommand(DevInfo); +#endif +// ;<(EIP25229+) + //(EIP80382)> + if (DevInfo->bSubClass == SUB_CLASS_UFI) { + EmulationType = (UINT16)(USB_EMU_FLOPPY_ONLY << 8) + USB_MASS_DEV_ARMD; + } else { + EmulationType = (UINT16)(USB_EMU_HDD_ONLY << 8) + USB_MASS_DEV_HDD; + } + //<(EIP80382) + + FixedDelay(gUsbData->UsbTimingPolicy.MassDeviceComeUp * 1000); // Device is coming up give 500ms delay + // + // Some USB mass storage devces are not fast enough to accept mass storage + // commands for parsing geometry, issue read capacity command to make sure device + // is ready for further access. (USB0089+)> + // + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + for (Count = 0; Count < 30 && VALID_DEVINFO(DevInfo); Count++) { + if (USBMassReadCapacity10Command(DevInfo) == USB_SUCCESS) { + break; + } + if ((UINT16)USBMassRequestSense(DevInfo) == 0x3A02 ) { //(EIP86793) + break; // No media + } + } + } + // + // Get the block size & last LBA number + // + Data = USBMassCheckDeviceReady(DevInfo); + //(EIP86793)> + if ((UINT16)Data == 0x3A02) { // Check for media presence status + // + // Media not present. Try to get disk geometry from Format + // capacity command + // + if (!(DevInfo->wIncompatFlags & USB_INCMPT_FORMAT_CAPACITY_NOT_SUPPORTED)) { + USBMassReadFormatCapacity(DevInfo); + if ((DevInfo->MaxLba != 0) && (DevInfo->MaxLba <= USB_144MB_FDD_MAX_LBA)) { + EmulationType = (UINT16)(USB_EMU_FLOPPY_ONLY << 8) + USB_MASS_DEV_ARMD; + } else { + if (!(gUsbData->dUSBStateFlag & USB_FLAG_MASS_EMULATION_FOR_NO_MEDIA)) { + EmulationType = (UINT16)(USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + } + } + goto UMIDT_DeviceTypeOver; + } + } + + // + // Proceed with normal checking + // + if (!Data) { + //(EIP59738-)> + // + // Get the max LBA & block size; if block size is other than + // 512 bytes assume emulation as CDROM + // + //if ( dev->wBlockSize > 0x200 ) { + // wEmulationType = (UINT16)(USB_EMU_HDD_OR_FDD << 8) + USB_MASS_DEV_CDROM; + // goto UMIDT_DeviceTypeOver; + //} + //(<EIP59738-) + //(EIP80382)> + if (USBMassGetFormatType(DevInfo, DevInfo->MaxLba, &EmulationType) == USB_ERROR) { + // + // Find the device type by size + // + if (((Shr64(DevInfo->MaxLba, 11)) < MAX_SIZE_FOR_USB_FLOPPY_EMULATION) || + (gUsbData->dUSBStateFlag & USB_FLAG_MASS_NATIVE_EMULATION)) { + if (DevInfo->bSubClass != SUB_CLASS_UFI) { + EmulationType = (USB_EMU_FORCED_FDD << 8) + USB_MASS_DEV_ARMD; + } + } + } + } + //<(EIP80382) + //<(EIP86793) + +UMIDT_DeviceTypeOver: + + if (ForceEmulationType) { + EmulationType = ForceEmulationType; + } + DevInfo->bStorageType = (UINT8)EmulationType; + DevInfo->bEmuType = (UINT8)(EmulationType >> 8); + + USB_DEBUG(DEBUG_LEVEL_3, "<<-- IdentifyDeviceType:: Emul: %x\n", EmulationType); + + return; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetPhysicalDeviceType +// +// Description: This procedure classify USB mass storage devices according to +// inquiry command return data. +// +// Input: Pointer to DeviceInfo structure +// Pointer to the inquiry data (read from device) +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassGetPhysicalDeviceType( + DEV_INFO* Dev, + UINT8 *Buf +) +{ + + switch (*Buf) { + case 0x0: + if (Dev->bSubClass == SUB_CLASS_UFI) { + Dev->bPhyDevType = USB_MASS_DEV_FDD; + break; + } + Dev->bPhyDevType = (*(Buf+1) & 0x80) ? + USB_MASS_DEV_ARMD : USB_MASS_DEV_HDD; + break; + case 0x5: + Dev->bPhyDevType = USB_MASS_DEV_CDROM; + break; + case 0x7: + Dev->bPhyDevType = USB_MASS_DEV_MO; + break; + case 0xE: + Dev->bPhyDevType = USB_MASS_DEV_ARMD; + break; + default: + Dev->bPhyDevType = USB_MASS_DEV_UNKNOWN; + break; + } + +} + +/* //(EIP59738-)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassConsumeBulkData +// +// DESCRIPTION: This function reads unwanted amount of data specified in +// the size +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// bXferDir Transfer direction +// wLength Size of data to consume +// +// RETURN: USB_ERROR or USB_SUCCESS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassConsumeBulkData( + DEV_INFO* fpDevInfo, + UINT8 bXferDir, + UINT16 wLength) +{ + UINT16 wBytesToTransfer, wBytesRemaining; + UINT32 dData; + +// +// Need to process only maximum amount of data that pUSBMassConsumeBuffer can +// handle, i.e. MAX_CONTROL_DATA_SIZE +// + wBytesRemaining = wLength; + do { + wBytesToTransfer = (UINT16)((wBytesRemaining < MAX_CONTROL_DATA_SIZE)? + wBytesRemaining : MAX_CONTROL_DATA_SIZE); + + dData = USBMassIssueBulkTransfer(fpDevInfo, bXferDir, + gUsbData->fpUSBMassConsumeBuffer, (UINT32)wBytesToTransfer); + + if ((UINT16)dData != wBytesToTransfer) { // Comparing word should be sufficient + return USB_ERROR; + } + wBytesRemaining = (UINT16)(wBytesRemaining - dData); + + } while (wBytesRemaining); + + return USB_SUCCESS; +} +*/ //<(EIP59738-) + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassProcessBulkData +// +// DESCRIPTION: This function reads/writes the data to the mass storage +// device using bulk transfer. It also takes care of pre and +// post skip bytes. +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// stMassXactStruc (given for reference) +// bXferDir Transfer direction +// fpBuffer Data buffer far pointer +// dLength Amount of data to be transferred +// wPreSkip Number of bytes to skip before data +// wPostSkip Number of bytes to skip after data +// +// RETURN: Amount of data actually transferred +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + //(EIP70814)> +UINT32 +USBMassProcessBulkData( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) + +{ + UINT32 dData; + UINT16 wTemp; + UINT8 *Buffer; + UINT8 *SrcBuffer; + UINT8 *DestBuffer; + UINT16 PreSkip; + UINT32 XferSize; + UINT32 XferedSize; + UINT32 RemainingSize; + +//USB_DEBUG (DEBUG_LEVEL_3, "Pre,%x;Post,%x\n", MassXactStruc->wPreSkip, +// MassXactStruc->wPostSkip); + // + // Check whether something we have to transfer + // + if (!MassXactStruc->dLength) { + return 0; + } + + + wTemp = gUsbData->wTimeOutValue; // Save original value + if (gUsbData->wBulkDataXferDelay) { // Check the bulk data delay specified + gUsbData->wTimeOutValue = gUsbData->wBulkDataXferDelay; + } + + if ((MassXactStruc->wPreSkip == 0) && + (MassXactStruc->wPostSkip == 0)) { + + dData = USBMassIssueBulkTransfer( + DevInfo, + MassXactStruc->bXferDir, + MassXactStruc->fpBuffer, + MassXactStruc->dLength); + } else { + // Allocate a data buffer + Buffer = USB_MemAlloc((UINT16)GET_MEM_BLK_COUNT(DevInfo->wBlockSize)); + PreSkip = MassXactStruc->wPreSkip; + RemainingSize = MassXactStruc->dLength - + (PreSkip + MassXactStruc->wPostSkip); + DestBuffer = MassXactStruc->fpBuffer; + + for (XferedSize = 0; XferedSize < MassXactStruc->dLength;) { + XferSize = MassXactStruc->dLength >= DevInfo->wBlockSize ? + DevInfo->wBlockSize : MassXactStruc->dLength; + + dData = USBMassIssueBulkTransfer( + DevInfo, + MassXactStruc->bXferDir, + Buffer, + XferSize); + if (dData == 0) { + //(EIP83295)> + //return 0; + XferedSize = 0; + break; + //<(EIP83295) + } + + XferedSize += XferSize; + if (RemainingSize == 0) { + continue; + } + + SrcBuffer = Buffer; + + if (PreSkip != 0) { + if (PreSkip >= XferSize) { + PreSkip -= XferSize; + continue; + } + + SrcBuffer += PreSkip; + XferSize -= (UINT32)PreSkip; + PreSkip = 0; + } + + XferSize = RemainingSize < XferSize ? RemainingSize : XferSize; + MemCopy(SrcBuffer, DestBuffer, XferSize); + + // Update the destination buffer pointer + DestBuffer += XferSize; + RemainingSize -= XferSize; + } + + USB_MemFree(Buffer, (UINT16)GET_MEM_BLK_COUNT(DevInfo->wBlockSize)); + + dData = XferedSize; + } + + gUsbData->wTimeOutValue = wTemp; // Restore original timeout value + gUsbData->wBulkDataXferDelay = 0; + + return dData; +} + //<(EIP70814) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassInquiryCommand +// +// DESCRIPTION: This function sends inquiry command to the USB mass storage +// device +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +// RETURN: Pointer to the inquiry data +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +MASS_INQUIRY* +USBMassInquiryCommand (DEV_INFO* fpDevInfo) +{ + COMMON_INQ_CMD *fpCmdBuffer; + UINT32 dData; + MASS_XACT_STRUC MassXactStruc; + + // + // Allocate memory for the command buffer + // + fpCmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMMON_INQ_CMD)); + if(!fpCmdBuffer) { + return NULL; + } + + fpCmdBuffer->bOpCode = COMMON_INQUIRY_OPCODE; + fpCmdBuffer->bAllocLength = 0x24; + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)fpCmdBuffer; + //(EIP51158+)> + if (fpDevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x06; //SPC-4_246 + } else { + MassXactStruc.bCmdSize = sizeof (COMMON_INQ_CMD); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = gUsbData->fpUSBTempBuffer + 0x40; + MassXactStruc.dLength = 0x24; + +USB_DEBUG (DEBUG_LEVEL_5, "Issue Inquiry Command .... \n"); + + dData = USBMassIssueMassTransaction(fpDevInfo, &MassXactStruc); + + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMMON_INQ_CMD)); + + + if (dData) { + return (MASS_INQUIRY*)(gUsbData->fpUSBTempBuffer + 0x40); + } + else { + return NULL; + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassRWVCommand +// +// Description: This function reads/writes/verifies blocks of data from the +// USB mass device specified by its device address +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// bOpCode Read/Write/Verify +// fpReadData Pointer to the read command structure +// bDevAddr USB device address of the device +// dStartLBA Starting LBA address +// wNumBlks Number of blocks to process +// wPreSkipSize Number of bytes to skip before +// wPostSkipSize Number of bytes to skip after +// fpBufferPtr Far buffer pointer +// +// Output: Return code (0 - Failure, <>0 - Size read) +// fpReadData Pointer to the mass read command structure +// dSenseData Sense data of the last command +// fpBufferPtr Far buffer pointer +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassRWVCommand( + DEV_INFO *DevInfo, + UINT8 OpCode, + VOID *DataStruc +) +{ + MASS_READ *MassDataStruc = (MASS_READ*)DataStruc; + COMN_RWV_16_CMD *CmdBuffer; + UINT64 StartLba; + UINT32 BytesToRw; + UINT32 Data; + UINT32 SenseData; + UINT8 Dir; // BIT7 0/1 - R/W + UINT8 RetryNum; + UINT16 RetCode = 0; + UINT8 CmdSize; + MASS_XACT_STRUC MassXactStruc; + + EFI_STATUS EfiStatus = EFI_SUCCESS; + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)MassDataStruc->BufferPtr, + (UINT32)MassDataStruc->NumBlks * (UINT32)DevInfo->wBlockSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "UsbMassRWVCommand Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = TRUE; + } +#endif + + // + // Set the sense code as 0 + // + MassDataStruc->SenseData = 0; + + // + // Allocate memory for the command buffer + // + CmdBuffer = (COMN_RWV_16_CMD*)USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_RWV_16_CMD)); + if (!CmdBuffer) { + return 0; + } + + for (RetryNum = 0; RetryNum < 2; RetryNum++) { + // + // Load command into (just allocated) mass command buffer + // + CmdBuffer->OpCode = OpCode; + StartLba = MassDataStruc->StartLba; + //(EIP60588+)> + if (StartLba > (DevInfo->MaxLba - MassDataStruc->NumBlks)) { + StartLba = DevInfo->MaxLba - MassDataStruc->NumBlks; + } + //<(EIP60588+) + // + // If the "Forced FDD" option is selected that means the device has + // to be emulated as a floppy drive even though it has a HDD emulated + // image. This is accomplished by hiding the first cylinder totally. + // The partition table is in the first cylinder. LBA value for all + // the requests to the device will be offset with the number of sectors + // in the cylinder. + // + + // + // Check for forced floppy emulated device and change LBA accordingly + // + if (DevInfo->bEmuType == USB_EMU_FORCED_FDD) { + if (!(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI)) //(EIP113379+) + // + // Skip first track in case of floppy emulation + // + StartLba += DevInfo->bHiddenSectors; + } + + // + // Check the validity of the block size + // + if (DevInfo->wBlockSize != 0xFFFF) { + // + // Change big endian format (INTEL) to little endian format + // + if ((OpCode == COMMON_READ_10_OPCODE) || + (OpCode == COMMON_WRITE_10_OPCODE) || + (OpCode == COMMON_VERIFY_10_OPCODE)) { + ((COMN_RWV_10_CMD*)CmdBuffer)->dLba = dabc_to_abcd((UINT32)StartLba); + ((COMN_RWV_10_CMD*)CmdBuffer)->wTransferLength = + (UINT16)((MassDataStruc->NumBlks << 8) + (MassDataStruc->NumBlks >> 8)); + if (DevInfo->bSubClass == SUB_CLASS_SCSI) { + CmdSize = 0x0A; //SBC-3_60 + } else { + CmdSize = sizeof (COMN_RWV_10_CMD); + } + } else { + CmdBuffer->Lba = Shl64(dabc_to_abcd((UINT32)StartLba), 32); + CmdBuffer->Lba |= dabc_to_abcd((UINT32)Shr64(StartLba, 32)); + CmdBuffer->TransferLength = dabc_to_abcd(MassDataStruc->NumBlks); + CmdSize = sizeof(COMN_RWV_16_CMD); + } + // + // Verify command does not need delay + // + gUsbData->wBulkDataXferDelay = 0; + + // + // Calculate number of bytes to transfer (for verify command nothing + // to read/write. + // + BytesToRw = 0; + if ((OpCode != COMMON_VERIFY_10_OPCODE) && + (OpCode != COMMON_VERIFY_16_OPCODE)){ + // + // Read/write command may need long time delay + // + gUsbData->wBulkDataXferDelay = 20000; + BytesToRw = (UINT32)MassDataStruc->NumBlks * (UINT32)DevInfo->wBlockSize; + } + + // + // Set the direction properly + // + if ((OpCode == COMMON_WRITE_10_OPCODE) || + (OpCode == COMMON_WRITE_16_OPCODE)) { + Dir = 0; + } else { + Dir = BIT7; + } + + // + // Fill the common bulk transaction structure + // Fill Command buffer address & size + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + MassXactStruc.bCmdSize = CmdSize; + MassXactStruc.bXferDir = Dir; + MassXactStruc.fpBuffer = (UINT8*)(UINTN)MassDataStruc->BufferPtr; + MassXactStruc.wPreSkip = MassDataStruc->PreSkipSize; + MassXactStruc.wPostSkip = MassDataStruc->PostSkipSize; + MassXactStruc.dLength = BytesToRw; + + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + if ((Data) && ((RetryNum != 0) || (Data == BytesToRw))) { // Some data processed. Set return value + + // + // Bug fix for installing Linux from USB CD-ROM. + // Linux64Bit Boot + // If data read is 64K or higher return 0FFFFh + // + if (Data >= 0x010000) { + Data = 0xFFFF; + } + + RetCode = (UINT16)Data; + // + // Check for forced floppy emulated device + // + if ((DevInfo->bEmuType == USB_EMU_FORCED_FDD) && + (OpCode == COMMON_READ_10_OPCODE) && + (MassDataStruc->StartLba == 0) && + !(gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) ) { //(EIP113379+) + // + // This is a floppy emulated ZIP drive, with read to + // first sector. Update the boot record so that floppy + // emulation is okay. + // + // Force #of hidden sectors to 0 + // + *(UINT32*)((UINTN)MassDataStruc->BufferPtr + 0xB + 0x11) = 0; + + // + // FreeDOS workaround + // + if ((*(UINT32*)((UINTN)MassDataStruc->BufferPtr + 3)==0x65657246) && // 'eerF' + (*(UINT32*)((UINTN)MassDataStruc->BufferPtr + 7)==0x20534F44) && // ' SOD' + (*(UINT32*)((UINTN)MassDataStruc->BufferPtr + 0x3A)!=0x20202032)) { //(EIP61388) + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x42) = + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x42)-(UINT16)DevInfo->bHiddenSectors; + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x46) = + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x46)-(UINT16)DevInfo->bHiddenSectors; + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x4A) = + *(UINT16*)((UINTN)MassDataStruc->BufferPtr + 0x4A)-(UINT16)DevInfo->bHiddenSectors; + } + // + // Force physical drive# to 0 + // For FAT32, physical drive number is present in offset 40h + // + if ((*(UINT32*)((UINTN)MassDataStruc->BufferPtr + 0x52)) == + 0x33544146) { // "3TAF", FAT3 + *(UINT8*)((UINTN)MassDataStruc->BufferPtr + 0x40) = 0; + } + else { + *(UINT8*)((UINTN)MassDataStruc->BufferPtr + 0x24) = 0; + } + } + break; // dData ready + + } + else { // Error condition: dData = 0, RetCode = 0 + // + // Check for error + // + SenseData = USBMassRequestSense(DevInfo); + MassDataStruc->SenseData = SenseData; + Data = SenseData; + + // + // Check for write protect error code + // + if ((UINT8)SenseData == 7) { + break; + } + + if (((OpCode == COMMON_VERIFY_10_OPCODE) || + (OpCode == COMMON_VERIFY_16_OPCODE)) && (!SenseData)) { + // + // This is verify command so no data to send or read and + // also sense data is 0. So set return value to success. + // + RetCode = 0xFFFF; + break; + } + } + } // fpDevInfo->wBlockSize != 0xFFFF + + // + // UPRCC_ProceedIfRW + // May be drive error, try to correct it + // Check whether the drive is ready for read/write/verify command + // + Data = USBMassCheckDeviceReady(DevInfo); + MassDataStruc->SenseData = Data; + + if (Data) { + break; // Return error + } + + MemFill((UINT8*)CmdBuffer, sizeof(COMN_RWV_16_CMD), 0); + } // Fof loop + + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_RWV_16_CMD)); + + return RetCode; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassStartUnitCommand +// +// DESCRIPTION: This function sends the start unit command to the mass device +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +// RETURN: Sense data: 0 - Success, <>0 - Error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassStartUnitCommand (DEV_INFO* fpDevInfo) +{ + COMMON_START_STOP_UNIT_CMD *fpCmdBuffer; + MASS_XACT_STRUC MassXactStruc; +// MASS_START_STOP_UNIT *fpStartData; + + USB_DEBUG (DEBUG_LEVEL_5, "USBMProStartUnitCommand .... \n"); + + // + // Check the compatibility flag for start unit command not supported + // + if (fpDevInfo->wIncompatFlags & USB_INCMPT_START_UNIT_NOT_SUPPORTED) { + return USB_SUCCESS; + } + + // + // Allocate memory for the command buffer + // + fpCmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMMON_START_STOP_UNIT_CMD)); + if (!fpCmdBuffer) { + return USB_ERROR; + } + + // + // Load command into (just allocated) mass command buffer + // + fpCmdBuffer->bOpCode = COMMON_START_STOP_UNIT_OPCODE; + fpCmdBuffer->bStart = 1; + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + gUsbData->wBulkDataXferDelay = 10000; // Start unit command may need long time delay + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)fpCmdBuffer; + //(EIP51158+)> + if (fpDevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x06; //SBC-3_77 + } else { + MassXactStruc.bCmdSize = sizeof (COMMON_START_STOP_UNIT_CMD); + } + //<(EIP51158+) + USBMassIssueMassTransaction(fpDevInfo, &MassXactStruc); + + // + // No data to read/write. So do not process return code. + // Check and free command buffer + // + USB_MemFree(fpCmdBuffer,GET_MEM_BLK_COUNT_STRUC(COMMON_START_STOP_UNIT_CMD)); + + return USBMassRequestSense(fpDevInfo); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassModeSense +// +// DESCRIPTION: This function requests the mode sense data page number 5 from +// the USB mass storage device +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +// RETURN: USB_SUCCESS/USB_ERROR on Success/Failure +// fpModeSenseData Pointer to the mode sense data +// dSenseData Sense data +// bNumHeads Number of heads +// wNumCylinders Number of cylinders +// bNumSectors Number of sectors +// wBytesPerSector Number of bytes per sector +// bMediaType Media type +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassModeSense( + DEV_INFO *fpDevInfo, + MASS_MODE_SENSE *fpModeSenseData) +{ + UINT32 dData; + UINT8 bRetCode; + COMN_MODE_SENSE_10CMD *fpCmdBuffer; + MODE_SENSE_10_HEADER *fpModeSense10_Header; + PAGE_CODE_5 *fpPageCode5; + MASS_XACT_STRUC MassXactStruc; + + dData = 0; + bRetCode = USB_ERROR; + + fpCmdBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMN_MODE_SENSE_10CMD)); + if (!fpCmdBuffer) { + return USB_ERROR; + } + + // + // Load command into (just allocated) mass command buffer + // + fpCmdBuffer->bOpCode = COMMON_MODE_SENSE_10_OPCODE; + fpCmdBuffer->wAllocLength = 0x2800; // Allocation Length = 40 bytes (0x28) + fpCmdBuffer->bPageCode = 5; // Page code + + // + // Clear the common bulk transaction structure + // + USBMassClearMassXactStruc(&MassXactStruc); + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)fpCmdBuffer; + //(EIP51158+)> + if (fpDevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x0A; //SPC-4_280 + } else { + MassXactStruc.bCmdSize = sizeof (COMN_MODE_SENSE_10CMD); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = gUsbData->fpUSBTempBuffer; + MassXactStruc.dLength = 0x28; + + // + // Bulk in, with temp buffer & 40 bytes of data to read + // + dData = USBMassIssueMassTransaction(fpDevInfo, &MassXactStruc); + + if (!dData) { + USBMassRequestSense( fpDevInfo ); + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_MODE_SENSE_10CMD)); + return USB_ERROR; + } + + // + // Fill in the output data + // + fpModeSense10_Header = (MODE_SENSE_10_HEADER*)gUsbData->fpUSBTempBuffer; + + // + // Process media type + // + fpModeSenseData->bMediaType = fpModeSense10_Header->bMediaType; + + // + // Position to the correct page code starting location + // + fpPageCode5 = (PAGE_CODE_5*)((UINT8*)fpModeSense10_Header + + fpModeSense10_Header->wBlkDescSize + + sizeof (MODE_SENSE_10_HEADER)); +// USB_DEBUG (DEBUG_LEVEL_3, "USBMassModeSense .... fpPageCode5->bPageCode %x\n",fpPageCode5->bPageCode); + + bRetCode = USB_ERROR; + if(fpPageCode5->bPageCode == 5) { + // + // Process number of bytes per sector (the block size) + // + fpModeSenseData->wBytesPerSector = (UINT16)((fpPageCode5->wBlockSize << 8) + + (fpPageCode5->wBlockSize >>8)); + // + // Process number of heads and number of sectors/track + // + fpModeSenseData->bNumHeads = fpPageCode5->bHeads; + fpModeSenseData->bNumSectors = fpPageCode5->bSectors; + + // + // Process number of cylinders + // + fpModeSenseData->wNumCylinders = (UINT16)((fpPageCode5->wCylinders << 8) + + (fpPageCode5->wCylinders >> 8)); + bRetCode = USB_SUCCESS; + } + + fpModeSenseData->dSenseData = USBMassRequestSense( fpDevInfo ); + + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_MODE_SENSE_10CMD)); +// USB_DEBUG (DEBUG_LEVEL_5, "USBMProModeSense .... wRetCode %x\n",wRetCode); + + return bRetCode; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassRequestSense +// +// DESCRIPTION: This function sends request sense command and returns +// the sense key information +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +// RETURN: Sense data +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USBMassRequestSense(DEV_INFO* fpDevInfo) +{ + UINT32 dData; + UINT8 *fpDataBuffer; + COMMON_REQ_SENSE_CMD *fpCmdBuffer; + MASS_XACT_STRUC MassXactStruc; + + // + // Allocate memory for the command buffer + // + fpCmdBuffer = (COMMON_REQ_SENSE_CMD*)USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(COMMON_REQ_SENSE_CMD)); + if(!fpCmdBuffer) { + return USB_ERROR; // Error - return no sense data <>0 + } + + fpDataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(1)); + if(!fpDataBuffer) { + return USB_ERROR; // Error - return no sense data <>0 + } + + // + // Load command into (just allocated) mass command buffer + // + fpCmdBuffer->bOpCode = COMMON_REQUEST_SENSE_OPCODE; + fpCmdBuffer->bAllocLength = 0x12; // Length of transfer + + USBMassClearMassXactStruc(&MassXactStruc); // Clear the common bulk transaction structure + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)fpCmdBuffer; + //(EIP51158+)> + if (fpDevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x06; //SPC-4_350 + } else { + MassXactStruc.bCmdSize = sizeof (COMMON_REQ_SENSE_CMD); + } + //<(EIP51158+) + MassXactStruc.bXferDir = BIT7; // IN + MassXactStruc.fpBuffer = fpDataBuffer; + MassXactStruc.dLength = 0x12; + + // + // Bulk in, with locally allocated temp buffer & 12h bytes of data to read + // + dData = USBMassIssueMassTransaction(fpDevInfo, &MassXactStruc); + + if(dData) { + // + // Form the return value: + // Bit 0..7 - Sense key (offset 002d) + // Bit 8..15 - ASC code (offset 012d) + // Bit 16..23 - ASCQ code (offset 013d) + // + dData = (UINT32)(fpDataBuffer[2] + + (fpDataBuffer[12] << 8) + + (fpDataBuffer[13] << 16)); + USBMassSenseKeyParsing(fpDevInfo, dData); + } + //(EIP20863+)> + else + dData = USB_ERROR; + //<(EIP20863+) + + USB_MemFree(fpCmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMMON_REQ_SENSE_CMD)); + USB_MemFree(fpDataBuffer, GET_MEM_BLK_COUNT(1)); + + return dData; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassSenseKeyParsing +// +// DESCRIPTION: Translate USB sense key to USB MassStorage status. +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// dCode[23..16] ASCQ +// dCode[15..08] ASC +// dCode[07..00] Sense Code + +// +// RETURN: Sense data +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassSenseKeyParsing(DEV_INFO* fpDevInfo, UINT32 dCode) +{ + if ((UINT16)dCode == 0x3A02) { //(EIP86793) + fpDevInfo->bLastStatus &= ~USB_MASS_MEDIA_PRESENT; + } + if((UINT16)dCode == 0x2806) { + fpDevInfo->bLastStatus |= (USB_MASS_MEDIA_PRESENT | USB_MASS_MEDIA_CHANGED); + } + //(EIP86125+)> + if(dCode == 0) { + fpDevInfo->bLastStatus |= USB_MASS_MEDIA_PRESENT; + } + //<(EIP86125+) +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassTestUnitReady +// +// DESCRIPTION: This function sends test unit ready command +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +// RETURN: Sense data +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USBMassTestUnitReady( + DEV_INFO* DevInfo +) +{ + COMN_TEST_UNIT_READY_CMD *CmdBuffer; + UINT32 Data; + MASS_XACT_STRUC MassXactStruc; + + CmdBuffer = (COMN_TEST_UNIT_READY_CMD*)USB_MemAlloc( + GET_MEM_BLK_COUNT_STRUC(COMN_TEST_UNIT_READY_CMD)); + if (!CmdBuffer) { + return USB_ERROR; // Error - return no sense data + } + + CmdBuffer->bOpCode = COMMON_TEST_UNIT_READY_OPCODE; + USB_DEBUG (DEBUG_LEVEL_5, "USBMassTestUnitReady .... \n"); + + USBMassClearMassXactStruc(&MassXactStruc); // Clear the common bulk transaction structure + + // + // Fill the common bulk transaction structure + // + MassXactStruc.fpCmdBuffer = (UINT8*)CmdBuffer; + //(EIP51158+)> + if (DevInfo->bSubClass == SUB_CLASS_SCSI) { + MassXactStruc.bCmdSize = 0x06; //SPC-4_368 + } else { + MassXactStruc.bCmdSize = sizeof (COMN_TEST_UNIT_READY_CMD); + } + //<(EIP51158+) + Data = USBMassIssueMassTransaction(DevInfo, &MassXactStruc); + + USB_MemFree(CmdBuffer, GET_MEM_BLK_COUNT_STRUC(COMN_TEST_UNIT_READY_CMD)); + + if ((Data == USB_ERROR) || (DevInfo->bProtocol == PROTOCOL_CBI) || + (DevInfo->bProtocol == PROTOCOL_CBI_NO_INT)) { + Data = USBMassRequestSense(DevInfo); + } + return Data; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassCheckDeviceReady +// +// Description: This function makes sure the device is ready for next +// command +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// +// Output: Sense code +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USBMassCheckDeviceReady (DEV_INFO* fpDevInfo) +{ + UINT8 count, nomedia_count; + UINT8 NotReadyCount; //(EIP101623+) + UINT32 dData = 0; + + count = gUsbData->bUSBStorageDeviceDelayCount; + nomedia_count = 3; + NotReadyCount = 3; //(EIP101623+) + while (count) { + if (fpDevInfo->wIncompatFlags & USB_INCMPT_TEST_UNIT_READY_FAILED) { + break; // consider device is ready + } + + // + // Issue test unit ready command and check the return value + // + dData = USBMassTestUnitReady( fpDevInfo ); +//USB_DEBUG(DEBUG_LEVEL_3, "(%d)tur..%x ", fpDevInfo->bDeviceAddress, dData); + if ((UINT8)dData == 0) { // Device ready + break; + } + // + // Device is not ready. + // Check for getting ready/reset command occurence in dData: + // Bit 0..7 - Sense Code + // Bit 8..15 - Additional Sense Code (ASC) + // Bit 16..23 - Additional Sense Code Qualifier (ASCQ) + // + if ((UINT16)dData == 0x2806) { + // + // Send Start/Stop Unit command to UFI class device only + // + if (fpDevInfo->bSubClass == SUB_CLASS_UFI) { + USBMassStartUnitCommand (fpDevInfo); + } + FixedDelay(100 * 1000); // 100 msec delay + count--; + continue; + } + if ((UINT16)dData == 0x3A02) { // Media is not present + nomedia_count--; + if (nomedia_count == 0) return dData; // No media + FixedDelay(20 * 1000); // 20 msec delay + count--; + continue; + } + + if (dData == 0x020402) + { + USBMassStartUnitCommand (fpDevInfo); + FixedDelay(100 * 1000); + count--; + continue; + } + + if ((UINT16)dData == 0x1103) { + FixedDelay(100 * 1000); + count--; + continue; + } + + // + // Check whether we can recover from this error condition + // Currently only recoverable error condition are + // 1. Device is getting ready (010402) + // 2. Device reset occurred (002906) + // + if (dData != 0x010402) { + // + // Check for write protected command + // + if ( (UINT8)dData == 7 ) { + break; + } + if (((UINT8)dData != 0x06) && ((UINT8)dData != 0x02)) { + return dData; + } + } + + //(EIP101623+)> + if (dData == 0x02) { + NotReadyCount--; + if (NotReadyCount == 0) return dData; + FixedDelay(20 * 1000); // 20 msec delay + count--; + continue; + } + //<(EIP101623+) + + // + // Prepare for the next itaration + // Delay for the device to get ready + // + FixedDelay(1000 * 1000); // 1 sec delay + count--; + } // while + //(EIP53416+)> + if (count == 0) { + return dData; + } + //<(EIP53416+) + return USBMassUpdateDeviceGeometry(fpDevInfo); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassUpdateParamUsingModeSense +// +// Description: This function obtains the device geometry from the device +// using mode sense command and updates the global variables +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassUpdateParamUsingModeSense(DEV_INFO* fpDevInfo) +{ + MASS_MODE_SENSE ModeSenseData; + + gUsbData->wModeSenseCylinders = gUsbData->bModeSenseHeads = + gUsbData->bModeSenseSectors = 0; + // + // Check the compatibility flag for mode sense support + // + if (fpDevInfo->wIncompatFlags & USB_INCMPT_MODE_SENSE_NOT_SUPPORTED) { + return USB_SUCCESS; + } + + // + // CDROM devices never support mode sense page code 5 (Flexible disk page) + // so skip it + // + if (fpDevInfo->bStorageType == USB_MASS_DEV_CDROM) { + return USB_ERROR; + } + + // + // Issue mode sense command + // + if (USBMassModeSense(fpDevInfo, &ModeSenseData)) { +USB_DEBUG(DEBUG_LEVEL_3, "ms..err "); + return USB_ERROR; + } + + // + // Mode sense is supported. Update the local structure. + // + gUsbData->wModeSenseCylinders = ModeSenseData.wNumCylinders; // Number of cylinders + gUsbData->bModeSenseHeads = ModeSenseData.bNumHeads; // Number of heads + gUsbData->bModeSenseSectors = ModeSenseData.bNumSectors; // Number of sectors + gUsbData->wModeSenseBlockSize = ModeSenseData.wBytesPerSector;// Number of bytes per sector + gUsbData->bDiskMediaType = ModeSenseData.bMediaType; // Media type + + +USB_DEBUG(DEBUG_LEVEL_4, "ms..%x %x %x %x %x ", + gUsbData->wModeSenseCylinders, + gUsbData->bModeSenseHeads, + gUsbData->bModeSenseSectors, + gUsbData->wModeSenseBlockSize, + gUsbData->bDiskMediaType +); + + if (fpDevInfo->bStorageType == USB_MASS_DEV_HDD) { + gUsbData->bDiskMediaType = USB_UNKNOWN_MEDIA_TYPE; + } + + // + // Calculate and update Max LBA + // + gUsbData->dModeSenseMaxLBA = + (UINT32)(ModeSenseData.wNumCylinders * + ModeSenseData.bNumHeads * ModeSenseData.bNumSectors); + // + // Set the flag indicating mode sense is executed + // + gUsbData->bGeometryCommandStatus |= MODE_SENSE_COMMAND_EXECUTED; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassUpdateParamUsingReadCapacity +// +// Description: This function obtains the device geometry from the device +// using read capacity command and updates the global variables +// +// Input: Pointer to DeviceInfo structure +// +// Output: USB_ERROR On error +// USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassUpdateParamUsingReadCapacity( + DEV_INFO* DevInfo +) +{ + UINT8 Sectors; + UINT8 Heads; + + // + // Either mode sense not supported or failed. Try read capacity + // Issue read capacity command + // + if (USBMassReadCapacity10Command(DevInfo)) { + return USB_ERROR; + } + + // + // Set the flag indicating read capacity is executed + // + gUsbData->bGeometryCommandStatus |= READ_CAPACITY_COMMAND_EXECUTED; + + // + // Max LBA & block size are updated in MassDeviceInfo structure + // + if (DevInfo->MaxLba < 0x4000) { // last LBA < 16MB + switch (DevInfo->MaxLba) { + case USB_144MB_FDD_MAX_LBA: + gUsbData->bReadCapHeads = USB_144MB_FDD_MAX_HEADS; + gUsbData->bReadCapSectors = USB_144MB_FDD_MAX_SECTORS; + gUsbData->wReadCapCylinders= USB_144MB_FDD_MAX_CYLINDERS; + gUsbData->bDiskMediaType = USB_144MB_FDD_MEDIA_TYPE; + return USB_SUCCESS; + + case USB_720KB_FDD_MAX_LBA: + gUsbData->bReadCapHeads = USB_720KB_FDD_MAX_HEADS; + gUsbData->bReadCapSectors = USB_720KB_FDD_MAX_SECTORS; + gUsbData->wReadCapCylinders= USB_720KB_FDD_MAX_CYLINDERS; + gUsbData->bDiskMediaType = USB_720KB_FDD_MEDIA_TYPE; + return USB_SUCCESS; + } + } + + // + // Convert to CHS + // + gUsbData->wReadCapBlockSize = DevInfo->wBlockSize; + + // + // Do CHS conversion + // Use fixed sectors/track & heads for CHS conversion + // + if (DevInfo->MaxLba < 0x400) { // < 512 KB + Sectors = 1; + Heads = 1; + } + else { + if (DevInfo->MaxLba < 0x200000) { // < 1GB + Sectors = USB_FIXED_LBA_SPT_BELOW_1GB; + Heads = USB_FIXED_LBA_HPT_BELOW_1GB; + } + else { // > 1GB + Sectors = USB_FIXED_LBA_SPT_ABOVE_1GB; + Heads = USB_FIXED_LBA_HPT_ABOVE_1GB; + } + } + + gUsbData->bReadCapSectors = Sectors; + gUsbData->bReadCapHeads = Heads; + + // + // Calculate number of cylinders Cyl = LBA/(Head*Sec) + // + if ((Sectors != 0) && (Heads != 0)) { + gUsbData->wReadCapCylinders = (UINT16)Div64(DevInfo->MaxLba, (Sectors * Heads), NULL); + } else { + gUsbData->wReadCapCylinders = 0; + } + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassUpdateDeviceGeometry +// +// Description: This function updates the device geometry information +// +// Input: Pointer to device info structure +// +// Output: USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassUpdateDeviceGeometry ( + DEV_INFO* DevInfo +) +{ + UINT64 MaxLba; + UINT8 Heads; + UINT8 Sectors; + UINT16 Cylinders; + UINT8 Status; + + // + // Try to update geometry if it is not valid + // "Valid" block size is 1...FFFE + // Additional check added to ensure the head, sector, and cylinder values are non-zero. + // + //(EIP13457+)> + if ((DevInfo->Heads != 0) && + (DevInfo->bSectors != 0) && + (DevInfo->wCylinders != 0) && + !(DevInfo->bLastStatus & USB_MASS_MEDIA_CHANGED) && + (!((DevInfo->bLastStatus & USB_MASS_GET_MEDIA_FORMAT) && + (DevInfo->bSubClass == SUB_CLASS_UFI)))) { + + DevInfo->bLastStatus &= ~USB_MASS_GET_MEDIA_FORMAT; + + if (DevInfo->wBlockSize && (DevInfo->wBlockSize != 0xFFFF)) { + return USB_SUCCESS; + } + } + + DevInfo->bLastStatus &= ~USB_MASS_GET_MEDIA_FORMAT; + + // + // Set default values for the global variables + // + gUsbData->bDiskMediaType = USB_UNKNOWN_MEDIA_TYPE; + gUsbData->bGeometryCommandStatus &= ~(MODE_SENSE_COMMAND_EXECUTED | + READ_CAPACITY_COMMAND_EXECUTED); + + // + // Get disk geometry using Mode Sense + // + if (DevInfo->bSubClass == SUB_CLASS_UFI) { //(EIP94060) + USBMassUpdateParamUsingModeSense(DevInfo); + } + + // + // Get disk geometry using Read Capacity + // + Status = USBMassUpdateParamUsingReadCapacity(DevInfo); + + // + // Parameters are obtained and stored in respective global variables; + // check whether any of the commands executed. + // + if (!(gUsbData->bGeometryCommandStatus & (READ_CAPACITY_COMMAND_EXECUTED | + MODE_SENSE_COMMAND_EXECUTED))) { + USB_DEBUG(DEBUG_LEVEL_3, "-error\n"); + return USB_ERROR; + } + + // + // Check whether read capacity is executed. If so, then max LBA & block size + // are already updated in the MassDeviceInfo structure. If not update it using + // mode sense parameters + // + if (!(gUsbData->bGeometryCommandStatus & READ_CAPACITY_COMMAND_EXECUTED)) { + // + // At this point we made sure atleast one of the command (Mode sense or Read + // Capacity) was executed. So if one command is not executed then other + // command is surely executed. + // + + // + // Update the max LBA & block size using mode sense parameters + // + DevInfo->wBlockSize = gUsbData->wModeSenseBlockSize; + DevInfo->MaxLba = gUsbData->dModeSenseMaxLBA; + USB_DEBUG(DEBUG_LEVEL_4, "size %x lba %lx\n", DevInfo->wBlockSize, DevInfo->MaxLba); + } + + //Some usb mass storages report media change even if they don't, we already + //update CHS from boot record and legacy boot doesn't support dynamic + //media insertion, we should not update it from read capacity parameters. + + if ((DevInfo->Heads != 0) && (DevInfo->bSectors != 0) && (DevInfo->wCylinders !=0)) { + return USB_SUCCESS; + } + + // + // Update the media type byte + // + DevInfo->bMediaType = gUsbData->bDiskMediaType; + + // + // Check whether mode sense is executed. If so, then update CHS from mode + // sense value or else update from read capacity values. + // + + // + // Update the CHS values using mode sense parameters + // + Heads = gUsbData->bModeSenseHeads; + Sectors = gUsbData->bModeSenseSectors; + Cylinders = gUsbData->wModeSenseCylinders; + +// if ((gUsbData->bGeometryCommandStatus & MODE_SENSE_COMMAND_EXECUTED) && + if ((Heads * Sectors * Cylinders) == 0) { + // + // Update the CHS values using read capacity parameters + // + Heads = gUsbData->bReadCapHeads; + Sectors = gUsbData->bReadCapSectors; + Cylinders = gUsbData->wReadCapCylinders; + } + + USB_DEBUG (DEBUG_LEVEL_4, "Cyl-%x, Hds-%x, Sec-%x", Cylinders, Heads, Sectors); + + DevInfo->Heads = Heads; + DevInfo->bSectors = Sectors; + DevInfo->wCylinders = Cylinders; + + // + // Calculate non-LBA CHS values from max LBA + // + MaxLba = DevInfo->MaxLba; + + // + // Do not translate sectors for non HDD devices + // + if ((!DevInfo->bStorageType) || (DevInfo->bStorageType == USB_MASS_DEV_HDD)) { + // + // If Total number of sectors < 1032192(0FC000h) CHS translation is not + // needed + // + if (MaxLba >= 0xFC000) { + Sectors = 63; + Heads = 32; + // + // If Total number of sectors < 2064384(01F8000h) then use + // 63 Sec/track and 32 head for translation + // + if (MaxLba >= 0x01F8000) { + Heads = 64; + // + // If Total number of sectors < 4128768(03F0000h) then use + // 63 Sec/track and 64 head for translation + // + if (MaxLba >= 0x03F0000) { + Heads = 128; + // + // If Total number of sectors < 8257536(07E0000h) then use + // 63 Sec/track and 128 head for translation else use 255 heads + // + if (MaxLba >= 0x7E0000) { + Heads = 255; + MaxLba = DevInfo->MaxLba; + } + } + } + } + + // + // In any case, check the parameters for maximum values allowed by BIOS and + // ATA specs (that is, 1024 cylinders, 16 heads and 63 sectors per track) + // + for (;;) { + // + // Calculate translated number of cylinders + // + if ((Sectors != 0) && (Heads != 0)) { + Cylinders = (UINT16)Div64(MaxLba, (Heads * Sectors), NULL); + } else { + Cylinders = 0; + } + + // + // Check whether number of cylinders is less than or equal to 1024 + // + if (Cylinders <= 1024) break; + + // + // Cylinders are getting larger than usually supported try increasing + // head count keeping cylinders within safe limit + // + Cylinders = 1024; + if (Heads == 0xFF) { + break; // Heads limit reached + } + // + // Double number of heads + // + Heads <<= 1; + if (!Heads) { + Heads = 0xFF; + } + } + } + + // + // Save the parameters + // + DevInfo->NonLBAHeads = Heads; + DevInfo->bNonLBASectors = Sectors; + DevInfo->wNonLBACylinders = Cylinders; + + USB_DEBUG(DEBUG_LEVEL_5, "BPS %d H %d S %d C %d MT %d\n", + DevInfo->wBlockSize, + DevInfo->Heads, + DevInfo->bSectors, + DevInfo->wCylinders, + DevInfo->bMediaType); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassIssueBOTTransaction +// +// Description: This function performs a mass storage transaction using bulk +// only transport (BOT) protocol. +// +// Input: Pointer to DeviceInfo structure +// stMassXactStruc +// pCmdBuffer Pointer to command buffer +// bCmdSize Size of command block +// bXferDir Transfer direction +// fpBuffer Data buffer far pointer +// dwLength Amount of data to be transferred +// wPreSkip Number of bytes to skip before data +// wPostSkip Number of bytes to skip after data +// +// Output: Amount of data actually transferred +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USBMassIssueBOTTransaction( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + UINT32 Data; + UINT8 Status; + + Data = USBMassSendBOTCommand(DevInfo, MassXactStruc); // Send the command control transfer + + if (!Data) { + // + // Check for stall/timedout condition + // + if (gUsbData->bLastCommandStatus & (USB_BULK_STALLED + USB_BULK_TIMEDOUT)) { + // + // Perform USB BOT reset recovery + // + USBMassBOTResetRecovery(DevInfo); + return 0; + } + else { + return 0; // Unknown error exit + } + } + + if (!MassXactStruc->dLength) { // No data + if (gUsbData->wBulkDataXferDelay) { + // + // Issue some delay + // + FixedDelay(100 * 1000); + gUsbData->wBulkDataXferDelay = 0; + } + // + // Get the status for the last transfer + // + Data = USBMassGetBOTStatus(DevInfo, MassXactStruc); + return Data; + } + + // + // Tranfer the bulk data + // + Data = USBMassProcessBulkData(DevInfo, MassXactStruc); // Actual data size + + // + // Check for stall/timeout condition + // + if (!(gUsbData->bLastCommandStatus & (USB_BULK_STALLED + USB_BULK_TIMEDOUT))) { + // + // Get the status for the last transfer + // + Status = USBMassGetBOTStatus(DevInfo, MassXactStruc); + if ((Status == USB_ERROR) || (gUsbData->bLastCommandStatus & USB_BULK_TIMEDOUT)) { + return 0; + } else { + return Data; + } + } + + // + // Check for time out condition + // + if (gUsbData->bLastCommandStatus & USB_BULK_TIMEDOUT) { + // + // Perform USB BOT reset recovery + // + USBMassBOTResetRecovery(DevInfo); + return 0; + } + + // + // Clear endpoint stall + // + USBMassClearBulkEndpointStall(DevInfo, MassXactStruc->bXferDir); + + // + // Get the status for the last transfer + // + USBMassGetBOTStatus(DevInfo, MassXactStruc); + + return Data; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBBOTSendCommand +// +// DESCRIPTION: This function performs a mass storage transaction using bulk +// only transport (BOT) protocol. +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// bXferDir Transfer direction +// dwDataSize Amount of data to be transferred +// fpCmdBuffer Pointer to the command buffer +// bCmdSize Size of command block + +// RETURN: Amount of data actually transferred +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassSendBOTCommand( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + UINT8 Count; + UINT8 *Src; + UINT8 *Dest; + BOT_CMD_BLK *BotCmdBlk; + UINT8 CmdSize; + + BotCmdBlk = (BOT_CMD_BLK*)MassXactStruc->fpCmdBuffer; + + CmdSize = MassXactStruc->bCmdSize; + +// if( !VALID_DEVINFO2( fpDevInfo) ) +// return 0; + // + // Make enough space for BOT command block wrapper + // Move backwards + // + Src = MassXactStruc->fpCmdBuffer + CmdSize - 1; + + // + // BOT_COMMAND_BLOCK + end of command + // + Dest = Src + ((UINT8*)BotCmdBlk->aCBWCB - (UINT8*)BotCmdBlk); + + for (Count = 0; Count < CmdSize; Count++) { + *Dest = *Src; + --Dest; + --Src; + } + + //fpDest = gUsbData->stMassXactStruc.fpCmdBuffer; + + // + // Clear the BOT command block + // + //for (bCount = 0; bCount < bCmdSize; bCount++) { + // *fpDest = 0x00; + // ++fpDest; + //} + + BotCmdBlk->dCbwSignature = BOT_CBW_SIGNATURE; + BotCmdBlk->dCbwTag = ++(gUsbData->dBOTCommandTag); + BotCmdBlk->dCbwDataLength = MassXactStruc->dLength; + BotCmdBlk->bmCbwFlags = MassXactStruc->bXferDir; + BotCmdBlk->bCbwLun = DevInfo->bLUN; + BotCmdBlk->bCbwLength = CmdSize; + + return (UINT16)USBMassIssueBulkTransfer( + DevInfo, + 0, + (UINT8*)BotCmdBlk, + sizeof (BOT_CMD_BLK)); + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBBOTGetStatus +// +// Description: This function gets the BOT status sequence using +// bulk IN transfer +// +// Input: fpDevInfo Pointer to DeviceInfo structure +// +// Output: Nothing +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetBOTStatus( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + //(EIP90503)> + UINT8* CmdBuffer; + UINT16 Data; + + CmdBuffer = MassXactStruc->fpCmdBuffer; + + Data = (UINT16)USBMassIssueBulkTransfer(DevInfo, BIT7, + CmdBuffer, sizeof (BOT_STATUS_BLOCK)); + if ((Data != sizeof (BOT_STATUS_BLOCK))) { + if (gUsbData->bLastCommandStatus & USB_BULK_STALLED) { + USBMassClearBulkEndpointStall(DevInfo, BIT7); + } + Data = (UINT16)USBMassIssueBulkTransfer(DevInfo, BIT7, + CmdBuffer, sizeof (BOT_STATUS_BLOCK)); + if (gUsbData->bLastCommandStatus & USB_BULK_STALLED) { + USBMassBOTResetRecovery(DevInfo); + return USB_ERROR; + } + } + + // + // Check for valid CSW + // + if ((Data != sizeof (BOT_STATUS_BLOCK)) || + (((BOT_STATUS_BLOCK*)CmdBuffer)->dCswSignature != BOT_CSW_SIGNATURE) || + (((BOT_STATUS_BLOCK*)CmdBuffer)->dCswTag != gUsbData->dBOTCommandTag)) { + //USBMassClearBulkEndpointStall(fpDevInfo, BIT7); //(EIP63308-) + //USBMassClearBulkEndpointStall(fpDevInfo, BIT0); //(EIP63308-) + return USB_ERROR; + } + //<(EIP90503) + // + // Check for meaningful CSW + // + if (((BOT_STATUS_BLOCK*)CmdBuffer)->bmCswStatus) { + if (((BOT_STATUS_BLOCK*)CmdBuffer)->bmCswStatus > 1) { + // + // Perform reset recovery if BOT status is phase error + // + USBMassBOTResetRecovery(DevInfo); + } + return USB_ERROR; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassBOTResetRecovery +// +// DESCRIPTION: This function performs the BOT reset recovery +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMassBOTResetRecovery(DEV_INFO* fpDevInfo) +{ + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable + [fpDevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer) + (gUsbData->HcTable[fpDevInfo->bHCNumber - 1], + //(EIP20863)> + //fpDevInfo, ADSC_OUT_REQUEST_TYPE, + //(UINT16)fpDevInfo->bInterfaceNum,BOT_RESET_REQUEST_CODE, 0, 0); + fpDevInfo, ADSC_OUT_REQUEST_TYPE + (BOT_RESET_REQUEST_CODE << 8), + (UINT16)fpDevInfo->bInterfaceNum, 0, 0, 0); + //<(EIP20863) + USBMassClearBulkEndpointStall(fpDevInfo, BIT7); + USBMassClearBulkEndpointStall(fpDevInfo, BIT0); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassBOTGetMaxLUN +// +// Description: This function gets the maximum logical unit number(LUN) +// supported by the device. It is zero based value. +// +// Input: Pointer to DeviceInfo structure +// +// Output: Max LUN supported +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassBOTGetMaxLUN( + DEV_INFO* DevInfo +) +{ + UINT8 *Buffer = NULL; + UINT8 MaxLun = 0; + UINT16 Status; + + if (DevInfo->wIncompatFlags & USB_INCMPT_GETMAXLUN_NOT_SUPPORTED) { + return 0; + } + + Buffer = USB_MemAlloc(1); + ASSERT(Buffer); + if (Buffer == NULL) { + return 0; + } + + Status = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable + [DevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer) + (gUsbData->HcTable[DevInfo->bHCNumber - 1], + DevInfo, ADSC_IN_REQUEST_TYPE + (BOT_GET_MAX_LUN_REQUEST_CODE << 8), + DevInfo->bInterfaceNum, 0, Buffer, 1); + if (Status) { + MaxLun = *Buffer; + } + USB_MemFree(Buffer, 1); + + return MaxLun; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassIssueCBITransaction +// +// DESCRIPTION: This function performs a mass storage transaction using CBI +// or CB protocol. +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// fpCmdBuffer Pointer to command buffer +// bCmdSize Size of command block +// bXferDir Transfer direction +// fpBuffer Data buffer far pointer +// dwLength Amount of data to be transferred +// wPreSkip Number of bytes to skip before data +// wPostSkip Number of bytes to skip after data +// +// RETURN: Amount of data actually transferred +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +USBMassIssueCBITransaction( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + UINT32 Data = 0; + + if (!(USBMassSendCBICommand(DevInfo, MassXactStruc))) { // Returns 0 on error + return 0; + } + + if (MassXactStruc->dLength) { + Data = USBMassProcessBulkData(DevInfo, MassXactStruc); + if (!Data) { + if(gUsbData->bLastCommandStatus & USB_BULK_STALLED) { + USBMassClearBulkEndpointStall(DevInfo, MassXactStruc->bXferDir); + return Data; + } + } + } + + if(DevInfo->bProtocol != PROTOCOL_CBI_NO_INT && DevInfo->IntInEndpoint != 0) { + // + // Bypass interrupt transaction if it is CB protocol + // + USBMassCBIGetStatus(DevInfo); + } + + return Data; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// PROCEDURE: USBMassSendCBICommand +// +// DESCRIPTION: This function performs a mass storage transaction using CBI +// or CB protocol. +// +// PARAMETERS: fpDevInfo Pointer to DeviceInfo structure +// fpCmdBuffer Pointer to the command buffer +// bCmdSize Size of command block +// +// RETURN: 0xFFFF SUCCESS +// 0x00 ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassSendCBICommand( + DEV_INFO* DevInfo, + MASS_XACT_STRUC* MassXactStruc +) +{ + UINT16 RetValue; + + RetValue = (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable + [DevInfo->bHCNumber - 1]->bHCType)].pfnHCDControlTransfer) + (gUsbData->HcTable[DevInfo->bHCNumber - 1], + DevInfo, ADSC_OUT_REQUEST_TYPE, + (UINT16)DevInfo->bInterfaceNum, 0, + MassXactStruc->fpCmdBuffer, + (UINT16)MassXactStruc->bCmdSize); + + return RetValue; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassCBIGetStatus +// +// Description: This function gets the status of the mass transaction +// through an interrupt transfer +// +// Input: pDevInfo Pointer to DeviceInfo structure +// +// Output: Return value from the interrupt transfer +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +USBMassCBIGetStatus(DEV_INFO* fpDevInfo) +{ + (*gUsbData->aHCDriverTable[GET_HCD_INDEX(gUsbData->HcTable + [fpDevInfo->bHCNumber - 1]->bHCType)].pfnHCDInterruptTransfer) + (gUsbData->HcTable[fpDevInfo->bHCNumber - 1], + fpDevInfo, fpDevInfo->IntInEndpoint, + fpDevInfo->IntInMaxPkt, (UINT8*)&gUsbData->wInterruptStatus, 2); + + return ((UINT16)gUsbData->wInterruptStatus); + +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMiscIssueBulkTransfer +// +// 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 +USBMassIssueBulkTransfer(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); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassGetDeviceGeometry +// +// Description: This function fills and returns the mass get device geometry +// structure +// +// Input: fpMassGetDevGeo Pointer to mass get geometry struc +// +// Output: Return value +// fpMassGetDevGeo Pointer to mass get geometry struc +// dSenseData Sense data of the last command +// bNumHeads Number of heads +// wNumCylinders Number of cylinders +// bNumSectors Number of sectors +// wBytesPerSector Number of bytes per sector +// bMediaType Media type +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassGetDeviceGeometry( + MASS_GET_DEV_GEO *GetDevGeometry + ) +{ + DEV_INFO *DevInfo; + UINT8 DevAddr = GetDevGeometry->bDevAddr; + BOOLEAN ValidGeo; + MASS_GET_DEV_STATUS MassGetDevSts; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + + if ((!DevInfo) || (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT))) { // Error + return USB_ERROR; + } + + MassGetDevSts.bDevAddr = DevAddr; + //(EIP13457+)> + if (GetDevGeometry->bInt13FuncNum == 0x20){ + DevInfo->bLastStatus |= USB_MASS_GET_MEDIA_FORMAT; + } + if ((!DevInfo->wBlockSize) || (DevInfo->wBlockSize == 0xFFFF) || + (!(DevInfo->bLastStatus & USB_MASS_MEDIA_PRESENT) || + (GetDevGeometry->bInt13FuncNum == 0x20)) ) { +// USBMassCheckDeviceReady(fpDevInfo); + USBMassGetDeviceStatus(&MassGetDevSts); + } //<(EIP13457+) + ValidGeo = (BOOLEAN)((DevInfo->wBlockSize != 0xFFFF) && (DevInfo->wBlockSize != 0)); + ValidGeo &= (DevInfo->bLastStatus & USB_MASS_MEDIA_PRESENT); + //(EIP107198+)> + GetDevGeometry->wBytesPerSector = ValidGeo? DevInfo->wBlockSize : 0; + GetDevGeometry->LBANumHeads = ValidGeo? DevInfo->Heads : 0; + GetDevGeometry->bLBANumSectors = ValidGeo? DevInfo->bSectors : 1; + GetDevGeometry->wLBANumCyls = ValidGeo? DevInfo->wCylinders : 0; + GetDevGeometry->NumHeads = ValidGeo? DevInfo->NonLBAHeads : 0; + GetDevGeometry->bNumSectors = ValidGeo? DevInfo->bNonLBASectors : 1; + GetDevGeometry->wNumCylinders = ValidGeo? DevInfo->wNonLBACylinders : 0; + GetDevGeometry->bMediaType = DevInfo->bMediaType; + GetDevGeometry->LastLBA = ValidGeo? DevInfo->MaxLba : 0; + GetDevGeometry->BpbMediaDesc = ValidGeo? DevInfo->BpbMediaDesc : 0; + + //<(EIP107198+) + + USB_DEBUG(DEBUG_LEVEL_4, "BPS %d H %d S %d C %d MT %d\n", + DevInfo->wBlockSize, + DevInfo->Heads, + DevInfo->bSectors, + DevInfo->wCylinders, + DevInfo->bMediaType); + + return USB_SUCCESS; + +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMassReadCapacity +// +// Description: This function issues read capacity command to the mass +// device and returns the value obtained +// +// Input: fpReadCapacity Pointer to the read capacity structure +// bDevAddr USB device address of the device +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMassReadCapacity( + MASS_READ_CAPACITY *ReadCapacity +) +{ + DEV_INFO *DevInfo; + UINT8 DevAddr = ReadCapacity->bDevAddr; + + DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_INDX, 0, DevAddr, 0); + + if ((!DevInfo) || (!(DevInfo->Flag & DEV_INFO_DEV_PRESENT))) { // Error + return USB_ERROR; + } + + return USBMassReadCapacity10Command(DevInfo); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: dabc_to_abcd +// +// Description: This function swaps the bytes in dword: 0-3,1-2,2-1,3-0. Can be +// used for example in little endian->big endian conversions. +// +// Input: DWORD to swap +// +// Output: Input value with the swapped bytes in it. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 dabc_to_abcd(UINT32 dData) +{ + return (((dData & 0x000000FF) << 24) + | ((dData & 0x0000FF00) << 8) + | ((dData & 0x00FF0000) >> 8) + | ((dData & 0xFF000000) >> 24)); +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbms.c b/Core/EM/usb/rt/usbms.c new file mode 100644 index 0000000..7c24dff --- /dev/null +++ b/Core/EM/usb/rt/usbms.c @@ -0,0 +1,774 @@ +#pragma warning(disable: 4001) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/usbms.c 50 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 50 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbms.c $ +// +// 50 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 +// +// 49 4/29/15 5:29a Wilsonlee +// [TAG] EIP215830 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] CYBORG R.A.T3 Gaming Mouse left/right button has no +// function, instead DPI UP/DOWN config button has left/right click +// function. +// [RootCause] We get mouuse button data from constant data offset. +// [Solution] Mouse Data should be defining report fields that contain +// modifiable device data. +// [Files] usbms.c, usbhid.c, usbpoint.c +// +// 48 2/24/15 5:50a Wilsonlee +// [TAG] EIP149716 +// [Category] Improvement +// [Description] Error Handling in USB mouse data. +// [Files] usbms.c, usbkbd.h, syskbc.c, xhci.c +// +// 47 12/24/14 9:33p Wilsonlee +// [TAG] EIP194683 +// [Category] Improvement +// [Description] Add the flag "USB_INCMPT_HID_BOOT_PROTOCOL_ONLY" of usb +// bad device table to keep devices use boot protocol. +// [Files] usbkbd.c, usbms.c, usbhid.c, usbdef.h +// +// 46 8/12/14 3:04a Wilsonlee +// [TAG] EIP180970 +// [Category] Improvement +// [Description] Update X and Y data to usbmousedata and install +// SimplePointerProtocol interface if the mouses are using boot protocol +// interface. +// [Files] efiusbhid.c, usbms.c +// +// 45 5/06/14 5:16a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 44 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 +// +// 43 12/30/13 3:47a Wilsonlee +// [TAG] EIP148707 +// [Category] Improvement +// [Description] We need to store wheel data before clearing the buffer. +// [Files] usbms.c, efiusbms.c +// +// 42 8/22/13 6:33a Wilsonlee +// [TAG] EIP122944 +// [Category] Improvement +// [Description] Remove mouse_flag3 and check the mouse interface status +// in the CCB byte before we send the data to KBC. +// [Files] syskbc.c, usbms.c +// +// 41 7/04/13 5:46a Roberthsu +// [TAG] EIP127014 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Mouse drifting not smooth +// [RootCause] Bbecause Efi simple point protocol RelativeMovementX +// type is INT32. +// [Solution] Transfer data type to INT32. +// [Files] usbdef.h,usbhid.c,usbms.c,usbkbd.h +// +// 40 1/11/13 4:15a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 39 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 +// +// 38 8/21/12 2:33a Roberthsu +// [TAG] EIP91835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Wireless mouse auto click" problem +// [RootCause] Because button status and X Y in different packet. +// [Solution] Save button status. +// [Files] usbms.c +// +// 37 8/07/12 12:07a Roberthsu +// [TAG] EIP95351 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Usb mouse work unnormal +// [RootCause] This mouse will send garbage data. +// [Solution] Change check section +// [Files] usbms.c +// +// 36 5/03/12 6:30a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 35 9/27/11 1:40a Roberthsu +// [TAG] EIP67400 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Microsoft wireless Media Desktop 1000 can¡¦t work normal. +// [RootCause] Wireless ms report data contains usage page keyboard.And +// output data not contains vaild report id. +// [Solution] Check usage page led to decide kb or ms.Check correct +// report id with report data. +// [Files] usbkbd.c,usbhid.c,usbms.c +// +// 34 9/19/11 9:34a Lavanyap +// [TAG] EIP66198 +// [Category] Improvement +// [Description] Added Mouse Wheel support in PS2 and USB drivers. +// [Files] usbdef.h, usbms.c, efiusbms.c, ps2mouse.h, mouse.c +// +// 33 8/05/11 2:03a Ryanchou +// +// 32 7/15/11 6:11a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, +// usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, +// usbsrc.sdl, xhci.c +// +// 31 7/12/11 11:40p Ryanchou +// [TAG] EIP63752 +// [Bug fix] Left click status lost on USB Mousee. +// [Symptom] First time Getstate will return that Left Click is Pressed. +// On the Second GetState Call it will return that Left click released. +// [Root Cause] We are clearing the Button status once we send the data. +// So next time getstate will return that left click is released. +// [Solution] We should not clear the ButtonStatus.Insteed of OR the data, +// we should have taken directly from the fpBuffer. +// +// 30 5/03/11 6:56a Ryanchou +// [TAG] EIP57745 +// [Category] Improvement +// [Description] The token CHECK_MOUSE_FLAG is depend on CSM version, +// remove the token and check CSM verion to support this feature or not. +// [Files] syskbc.c, usbms.c, usbsrc.sdl +// +// 29 3/30/11 8:16a Ryanchou +// [TAG] EIP54126 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Sometimes system hangs at checkpoint 0xB4. +// [RootCause] The bLength field of configuration descriptor is zero. +// [Solution] Check wether bLength field is zero before paring next +// descriptor. +// [Files] usb.c, usbbus.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c +// +// 28 3/17/11 12:23a Ryanchou +// [TAG] EIP49214 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] USB mouse can't work on legacy free system +// [RootCause] The key repeat SMI didn't enabled. +// [Solution] Enable the key repeat SMI if receive mouse data. +// [Files] usbms.c +// +// 27 2/10/11 7:41a Ryanchou +// [TAG] EIP52206 +// [Category] Improvement +// [Description] Remote wakeup command should be sent before sleep, +// comment out the command. +// [Files] usbkbd.c, usbms.c +// +// 26 1/17/11 4:35a Ryanchou +// [TAG] EIP51108 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Some HID devices that has two interfaces can't work. +// [RootCause] BIOS using the wrong endpoint to poll KBD/MS data. +// [Solution] Get the first interrupt in endpoint when parsing +// descriptors. +// [Files] usbkbd.c, usbms.c +// +// 25 9/24/10 5:38p Olegi +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 24 9/16/10 1:08p Olegi +// - removed junk function code +// - EIP40959:: activate mouse polling depending on the project settings +// +// 23 9/08/10 8:05a Ryanchou +// EIP43822: Add a toekn "CHECK_MOUSE_FLAG", the token controls whether +// apply EIP40121 solution. +// +// 22 8/30/10 12:16p Olegi +// Send mouse data only when driver is active; EIP40121 +// +// 21 6/22/10 9:11p Olegi +// EIP39708: Added new incompatibility type for HIDs that ignore boot +// protocol. +// +// 20 5/11/10 1:52p Olegi +// Corrected the mouse data report. EIP37798 +// +// 19 11/24/09 11:39a Olegi +// EIP#29733 - BIOS adds an USB API (Block KBC Access) +// +// 18 9/10/09 3:58p Davidd +// Corrected build error caused by previous change. +// +// 17 9/10/09 9:43a Olegi +// EIP25224: When set boot protocol for mouse, the interface number may +// not be 0. Some keyboard/mouse composite devices have one more +// interface. +// +// 16 7/07/08 4:01p Olegi +// +// 15 5/16/08 12:06p Olegi +// +// 14 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 13 12/17/07 4:04p Olegi +// KBC emulation support added. +// +// 12 3/29/07 6:40p Olegi +// +// 11 3/20/07 12:20p Olegi +// +// 9 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 8 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 7 2/06/06 9:35a Andriyn +// +// 6 1/24/06 12:28p Andriyn +// +// 5 8/27/05 3:44p Andriyn +// Fix: lost mouse click when mouse is not moving +// +// 4 8/26/05 12:25p Andriyn +// Simulate Mouse Sampling rate by disabling Mouse Polling (reduce USB +// SMI# generation) +// +// 3 8/25/05 7:19p Andriyn +// USB Keyboard and mouse to use EMUL 60/64 for passing data to KBC. +// Fall-back when EMUL 60/64 is not present +// +// 2 8/04/05 5:03p Andriyn +// cosmetic changes +// +// 1 3/28/05 6:20p Olegi +// +// 2 3/18/05 9:41a Olegi +// Correction in Y coordinate calculations. +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbMs.c +// +// Description: AMI USB mouse support implementation +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" + +extern USB_GLOBAL_DATA *gUsbData; + +extern UINT8 IsKbcAccessBlocked; //(EIP29733+) + +extern EFI_EMUL6064MSINPUT_PROTOCOL* gMsInput; + +VOID USBMSInitialize (VOID); +DEV_INFO* USBMSConfigureDevice (HC_STRUC*, DEV_INFO*, UINT8*, UINT16, UINT16); +UINT8 USBMSProcessMouseData (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID USBKeyRepeat(HC_STRUC*, UINT8); +VOID SetMouseData (UINT8*, USBMS_DATA*, UINT8, UINT8, HID_REPORT_FIELD*); //(EIP127014+) +EFI_STATUS SendMouseData(PS2MouseData*); +UINT8 OrgButtonStatus = 0; //(EIP91835) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBMSInitialize +// +// Description: This routine is called once to initialize the USB mouse data +// area +// +// Input: None +// +// Output: Nothing +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +USBMSInitialize() +{ + // + // Initialize the mouse input buffer head and tail values + // + gUsbData->fpMouseInputBufferHeadPtr = &gUsbData->aMouseInputBuffer[0]; + gUsbData->fpMouseInputBufferTailPtr = &gUsbData->aMouseInputBuffer[0]; + USB_DEBUG(DEBUG_LEVEL_3, "USBMSInitialize: Head and Tail are at %x\n", gUsbData->fpMouseInputBufferHeadPtr); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBMSConfigureDevice +// +// Description: This routine checks an interface descriptor of the USB device +// detected to see if it describes a HID/Boot/Mouse device. +// If the device matches the above criteria, then the device is +// configured and initialized +// +// Input: HcStruc HCStruc pointer +// DevInfo Device information structure pointer +// Desc Pointer to the descriptor structure +// Start Offset within interface descriptor +// supported by the device +// End End offset of the device descriptor +// +// Output: FPDEV_INFO New device info structure, 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBMSConfigureDevice ( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Desc, + UINT16 Start, + UINT16 End) +{ + return NULL; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBMSProcessMouseData +// +// Description: This function is called at regular intervals with USB mouse +// report data. This function handles the translation of USB +// mouse data into PS/2 mouse data, and makes the PS/2 data +// available to software using ports 60/64 to communicate with +// a PS/2 mouse. +// +// Input: HcStruc Pointer to HCStruc +// DevInfo Pointer to device information structure +// Td Pointer to the polling TD +// Buffer Pointer to the data buffer +// +// Output: Nothing +// +// Notes: The format of 3 byte data packet is as follow: +// Byte Description +// ----------------------------------------------------------- +// 0 Bit Description +// ------------------------------------------- +// 0 If set, button 1 is pressed +// 1 If set, button 2 is pressed +// 2 If set, button 3 is pressed +// 3-7 Reserved +// ------------------------------------------- +// 1 X displacement value +// 2 Y displacement value +// ----------------------------------------------------------- +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBMSProcessMouseData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + UINT8* MachineConfigPtr = (UINT8*)(UINTN)0x410; + PS2MouseData MouseData; + USBMS_DATA TempData; + INT32 Coordinates; + HID_REPORT_FIELD *Field = NULL; + UINT8 OffsetTmp = 0; + UINT8 XStart; + UINT8 XEnd; + UINT8 YStart; + UINT8 YEnd; + UINT8 ButtonStart; + UINT8 WheelStart; + UINT8 i; + UINT16 j; + UINT8 ButtonSet = 0; + UINT8 XSet = 0; + UINT8 YSet = 0; + UINT8 WheelSet = 0; + + //Is KBC access allowed? + if (IsKbcAccessBlocked) { + return USB_SUCCESS; //(EIP29733+) + } + + MemSet(&TempData, sizeof(USBMS_DATA), 0); //(EIP127014) + + if (DevInfo->HidReport.Flag & HID_REPORT_FLAG_REPORT_PROTOCOL) { + //serach button and X Y + for (i = 0; i < DevInfo->HidReport.FieldCount; i++) { + Field = DevInfo->HidReport.Fields[i]; + + //Check if it is input? + if (!(Field->Flag & HID_REPORT_FIELD_FLAG_INPUT)) { + continue; + } + //if report id is exist, check first byte + if (Field->ReportId != 0 && Field->ReportId != Buffer[0]) { + continue; + } + + // Check if the field is contant. + if (Field->Flag & HID_REPORT_FIELD_FLAG_CONSTANT) { + OffsetTmp += Field->ReportCount * Field->ReportSize; + continue; + } + + //Check Button + if ((Field->UsagePage == 9) && (Field->UsageCount != 0) && (Field->Usages[0] == 1)) { + ButtonSet = 1; + ButtonStart = OffsetTmp; + if (Field->ReportId != 0) { + ButtonStart += 8; + } + ButtonStart /= 8; + TempData.ButtonByte = *(Buffer + ButtonStart); + } + //Check X,Y + if ((Field->UsagePage == 1) && (Field->UsageCount != 0)) { + for (j = 0; j < Field->UsageCount; j++) { + //find X + if (Field->Usages[j] == 0x30) { + XSet = 1; + XStart = (OffsetTmp + j * Field->ReportSize); + if (Field->ReportId != 0) { + XStart += 8; + } + XEnd = XStart + Field->ReportSize; + TempData.FillUsage = 0x30; //(EIP127014) + SetMouseData(Buffer, &TempData, XStart, XEnd, Field); + } + //find Y + if (Field->Usages[j] == 0x31) { + YSet = 1; + YStart = (OffsetTmp + j * Field->ReportSize); + if (Field->ReportId != 0) { + YStart += 8; + } + YEnd = YStart + Field->ReportSize; + TempData.FillUsage = 0x31; + SetMouseData(Buffer, &TempData, YStart, YEnd, Field); + } + //find Wheel + if (Field->Usages[j] == 0x38) { + WheelSet = 1; + WheelStart = (OffsetTmp + j * Field->ReportSize) / 8; + if (Field->ReportId != 0) { + WheelStart += 1; + } + TempData.Z = *(Buffer + WheelStart); + } + } + } + OffsetTmp += Field->ReportCount * Field->ReportSize; + } + + for (i = 0; i < 8; i++) { + Buffer[i] = 0; + } + + //fill MS DATA + if (ButtonSet != 0) { + *Buffer = TempData.ButtonByte; + OrgButtonStatus = TempData.ButtonByte; + } else { + *Buffer = OrgButtonStatus; + } + + if (XSet == 1) { + *(Buffer + 1) = TempData.X; + } + if (YSet == 1) { + *(Buffer + 2) = TempData.Y; + } + if (WheelSet == 1) { + *(Buffer + 3) = TempData.Z; + } + } else { + TempData.EfiX = *((INT8*)Buffer + 1); + TempData.EfiY = *((INT8*)Buffer + 2); + } + + if (DevInfo->wIncompatFlags & USB_INCMPT_BOOT_PROTOCOL_IGNORED) { + Buffer++; + } + + if ((BOOT_PROTOCOL_SUPPORT == 0) && + !(DevInfo->wIncompatFlags & USB_INCMPT_HID_BOOT_PROTOCOL_ONLY)) { + if (!(ButtonSet || XSet || YSet || WheelSet)) { + return USB_SUCCESS; + } + } + + + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + + gUsbData->MouseData.ButtonStatus = *(UINT8*)Buffer; + + Coordinates = (INT16)TempData.EfiX; //(EIP127014) + gUsbData->MouseData.MouseX += Coordinates; + + Coordinates = (INT16)TempData.EfiY; //(EIP127014) + gUsbData->MouseData.MouseY += Coordinates; + + Coordinates= *((INT8*)Buffer + 3); + gUsbData->MouseData.MouseZ += Coordinates; + + return USB_SUCCESS; // Here should be code that prepares buffer for AMIUHCD + } + + if (!(*MachineConfigPtr & BIT2)) { + return USB_SUCCESS; // No mouse indication in BIOS Data area equipment byte + } +/* + //(EIP57745+)> + // + // Check the version of CSM16, support is available for ver 7.64 or later + // + { + UINT8 MjCsmVer = *(UINT8*)0xF0018; + UINT8 MnCsmVer = *(UINT8*)0xF0019; + UINT8 mouse_flag3 = *((UINT8*)((UINTN)((*(UINT16*)0x40E) << 4) + 0x30)); + + if (MjCsmVer > 7 || MnCsmVer > 0x63) { + if(!(mouse_flag3 & BIT0)) { + return USB_SUCCESS; + } + } + } + //<(EIP57745+) +*/ + // + // Check mouse data availability + // + if (gMsInput != 0) { + // + // Get mouse status byte and prepare it. + // Bit 2, 1, 0 = Middle, right and left button status + // Bit 3 is always 1 + // + MouseData.flags = (*(UINT8*)Buffer) & 7 | 8; + + // + // Get mouse X, Y position + // + MouseData.x = (*((UINT8*)Buffer + 1)); + MouseData.y = (UINT8)(-*((INT8*)Buffer + 2)); // Y data is opposite in USB than PS2 + + // + // Verify the direction of X-axis movement + // + if (MouseData.x >= 0x80) { + MouseData.flags |= 0x10; // Negative X-axis movement + } + if (MouseData.y >= 0x80) { + MouseData.flags |= 0x20; // Negative Y-axis movement + } + + if (gUsbData->kbc_support || (gUsbData->dUSBStateFlag & USB_FLAG_6064EMULATION_ON)) { + SendMouseData(&MouseData); + USBKeyRepeat(NULL, 2); // Enable Key repeat //(EIP49214+) + } + } + + return USB_SUCCESS; +} + //(EIP127014+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SetMouseData +// +// Description: This routine checks for mouse type device from the +// interface data provided +// +// Input: bBaseClass USB base class code +// bSubClass USB sub-class code +// bProtocol USB protocol code +// +// Output: BIOS_DEV_TYPE_MOUSE type on success or 0FFH on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +SetMouseData ( + UINT8 *Buffer, + USBMS_DATA *MsData, + UINT8 Start, + UINT8 End, + HID_REPORT_FIELD *Field +) +{ + UINT8 ReportSize; + UINT8 Size; + UINT8 PreSkip; + UINT8 PostSkip; + UINT16 TempData = 0; + UINT16 MinMask = 0; + UINT16 Multi = 1; + UINT16 Resolution; + UINT16 Count = 0; + UINT16 i; + + if ((Field->PhysicalMax == 0) && (Field->PhysicalMin == 0)) { + Field->PhysicalMax = Field->LogicalMax; + Field->PhysicalMin = Field->LogicalMin; + } + if (Field->UnitExponent != 0) { + Count = (~Field->UnitExponent) + 1; + } + + for (i = 0; i < Count; i++){ + Multi = Multi * 10; + } + + Resolution = ((INT16)Field->LogicalMax - (INT16)Field->LogicalMin) * Multi / + ((INT16)Field->PhysicalMax - (INT16)Field->PhysicalMin); + + ReportSize = End - Start; + MinMask = ((~MinMask) >> ReportSize) << ReportSize; + + Size = ReportSize / 8; + + if ((ReportSize % 8) != 0) { + Size++; + } + + ASSERT(Size > 0 && Size <= sizeof(TempData)); + if ((Size == 0) || (Size > sizeof(TempData))) { + return; + } + + MemCpy(&TempData, Buffer + Start / 8, Size); + + PreSkip = Start % 8; + PostSkip = End % 8; + + if (PreSkip != 0) { + TempData = TempData >> PreSkip; + } + if (PostSkip != 0) { + TempData = TempData << PostSkip; + TempData = TempData >> PostSkip; + } + + if (TempData > Field->LogicalMax) { + TempData |= MinMask; + } + + if (MsData->FillUsage == 0x30) { + MsData->EfiX = TempData; + MsData->X = (UINT8)TempData; + } + if (MsData->FillUsage == 0x31) { + MsData->EfiY = TempData; + MsData->Y = (UINT8)TempData; + } + + return; +} + //<(EIP127014+) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbpoint.c b/Core/EM/usb/rt/usbpoint.c new file mode 100644 index 0000000..96b95b6 --- /dev/null +++ b/Core/EM/usb/rt/usbpoint.c @@ -0,0 +1,474 @@ +#pragma warning(disable: 4001) +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbpoint.c 17 4/29/15 5:29a Wilsonlee $ +// +// $Revision: 17 $ +// +// $Date: 4/29/15 5:29a $ +//**************************************************************************** +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/usbpoint.c $ +// +// 17 4/29/15 5:29a Wilsonlee +// [TAG] EIP215830 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] CYBORG R.A.T3 Gaming Mouse left/right button has no +// function, instead DPI UP/DOWN config button has left/right click +// function. +// [RootCause] We get mouuse button data from constant data offset. +// [Solution] Mouse Data should be defining report fields that contain +// modifiable device data. +// [Files] usbms.c, usbhid.c, usbpoint.c +// +// 16 4/14/15 11:46p Wilsonlee +// [TAG] EIP213778 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Issue with right button on usb absolute mouses. +// [RootCause] For the absolute device, it has digitizers page +// (UsagePage is 0xD) or button page (UsagePage is 0x9). We clear button +// data even if it is from button page. +// [Solution] Clear the unnecessary bits if the data is from digitizers +// page and return all button data if it is from button page. +// [Files] usbpoint.c +// +// 15 9/04/14 7:42a Wilsonlee +// [TAG] EIP183463 +// [Category] Improvement +// [Description] In UEFI spec, the definitions of bits within +// ActiveButtons are EFI_ABSP_TouchActive and EFI_ABS_AltActive, we don't +// support AltActive, clear the unnecessary bits. +// [Files] usbpoint.c +// +// 14 5/12/14 3:29a Wilsonlee +// [TAG] EIP168389 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Usb tip switch data may not be correct if the device is +// multi-touch. +// [RootCause] We get the data from the other point, but we only support +// one point. +// [Solution] Only get the first point data. +// [Files] usbpoint.c +// +// 13 5/06/14 5:16a Ryanchou +// [TAG] EIP166835 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Arrow keys cannot work with specific USB keyboard +// [RootCause] HID driver cannot parse a input report that includes both +// usage minimum/maximum and single usage. +// [Solution] Store the usage in the same array to determine the input +// data format. +// [Files] syskbc.c, sysnokbc.c, usbdef.h, usbhid.c, usbkbd.c, +// usbkbd.h, usbms.c, usbpoint, efiusbhid.c, efiusbpoint.c +// +// 12 2/26/14 1:56a 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 +// +// 11 3/08/13 4:18a Roberthsu +// [TAG] EIP114280 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] vPro KVM Mouse can not work. +// [RootCause] Get wrong button offset. +// [Solution] Check usagemin get correct button offset. +// [Files] usbpoint.c +// +// 10 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 9 11/10/12 6:40a 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 +// +// 8 10/26/12 8:49a Roberthsu +// [TAG] EIP101990 +// [Category] Improvement +// [Description] Add check inpurt mode. +// [Files] usbhid.c,usbpoint.c +// +// 7 9/14/12 5:11a Roberthsu +// [TAG] EIP101018 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Button funtion not work +// [RootCause] Get wrong button status offset. +// [Solution] Get correct button status offset. +// [Files] usbpoint.c +// +// 6 3/05/12 2:18a Roberthsu +// [TAG] EIP81983 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Setup menu no response after update N-trig firmware. +// [RootCause] LogicalMax need use report item's value. +// [Solution] Correct LogicalMax parameter. +// [Files] usbpoint.c +// +// 5 1/13/12 4:06a Roberthsu +// [TAG] EIP80173 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Cando touch screen cannot work . +// [RootCause] Touch screen need send set_idle command. +// [Solution] Add set_idle command. +// [Files] usbpoint.c +// +// 4 1/09/12 1:05a Roberthsu +// [TAG] EIP79323 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Touch Screen cannot work smoothly +// [RootCause] There are some empty data. +// [Solution] Check empty data then exit. +// [Files] usbpoint.c +// +// 3 11/21/11 10:58p Roberthsu +// [TAG] EIP75015 +// [Category] Improvement +// [Description] Report button status direct. +// [Files] usbpoint.c +// +// 2 8/05/11 7:32a Ryanchou +// [TAG] EIP66231 +// [Category] Improvement +// [Description] Remove token POINT_SUPPORT.Add token USB_DEV_POINT.Add +// check core version in point driver.Add check device descriptor to send +// get lang id command.Modify check button usage page. +// [Files] efiusbhid.c, efiusbpoint.c, usbbus.c, usbhid.c, usbpoint.c, +// usbsrc.sdl +// +// 1 7/15/11 6:18a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, efiusbpoint.c, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, +// usb.c, usbdef.h, usbhid.c, usbkbd.c, usbkbd.h, usbms.c, usbpoint.c, +// usbrt.cif, usbsb.c, usbsetup.c, usbsrc.sdl, xhci.c +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: UsbPoint.c +// +// Description: AMI USB Absolute Device support implementation +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" +#include <Protocol/AbsPointerProtocol.h> + +extern USB_GLOBAL_DATA *gUsbData; + +static BOOLEAN globalAbsolutePolling = TRUE; + +UINT8 USBAbsProcessMouseData (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID SetABSData (UINT8*,UINT16*,UINT8,UINT8,UINT16); +UINT16 PerviousXPosition = 0; +UINT16 PerviousYPosition = 0; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: USBAbsConfigureDevice +// +// Description: This routine checks an interface descriptor of the USB device +// detected to see if it describes a HID/Boot/Mouse device. +// If the device matches the above criteria, then the device is +// configured and initialized +// +// Input: HcStruc HCStruc pointer +// DevInfo Device information structure pointer +// Desc Pointer to the descriptor structure +// Start Offset within interface descriptor +// supported by the device +// End End offset of the device descriptor +// +// Output: FPDEV_INFO New device info structure, 0 on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +USBAbsConfigureDevice ( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Desc, + UINT16 Start, + UINT16 End +) +{ + return NULL; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: USBAbsProcessMouseData +// +// Description: +// +// Input: HcStruc Pointer to HCStruc +// DevInfo Pointer to device information structure +// Td Pointer to the polling TD +// Buffer Pointer to the data buffer +// +// Output: Nothing +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +USBAbsProcessMouseData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + USBABS_DATA AbsBuffer; + HID_REPORT_FIELD *Field = NULL; + UINT8 OffsetTmp = 0; + UINT8 XStart = 0; + UINT8 XEnd; + UINT8 YStart = 0; + UINT8 YEnd; + UINT8 ButtonStart = 0; + UINT8 ButtonEnd = 0; + UINT8 i; + UINT16 j; + UINT16 MaxX; + UINT16 MaxY; + BOOLEAN SetButtonData = FALSE; + BOOLEAN SetXData = FALSE; + BOOLEAN SetYData = FALSE; + + AbsBuffer.X =0; + AbsBuffer.Y =0; + AbsBuffer.Button =0; + + for (i = 0; i < DevInfo->HidReport.FieldCount; i++) { + Field = DevInfo->HidReport.Fields[i]; + + //Check is input? + if (!(Field->Flag & HID_REPORT_FIELD_FLAG_INPUT)) { + continue; + } + + // Check if report id is matched + if (Field->ReportId != 0 && Field->ReportId != Buffer[0]) { + continue; + } + + // Check if the field is contant. + if (Field->Flag & HID_REPORT_FIELD_FLAG_CONSTANT) { + OffsetTmp += Field->ReportCount * Field->ReportSize; + continue; + } + + if ((Field->UsagePage == 0xd) && (Field->UsageCount != 0)) { + for (j = 0; j < Field->UsageCount; j++) { + //Check Tip switch + if (Field->Usages[j] == 0x42) { //(EIP79323) + if (SetButtonData == TRUE) { + break; + } + ButtonStart = OffsetTmp; + if (Field->ReportId != 0) { + ButtonStart += 8; + } + ButtonEnd = ButtonStart + (Field->ReportSize * Field->ReportCount); //(EIP101990) + SetABSData(Buffer, (UINT16*)(&AbsBuffer.Button), ButtonStart, ButtonEnd, 0xffff); //(EIP101990) + SetButtonData = TRUE; + //In UEFI spec, the definitions of bits within ActiveButtons are EFI_ABSP_TouchActive + // and EFI_ABS_AltActive, we don't support AltActive, clear the unnecessary bits. + AbsBuffer.Button &= EFI_ABSP_TouchActive; + } + } + } + + //Check Button + if ((Field->UsagePage == 9) && (Field->UsageCount != 0) && (Field->Usages[0] == 1)) { //(EIP114280) + if (SetButtonData == TRUE) { + break; + } + ButtonStart = OffsetTmp; + if (Field->ReportId != 0) { + ButtonStart += 8; + } + ButtonEnd = ButtonStart + Field->ReportSize * Field->ReportCount; //(EIP101018) + SetABSData(Buffer, (UINT16*)(&AbsBuffer.Button), ButtonStart, ButtonEnd, 0xffff); //(EIP101018) + SetButtonData = TRUE; + } + + //Check X,Y + if ((Field->UsagePage == 1) && (Field->UsageCount != 0)) { + for (j = 0; j < Field->UsageCount; j++) { + //find X + if (Field->Usages[j] == 0x30) { + if (SetXData == TRUE) { + break; + } + XStart = OffsetTmp + (j * Field->ReportSize); + if (Field->ReportId != 0) { + XStart += 8; + } + XEnd = XStart + Field->ReportSize; + SetABSData(Buffer, &AbsBuffer.X, XStart, XEnd, Field->LogicalMax); //(EIP81983) + SetXData = TRUE; + MaxX = Field->LogicalMax; + } + + //find Y + if (Field->Usages[j] == 0x31) { + if (SetYData == TRUE) { + break; + } + YStart = OffsetTmp + (j * Field->ReportSize); + if (Field->ReportId != 0) { + YStart += 8; + } + YEnd = YStart + Field->ReportSize; + MaxY = Field->LogicalMax; + SetABSData(Buffer, &AbsBuffer.Y, YStart, YEnd, Field->LogicalMax); //(EIP81983) + SetYData = TRUE; + } + } + } + OffsetTmp += Field->ReportCount * Field->ReportSize; + } + + if (AbsBuffer.Button == 0 && AbsBuffer.X == 0 && AbsBuffer.Y == 0) { + return USB_SUCCESS; + } + + if (gUsbData->dUSBStateFlag & USB_FLAG_RUNNING_UNDER_EFI) { + gUsbData->AbsMouseData[0].ButtonStauts = AbsBuffer.Button; + gUsbData->AbsMouseData[0].Xcoordinate = AbsBuffer.X; + gUsbData->AbsMouseData[0].Ycoordinate = AbsBuffer.Y; + gUsbData->AbsMouseData[0].Pressure = 0; + gUsbData->AbsMouseData[0].Max_X = MaxX; + gUsbData->AbsMouseData[0].Max_Y = MaxY; + } + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SetABSData +// +// Description: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +SetABSData ( + UINT8 *Buffer, + UINT16 *ReportData, + UINT8 Start, + UINT8 End, + UINT16 Maxvalue +) +{ + UINT8 ReportSize; + UINT8 Size; + UINT8 PreSkip; + UINT8 PostSkip; + UINT32 TempData = 0; + + ReportSize = End - Start; + Size = ReportSize / 8; + + if ((ReportSize % 8) !=0) { + Size++; + } + + ASSERT(Size > 0 && Size <= sizeof(TempData)); + if ((Size == 0) || (Size > sizeof(TempData))) { + return; + } + + MemCpy(&TempData, Buffer + Start / 8, Size); + + PreSkip = Start % 8; + PostSkip = End % 8; + + if (PreSkip != 0) { + TempData = TempData >> PreSkip; + } + + if (PostSkip != 0) { + TempData = TempData << PostSkip; + TempData = TempData >> PostSkip; + } + + if (TempData > Maxvalue) { + TempData &= Maxvalue; + } + + *ReportData = (UINT16)TempData; + USB_DEBUG (DEBUG_LEVEL_4, "out data %x\n",*ReportData); + + return; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/usbrt.cif b/Core/EM/usb/rt/usbrt.cif new file mode 100644 index 0000000..8d3a596 --- /dev/null +++ b/Core/EM/usb/rt/usbrt.cif @@ -0,0 +1,31 @@ +<component> + name = "UsbRt" + category = ModulePart + LocalRoot = "core\em\usb\rt" + RefName = "USBRT" +[files] +"amiusb.c" +"usbkbd.c" +"debug.c" +"elib.c" +"uhci.c" +"usb.c" +"usbhub.c" +"usbmass.c" +"UsbMass.h" +"usbCCID.c" +"usbms.c" +"usbhid.c" +"usbpoint.c" +"uhci.h" +"usbkbd.h" +"ehci.c" +"ehci.h" +"ohci.c" +"ohci.h" +"guids.c" +"syskbc.c" +"sysnokbc.c" +"xhci.h" +"xhci.c" +<endComponent> diff --git a/Core/EM/usb/rt/usbrt.mak b/Core/EM/usb/rt/usbrt.mak new file mode 100644 index 0000000..ef9b570 --- /dev/null +++ b/Core/EM/usb/rt/usbrt.mak @@ -0,0 +1,241 @@ +#********************************************************************** +#********************************************************************** +#** ** +#** (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/usbrt.mak 27 10/16/16 10:15p Wilsonlee $ +# +# $Revision: 27 $ +# +# $Date: 10/16/16 10:15p $ +# +#**************************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/USB/ALASKA/rt/usbrt.mak $ +# +# 27 10/16/16 10:15p 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 +# +# 26 12/03/14 9:38p Wilsonlee +# [TAG] EIP193805 +# [Category] Improvement +# [Description] Security Enhancement for SMIHandler in USB module. +# [Files] amiusb.c, uhcd.c, usbrt.mak, usbdef.h, usbsb.c +# +# 25 3/19/13 4:02a 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 +# +# 24 11/20/12 9:07p Wilsonlee +# [TAG] EIP90887 +# [Category] New Feature +# [Description] Add a hook to check keyboard buffer for speicial chars. +# [Files] usb.sdl, usbrt.mak, usbkbd.c +# +# 23 8/29/12 8:41a Ryanchou +# [TAG] EIP77262 +# [Category] New Feature +# [Description] Remove SMM dependency of USB. +# [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +# elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +# efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +# uhcd.h, usbmisc.c, AmiUsbController.h +# +# 22 1/16/12 6:02a Ryanchou +# [TAG] EIP81132 +# [Description] Add core version check for EIP80609 solution. +# [Files] amiusb.c, usbrt.mak, usbsb.c +# +# 21 1/14/12 4:10a Ryanchou +# [TAG] EIP80609 +# [Category] Bug Fix +# [Severity] Important +# [Symptom] If to enable debug mode and set launch CSM is "Never" in +# setup, system will hang at 0xB1 +# [RootCause] The pointer AmiUsb is invalid if CSM is not launched, +# that may cause CPU exception. +# [Solution] Added USB smm protocol, and use SmmLocateProtocol to get +# the pointer. +# [Files] amiusb.c, AmiUsbController.h, usbrt.mak, usbsb.c +# +# 20 10/25/11 8:27a Wilsonlee +# [TAG] EIP71750 +# [Category] New Feature +# [Description] Support extraUSB device driver hook by elink. +# [Files] usb.c, uhcd.c, uhcd.mak, usbrt.mak, usb.sdl +# +# 19 11/22/10 8:45a Ryanchou +# [TAG] EIP48064 +# [Category] Improvement +# [Description] The SB template implemented elink +# AcpiEnableCallbackList, the XHCI/EHCI hand off function should be +# invoked via the elink AcpiEnableCallbackList. +# [Files] amidef.h, amiusb.c, amiusb.dxs, amiusb.h, +# AmiUsbController.h, usb.sdl, usbrt.mak, usbsb.c +# +# 18 11/13/09 9:14a Olegi +# EIP31023: key repeat rates are defined by SDL tokens. +# +# 17 10/30/09 5:48p Olegi +# +# 16 5/16/08 12:03p Olegi +# Compliance with AMI coding standard. +# +#**************************************************************************** + +#********************************************************************** +#<AMI_FHDR_START> +# +# Name: UsbRt.mak +# +# Description: Make file for the UsbRt component +# +#<AMI_FHDR_END> +#********************************************************************** + +all : USBRT + +!ifndef PI_SPECIFICATION_VERSION +PI_SPECIFICATION_VERSION = 0 +!endif + +!ifndef CORE_COMBINED_VERSION +CORE_COMBINED_VERSION = $(CORE_MAJOR_VERSION)*65536+$(CORE_MINOR_VERSION)*100+$(CORE_REVISION)*10+$(CORE_BUILD_NUMBER) +!endif + +USBRT : $(BUILD_DIR)\usbrt.mak UsbRtElinkList USBRTBin + +USBRT_EXT_HEADERS=\ + $(UHCD_DIR)\RT\usbdef.h\ + $(UHCD_DIR)\RT\amidef.h\ + $(UHCD_DIR)\RT\amiusb.h\ + $(BUILD_DIR)\UsbDevDriverElinks.h + +$(BUILD_DIR)\usbrt.mak : $(USBRT_DIR)\$(@B).cif $(USBRT_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(USBRT_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +UsbRtElinkList: UhcdElinkList + $(ECHO) #define USB_DEV_DELAYED_DRIVER $(USB_DEV_DELAYED_DRIVER_LIST) >> $(BUILD_DIR)\UsbDevDriverElinks.h + $(ECHO) #define USB_DEV_DRIVER $(USB_DEV_DRIVER_LIST) >> $(BUILD_DIR)\UsbDevDriverElinks.h + $(ECHO) #define KBD_BUFFER_CHECK_ELINK_LIST $(CheckKeyBoardBufferForSpecialChars) >> $(BUILD_DIR)\UsbDevDriverElinks.h + +$(BUILD_DIR)\dummyusbrt.obj: + copy << $(BUILD_DIR)\dummyusbrt.c +#include "amidef.h" +#include "usbdef.h" +#include "usbkbd.h" + +extern UINT8 UHCI_FillHCDEntries(HCD_HEADER*); +extern UINT8 OHCI_FillHCDEntries(HCD_HEADER*); +extern UINT8 EHCI_FillHCDEntries(HCD_HEADER*); +extern UINT8 XHCI_FillHCDEntries(HCD_HEADER*); +extern USB_GLOBAL_DATA *gUsbData; + +void FillHcdEntries() +{ +#if UHCI_SUPPORT + UHCI_FillHCDEntries (&gUsbData->aHCDriverTable[USB_INDEX_UHCI]); +#endif +#if OHCI_SUPPORT + OHCI_FillHCDEntries (&gUsbData->aHCDriverTable[USB_INDEX_OHCI]); +#endif +#if EHCI_SUPPORT + EHCI_FillHCDEntries (&gUsbData->aHCDriverTable[USB_INDEX_EHCI]); +#endif +#if XHCI_SUPPORT + XHCI_FillHCDEntries (&gUsbData->aHCDriverTable[USB_INDEX_XHCI]); +#endif +} +<< + $(CC) $(CFLAGS) /Fo$(BUILD_DIR)\ $(BUILD_DIR)\dummyusbrt.c /I$(UHCD_DIR) /I$(USBRT_DIR) + +!if $(USB_RUNTIME_DRIVER_IN_SMM) == 1 +!ifdef AcpiEnableCallbackList +$(BUILD_DIR)\usbsb.obj: $(USB_SB_DIR)\usbsb.c + $(CC) $(CFLAGS) /Fo$(BUILD_DIR)\ $(USB_SB_DIR)\usbsb.c /I$(USB_SB_DIR) /I$(USBRT_DIR) + +$(BUILD_DIR)\usbacpi.obj: $(USB_SB_DIR)\usbsb.c + $(CC) $(CFLAGS) /DUSB_ACPI_ENABLE_CALLBACK /Fo$(BUILD_DIR)\usbacpi.obj $(USB_SB_DIR)\usbsb.c /I$(USB_SB_DIR) /I$(USBRT_DIR) + +AcpiModeEnableBin: $(BUILD_DIR)\usbacpi.obj + +!else +$(BUILD_DIR)\usbsb.obj: $(USB_SB_DIR)\usbsb.c + $(CC) $(CFLAGS) /DUSB_ACPI_ENABLE_DISPATCH /Fo$(BUILD_DIR)\ $(USB_SB_DIR)\usbsb.c /I$(USB_SB_DIR) /I$(USBRT_DIR) + +!endif +!endif + +$(BUILD_DIR)\usbrtport.obj : $(USBPORTING_DIR)\usbport.c + $(CC) $(CFLAGS) /DUSB_RT_DRIVER /Fo$(BUILD_DIR)\UsbrtPort.obj $(USBPORTING_DIR)\usbport.c /I$(UHCD_DIR) /I$(USBRT_DIR) + +USBRTBinObjects = \ + $(BUILD_DIR)\dummyusbrt.obj \ +!if $(USB_RUNTIME_DRIVER_IN_SMM) == 1 + $(BUILD_DIR)\usbsb.obj \ + $(BUILD_DIR)\AmiBufferValidationLib.lib \ + $(BUILD_DIR)\AmiUsbSmmGlobalDataValidationLib.lib \ +!endif + $(BUILD_DIR)\usbrtport.obj + +USBRTBin : $(AMIDXELIB) $(USBRTBinObjects) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\usbrt.mak all\ + GUID=04EAAAA1-29A1-11d7-8838-00500473D4EB \ + ENTRY_POINT=USBDriverEntryPoint \ + "CFLAGS=$(CFLAGS) /I$(UHCD_DIR)"\ + "AFLAGS=$(AFLAGS) /Fl"\ + "EXT_HEADERS=$(USBRT_EXT_HEADERS)"\ +!if $(USB_RUNTIME_DRIVER_IN_SMM) == 1 && $(PI_SPECIFICATION_VERSION) >= 0x00001000A && $(CORE_COMBINED_VERSION) >= 0x4028B + TYPE=SMM_DRIVER \ + DEPEX1=$(USBRT_DIR)\amiusb.dxs \ +!else + TYPE=BS_DRIVER \ + DEPEX1=$(USBRT_DIR)\amiusb.dxs \ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ +!endif + COMPRESS=1\ + +# "CFLAGS=$(CFLAGS:/W3=/W4) /I$(UHCD_DIR)"\ + +#********************************************************************** +#********************************************************************** +#** ** +#** (C)Copyright 1985-2016, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#********************************************************************** +#********************************************************************** diff --git a/Core/EM/usb/rt/xhci.c b/Core/EM/usb/rt/xhci.c new file mode 100644 index 0000000..870e327 --- /dev/null +++ b/Core/EM/usb/rt/xhci.c @@ -0,0 +1,4306 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: XHCI.C +// +// Description: AMI XHCI driver. +// +//<AMI_FHDR_END> +//********************************************************************** + +#include "amiusb.h" +#include "amidef.h" +#include "usbdef.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +UINT8 XHCI_Start (HC_STRUC*); +UINT8 XHCI_Stop (HC_STRUC*); +UINT8 XHCI_EnumeratePorts (HC_STRUC*); +UINT8 XHCI_DisableInterrupts (HC_STRUC*); +UINT8 XHCI_EnableInterrupts (HC_STRUC*); +UINT8 XHCI_ProcessInterrupt(HC_STRUC*); +UINT8 XHCI_GetRootHubStatus (HC_STRUC*, UINT8, BOOLEAN); +UINT8 XHCI_DisableRootHub (HC_STRUC*,UINT8); +UINT8 XHCI_EnableRootHub (HC_STRUC*,UINT8); +UINT16 XHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); +UINT32 XHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); +UINT16 XHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); +UINT8 XHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 XHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 XHCI_DisableKeyRepeat (HC_STRUC*); +UINT8 XHCI_EnableKeyRepeat (HC_STRUC*); +UINT8 XHCI_EnableEndpoints (HC_STRUC*, DEV_INFO*, UINT8*); +UINT8 XHCI_InitDeviceData (HC_STRUC*,DEV_INFO*,UINT8,UINT8**); +UINT8 XHCI_DeinitDeviceData (HC_STRUC*,DEV_INFO*); +UINT8 XHCI_ResetRootHub (HC_STRUC*,UINT8); +UINT8 XHCI_ClearEndpointState(HC_STRUC*,DEV_INFO*,UINT8); //(EIP54283+) +UINT8 XHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) + +UINT8 XHCI_WaitForEvent(HC_STRUC*,XHCI_TRB*,TRB_TYPE,UINT8,UINT8,UINT8*,UINT16,VOID*); +TRB_RING* XHCI_InitXfrRing(USB3_HOST_CONTROLLER*, UINT8, UINT8); +TRB_RING* XHCI_GetXfrRing(USB3_HOST_CONTROLLER*, UINT8, UINT8); +UINT8 XHCI_GetSlotId(USB3_HOST_CONTROLLER*, DEV_INFO*); +UINT64 XHCI_Mmio64Read(HC_STRUC*, USB3_HOST_CONTROLLER*, UINTN); +VOID XHCI_Mmio64Write(HC_STRUC*, USB3_HOST_CONTROLLER*, UINTN, UINT64); +EFI_STATUS XHCI_InitRing(TRB_RING*, UINTN, UINT32, BOOLEAN); +UINT32* XHCI_GetTheDoorbell(USB3_HOST_CONTROLLER*, UINT8); +VOID UpdatePortStatusSpeed(UINT8, UINT8*); +UINT8 XHCI_ResetPort(USB3_HOST_CONTROLLER*, UINT8, BOOLEAN); +BOOLEAN XHCI_IsUsb3Port(USB3_HOST_CONTROLLER*, UINT8); +UINT8 XhciRingDoorbell(USB3_HOST_CONTROLLER*, UINT8, UINT8); +EFI_STATUS XhciExtCapParser(USB3_HOST_CONTROLLER*); +UINT8 XhciAddressDevice (HC_STRUC*, DEV_INFO*, UINT8); + +DEV_INFO* XHCI_GetDevInfo(UINTN); +VOID* XHCI_GetDeviceContext(USB3_HOST_CONTROLLER*, UINT8); +VOID* XHCI_GetContextEntry(USB3_HOST_CONTROLLER*, VOID*, UINT8); + +UINT8 UsbHubGetHubDescriptor(HC_STRUC*, DEV_INFO*, VOID*, UINT16); + +VOID MemFill (UINT8*, UINT32, UINT8); +UINT8 USB_ResetHubPort(HC_STRUC*, UINT8, UINT8); +UINT8 USB_DisconnectDevice (HC_STRUC*, UINT8, UINT8); +UINT8 USB_GetHubPortStatus(HC_STRUC*, UINT8, UINT8, BOOLEAN); + +UINT32 ReadPCIConfig(UINT16, UINT8); + +VOID USBKeyRepeat(HC_STRUC*, UINT8); + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +#if USB_DEV_KBD +VOID USBKBDPeriodicInterruptHandler(HC_STRUC*); +#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_FillHCDEntries +// +// Description: +// This function fills the host controller driver routine pointers. +// +// Input: +// Ptr to the host controller header structure +// +// Output: +// Status: USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_FillHCDEntries ( + HCD_HEADER *fpHCDHeader +) +{ + fpHCDHeader->pfnHCDStart = XHCI_Start; + fpHCDHeader->pfnHCDStop = XHCI_Stop; + fpHCDHeader->pfnHCDEnumeratePorts = XHCI_EnumeratePorts; + fpHCDHeader->pfnHCDDisableInterrupts = XHCI_DisableInterrupts; + fpHCDHeader->pfnHCDEnableInterrupts = XHCI_EnableInterrupts; + fpHCDHeader->pfnHCDProcessInterrupt = XHCI_ProcessInterrupt; + fpHCDHeader->pfnHCDGetRootHubStatus = XHCI_GetRootHubStatus; + fpHCDHeader->pfnHCDDisableRootHub = XHCI_DisableRootHub; + fpHCDHeader->pfnHCDEnableRootHub = XHCI_EnableRootHub; + fpHCDHeader->pfnHCDControlTransfer = XHCI_ControlTransfer; + fpHCDHeader->pfnHCDBulkTransfer = XHCI_BulkTransfer; + fpHCDHeader->pfnHCDInterruptTransfer = XHCI_InterruptTransfer; + fpHCDHeader->pfnHCDDeactivatePolling = XHCI_DeactivatePolling; + fpHCDHeader->pfnHCDActivatePolling = XHCI_ActivatePolling; + fpHCDHeader->pfnHCDDisableKeyRepeat = XHCI_DisableKeyRepeat; + fpHCDHeader->pfnHCDEnableKeyRepeat = XHCI_EnableKeyRepeat; + fpHCDHeader->pfnHCDEnableEndpoints = XHCI_EnableEndpoints; + fpHCDHeader->pfnHCDInitDeviceData = XHCI_InitDeviceData; + fpHCDHeader->pfnHCDDeinitDeviceData = XHCI_DeinitDeviceData; + fpHCDHeader->pfnHCDResetRootHub = XHCI_ResetRootHub; + fpHCDHeader->pfnHCDClearEndpointState = XHCI_ClearEndpointState; //(EIP54283+) + fpHCDHeader->pfnHCDGlobalSuspend = XHCI_GlobalSuspend; //(EIP54018+) + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_Start +// +// Description: +// This API function is called to start a XHCI host controller. The input +// to the routine is the pointer to the HC structure that defines this host +// controller. The procedure flow is followed as it is described in 4.2 of +// XHCI specification. +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_SUCCESS = Success, USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_Start ( + HC_STRUC *HcStruc +) +{ + XHCI_INTERRUPTER_REGS *Interrupter; + XHCI_ER_SEGMENT_ENTRY *Erst0Entry; + UINT32 i; + BOOLEAN PpSet = FALSE; + UINT8 PortNumber; + volatile XHCI_PORTSC *PortSC; + UINT32 LegCtlStsReg = 0; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + HcStruc->BaseAddress = (UINTN)Usb3Hc->CapRegs; + HcStruc->bNumPorts = Usb3Hc->MaxPorts; + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)HcStruc->BaseAddress, HcStruc->BaseAddressSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Usb Mmio address is invalid, it is in SMRAM\n"); + return USB_ERROR; + } +#endif + + if (((VOID*)Usb3Hc->OpRegs < (VOID*)HcStruc->BaseAddress) || + ((VOID*)(Usb3Hc->OpRegs + sizeof(XHCI_HC_OP_REGS)) > (VOID*)(HcStruc->BaseAddress + HcStruc->BaseAddressSize))) { + return USB_ERROR; + } + + // Wait controller ready + for (i = 0; i < 1000; i++) { + if (Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0) break; + FixedDelay(100); // 100 us delay + } +// ASSERT(Usb3Hc->OpRegs->UsbSts.Field.Cnr == 0); + if (Usb3Hc->OpRegs->UsbSts.Field.Cnr) return USB_ERROR; + + // Check if the xHC is halted + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0) { + Usb3Hc->OpRegs->UsbCmd.AllBits &= ~XHCI_CMD_RS; + // The xHC should halt within 16 ms. Section 5.4.1.1 + for (i = 0; i < 160; i++) { + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) break; + FixedDelay(100); // 100 us delay + } + ASSERT(Usb3Hc->OpRegs->UsbSts.Field.HcHalted); + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0) return USB_ERROR; + } +#if XHCI_COMPLIANCE_MODE_WORKAROUND + for (PortNumber = 1; PortNumber <= Usb3Hc->MaxPorts; PortNumber++) { + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1))); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + if (PortSC->Field.Pls == XHCI_PORT_LINK_COMPLIANCE_MODE) { + XHCI_ResetPort(Usb3Hc, PortNumber, FALSE); + } + } +#endif + // Reset controller + if ((Usb3Hc->DbCapRegs == NULL) || (Usb3Hc->DbCapRegs->DcCtrl.Dce == 0)) { + Usb3Hc->OpRegs->UsbCmd.AllBits |= XHCI_CMD_HCRST; + for (i = 0; i < 8000; i++) { + if (Usb3Hc->OpRegs->UsbCmd.Field.HcRst == 0) { + break; + } + FixedDelay(100); // 100 us delay + } + ASSERT(Usb3Hc->OpRegs->UsbCmd.Field.HcRst == 0); + if (Usb3Hc->OpRegs->UsbCmd.Field.HcRst) { + return USB_ERROR; // Controller can not be reset + } + } + + if ((Usb3Hc->CapRegs->RtsOff + (sizeof(UINT32) * 8) + (sizeof(XHCI_INTERRUPTER_REGS) * Usb3Hc->CapRegs->HcsParams1.MaxIntrs)) + > HcStruc->BaseAddressSize) { + return USB_ERROR; + } + + Usb3Hc->RtRegs = (XHCI_HC_RT_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->RtsOff); + USB_DEBUG(3, "XHCI: RT registers are at %x\n", Usb3Hc->RtRegs); + + Usb3Hc->OpRegs->Config = Usb3Hc->MaxSlots; // Max device slots enabled + + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->DcbAap, (UINT64)(UINTN)Usb3Hc->DcbaaPtr); + + // Check if xHC support 64bit access capability + if (Usb3Hc->Access64) { + if(XHCI_Mmio64Read(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->DcbAap) != (UINT64)(UINTN)Usb3Hc->DcbaaPtr) { + Usb3Hc->Access64 = 0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->DcbAap, (UINT64)(UINTN)Usb3Hc->DcbaaPtr); + } + } + + // Define the Command Ring Dequeue Pointer by programming the Command Ring + // Control Register (5.4.5) with a 64-bit address pointing to the starting + // address of the first TRB of the Command Ring. + + // Initialize Command Ring Segment: Size TRBS_PER_SEGMENT*16, 64 Bytes aligned + XHCI_InitRing(&Usb3Hc->CmdRing, (UINTN)Usb3Hc->DcbaaPtr + 0x2000, TRBS_PER_SEGMENT, TRUE); + USB_DEBUG(3, "CMD Ring is at %x\n", (UINTN)&Usb3Hc->CmdRing); + + // Write CRCR HC register with the allocated address. Set Ring Cycle State to 1. + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->Crcr, + (UINT64)(UINTN)Usb3Hc->CmdRing.Base + CRCR_RING_CYCLE_STATE); + + // Initialize and assign Event Ring + XHCI_InitRing(&Usb3Hc->EvtRing, (UINTN)Usb3Hc->DcbaaPtr + 0x2400, TRBS_PER_SEGMENT, FALSE); + USB_DEBUG(3, "EVT Ring is at %x\n", (UINTN)&Usb3Hc->EvtRing); + + // NOTE: This driver supports one Interrupter, hence it uses + // one Event Ring segment with TRBS_PER_SEGMENT TRBs in it. + + // Initialize ERST[0] + Erst0Entry = (XHCI_ER_SEGMENT_ENTRY*)((UINTN)Usb3Hc->DcbaaPtr + 0x1200); + Erst0Entry->RsBase = (UINT64)(UINTN)Usb3Hc->EvtRing.Base; + Erst0Entry->RsSize = TRBS_PER_SEGMENT; + + Interrupter = Usb3Hc->RtRegs->IntRegs; + + // Initialize Interrupter fields + Interrupter->Erstz = 1; // # of segments + // ER dequeue pointer + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Interrupter->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr); + // Seg Table location + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Interrupter->Erstba, (UINT64)(UINTN)Erst0Entry); + Interrupter->IMod = XHCI_IMODI; // Max interrupt rate + Usb3Hc->OpRegs->UsbCmd.AllBits |= XHCI_CMD_INTE; + Interrupter->IMan |= 2; // Enable interrupt + + USB_DEBUG(3, "Transfer Rings structures start at %x\n", Usb3Hc->XfrRings); + + // Set PortPower unless PowerPortControl indicates otherwise + if (Usb3Hc->CapRegs->HccParams1.Ppc != 0) { + for (PortNumber = 1; PortNumber <= Usb3Hc->MaxPorts; PortNumber++) { + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (PortNumber - 1))); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + if (PortSC->Field.Pp == 0) { + PortSC->Field.Pp = 1; // Set port power + PpSet = TRUE; + } + } + if (PpSet) FixedDelay(20 * 1000); // Wait for 20 ms, Section 5.4.8 + } + + // If xHC doesn't support HW SMI, should not touch USB Legacy Support Capability registers + //if (((HcStruc->dHCFlag & HC_STATE_EXTERNAL) && (XHCI_EVENT_SERVICE_MODE == 0)) || + // (USB_RUNTIME_DRIVER_IN_SMM == 0)) { + // Usb3Hc->ExtLegCap = NULL; + //} + + // Check if USB Legacy Support Capability is present. + if (Usb3Hc->ExtLegCap) { + // Set HC BIOS Owned Semaphore flag + Usb3Hc->ExtLegCap->LegSup.HcBiosOwned = 1; + //If XHCI doesn't support HW SMI, should not enable USB SMI in Legacy Support Capability register. + if (((!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) || (XHCI_EVENT_SERVICE_MODE != 0)) && + (USB_RUNTIME_DRIVER_IN_SMM != 0)) { + // Enable USB SMI, Ownership Change SMI and clear all status + LegCtlStsReg = Usb3Hc->ExtLegCap->LegCtlSts.AllBits; + LegCtlStsReg |= XHCI_SMI_ENABLE | XHCI_SMI_OWNERSHIP_CHANGE_ENABLE | + XHCI_SMI_OWNERSHIP_CHANGE | XHCI_SMI_PCI_CMD | XHCI_SMI_PCI_BAR; + Usb3Hc->ExtLegCap->LegCtlSts.AllBits = LegCtlStsReg; + } + } + + Usb3Hc->OpRegs->UsbCmd.AllBits |= XHCI_CMD_RS; + + for (i = 0; i < 100; i++) { + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0) { + break; + } + FixedDelay(100); + } + ASSERT(Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0); + + HcStruc->dHCFlag |= HC_STATE_RUNNING; + + // Set USB_FLAG_DRIVER_STARTED flag when HC is running. + if (!(gUsbData->dUSBStateFlag & USB_FLAG_DRIVER_STARTED)) { + gUsbData->dUSBStateFlag |= USB_FLAG_DRIVER_STARTED; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) { + UsbInstallHwSmiHandler(HcStruc); + } else { + USBSB_InstallXhciHwSmiHandler(); + } + if (HcStruc->HwSmiHandle != NULL) { + USBKeyRepeat(HcStruc, 0); + } +#endif + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_Stop +// +// Description: +// This function stops the XHCI controller. +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_Stop ( + HC_STRUC *HcStruc +) +{ + UINT8 Port; + UINT32 i; + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + XHCI_INTERRUPTER_REGS *Interrupter = NULL; + UINT32 LegCtlStsReg = 0; + UINT8 CompletionCode = 0; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + // Set the flag to aviod port enumeration + gUsbData->bEnumFlag = TRUE; // disable recursive enumeration + + for (Port = 1; Port <= Usb3Hc->MaxPorts; Port++) { + USB_DisconnectDevice(HcStruc, HcStruc->bHCNumber | BIT7, Port); + } + + // Port Change Detect bit may set by disabling ports. + //Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_PCD; + + if (XHCI_Mmio64Read(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->Crcr) & CRCR_COMMAND_RUNNING) { + // Stop the command ring + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->Crcr, CRCR_COMMAND_STOP); + + CompletionCode = XHCI_TRB_CMDRINGSTOPPED; + XHCI_WaitForEvent( + HcStruc, NULL, XhciTCmdCompleteEvt, 0, 0, + &CompletionCode, XHCI_CMD_COMPLETE_TIMEOUT_MS, NULL); + } + + XHCI_ProcessInterrupt(HcStruc); + + // Clear the port enumeration flag + gUsbData->bEnumFlag = FALSE; + + // Disable interrupt + Usb3Hc->OpRegs->UsbCmd.AllBits &= ~XHCI_CMD_INTE; + Interrupter = Usb3Hc->RtRegs->IntRegs; + Interrupter->IMan &= ~BIT1; + + // Clear the Run/Stop bit + Usb3Hc->OpRegs->UsbCmd.AllBits &= ~XHCI_CMD_RS; + + // The xHC should halt within 16 ms. Section 5.4.1.1 + for (i = 0; i < 160; i++) { + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) break; + FixedDelay(100); + } + ASSERT(Usb3Hc->OpRegs->UsbSts.Field.HcHalted); + //if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted == 0) return USB_ERROR; + + // Check if USB Legacy Support Capability is present. + if(Usb3Hc->ExtLegCap != 0) { + // Clear HC BIOS Owned Semaphore flag + Usb3Hc->ExtLegCap->LegSup.HcBiosOwned = 0; + if (((!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) || (XHCI_EVENT_SERVICE_MODE != 0)) && + (USB_RUNTIME_DRIVER_IN_SMM != 0)) { + // Disable USB SMI and Clear all status + LegCtlStsReg = Usb3Hc->ExtLegCap->LegCtlSts.AllBits; + LegCtlStsReg &= ~XHCI_SMI_ENABLE; + LegCtlStsReg |= XHCI_SMI_OWNERSHIP_CHANGE | XHCI_SMI_PCI_CMD | XHCI_SMI_PCI_BAR; + Usb3Hc->ExtLegCap->LegCtlSts.AllBits = LegCtlStsReg; + } + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (HcStruc->HwSmiHandle != NULL) { + USBKeyRepeat(HcStruc, 3); + } +#endif + + // Set the HC state to stopped + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + + CheckBiosOwnedHc(); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_EnumeratePorts +// +// Description: +// This function enumerates the HC ports for devices. +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_EnumeratePorts( + HC_STRUC *HcStruc +) +{ + //(EIP60327)> + UINT8 Count; + UINT8 Port; + USB3_HOST_CONTROLLER *Usb3Hc; + EFI_STATUS EfiStatus; + + if (gUsbData->bEnumFlag == TRUE) { + return USB_SUCCESS; + } + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR;; + } + + USB_DEBUG(3, "XHCI_EnumeratePorts..\n"); + gUsbData->bIgnoreConnectStsChng = TRUE; //(EIP71962+) + gUsbData->bEnumFlag = TRUE; // disable recursive enumeration + + if (Usb3Hc->Usb2Protocol) { + for(Count = 0; Count < Usb3Hc->Usb2Protocol->PortCount; Count++) { + Port = Count + Usb3Hc->Usb2Protocol->PortOffset; + USBCheckPortChange(HcStruc, HcStruc->bHCNumber | BIT7, Port); + } + } + + if (Usb3Hc->Usb3Protocol) { + for(Count = 0; Count < Usb3Hc->Usb3Protocol->PortCount; Count++) { + Port = Count + Usb3Hc->Usb3Protocol->PortOffset; + if (Usb3Hc->Vid == XHCI_VL800_VID && Usb3Hc->Did == XHCI_VL800_DID) { + XHCI_ResetPort(Usb3Hc, Port , TRUE); + } + USBCheckPortChange(HcStruc, HcStruc->bHCNumber | BIT7, Port); + } + } + +// Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_PCD; // Clear PortChangeDetect + + gUsbData->bIgnoreConnectStsChng = FALSE; //(EIP71962+) + gUsbData->bEnumFlag = FALSE; // enable enumeration + + XHCI_ProcessInterrupt(HcStruc); + //<(EIP60327) + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_EnableInterrupts +// +// Description: +// This function enables the HC interrupts +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_ERROR On error, USB_SUCCESS On success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_EnableInterrupts ( + HC_STRUC* HcStruc +) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_DisableInterrupts +// +// Description: +// This function disables the HC interrupts +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_DisableInterrupts ( + HC_STRUC* HcStruc +) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_AdvanceEnqueuePtr +// +// Description: +// This function advances returns the pointer to the current TRB and anvances +// dequeue pointer. If the advance pointer is Link TRB, then it: 1) activates +// Link TRB by updating its cycle bit, 2) updates dequeue pointer to the value +// pointed by Link TRB. +// +// Input: +// Ring - TRB ring to be updated +// +// Output: +// TRB that can be used for command, transfer, etc. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +XHCI_TRB* +XHCI_AdvanceEnqueuePtr( + TRB_RING *Ring +) +{ + XHCI_TRB* Trb = Ring->QueuePtr; + EFI_STATUS Status = EFI_SUCCESS; + + if (Trb->TrbType == XhciTLink) { + Trb->CycleBit = Ring->CycleBit; + Ring->CycleBit ^= 1; + Ring->QueuePtr = Ring->Base; + + Trb = Ring->QueuePtr; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Trb, sizeof(XHCI_TRB)); + if (EFI_ERROR(Status)) { + return NULL; + } +#endif + // Clear the TRB + *(UINT32*)Trb = 0; + *((UINT32*)Trb + 1) = 0; + *((UINT32*)Trb + 2) = 0; + *((UINT32*)Trb + 3) &= BIT0; // Keep cycle bit + + //Trb->CycleBit = Ring->CycleBit; + Ring->QueuePtr++; + + return Trb; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_WaitForEvent +// +// Description: +// This function walks through the active TRBs in the event ring and looks for +// the command TRB to be complete. If found, returns SlotId and CompletionCode +// from the completed event TRB. In the end it processes the event ring, +// adjusting its Dequeue Pointer. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + //(EIP62376)> +UINT8 +XHCI_WaitForEvent( + HC_STRUC *HcStruc, + XHCI_TRB *TrbToCheck, + TRB_TYPE EventType, + UINT8 SlotId, + UINT8 Dci, + UINT8 *CompletionCode, + UINT16 TimeOutMs, + VOID *Data +) +{ + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + XHCI_TRB *Trb; + UINT32 Count; + UINT8 Status; + UINT8 CycleBit; + UINT32 TimeoutValue = ((UINT32)TimeOutMs) * 100; // in 10 macrosecond unit + XHCI_NORMAL_XFR_TRB *ResidualTrb; //(EIP82555+) + EFI_STATUS EfiStatus = EFI_SUCCESS; + + for (Count = 0; TimeoutValue == 0 || Count < TimeoutValue; Count++) { + for (Trb = Usb3Hc->EvtRing.QueuePtr, + CycleBit = Usb3Hc->EvtRing.CycleBit;;) { +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)Trb, sizeof(XHCI_TRB)); + if (EFI_ERROR(EfiStatus)) { + break; + } +#endif + if (Trb->CycleBit != CycleBit) { + // Command is not complete, break and retry + break; + } + + // Active TRB found + if (Trb->TrbType == EventType) { + if (EventType == XhciTCmdCompleteEvt) { + if (TrbToCheck) { + if((*(UINTN*)&Trb->Param1) == (UINTN)TrbToCheck) { + if (Data != NULL) { + *(UINT8*)Data = ((XHCI_CMDCOMPLETE_EVT_TRB*)Trb)->SlotId; + } + *CompletionCode = Trb->CompletionCode; + Status = Trb->CompletionCode == XHCI_TRB_SUCCESS? USB_SUCCESS:USB_ERROR; + goto DoneWaiting; + } + } else { + if (*CompletionCode != 0 && Trb->CompletionCode == *CompletionCode) { + Status = USB_SUCCESS; + goto DoneWaiting; + } + } + } else if (EventType == XhciTTransferEvt) { + if (((XHCI_TRANSFER_EVT_TRB*)Trb)->SlotId == SlotId && + ((XHCI_TRANSFER_EVT_TRB*)Trb)->EndpointId == Dci) { + if (Data != NULL) { + *(UINT32*)Data = ((XHCI_TRANSFER_EVT_TRB*)Trb)->TransferLength; + //(EIP82555+)> + if (Trb->CompletionCode == XHCI_TRB_SHORTPACKET) { + ResidualTrb = (XHCI_NORMAL_XFR_TRB*)(UINTN)((XHCI_TRANSFER_EVT_TRB*)Trb)->TrbPtr; + while (1) { + ResidualTrb->Isp = 0; + ResidualTrb->Ioc = 0; + if (ResidualTrb->Chain != 1) { + break; + } + ResidualTrb++; + if (ResidualTrb->TrbType == XhciTLink) { + ResidualTrb = (XHCI_NORMAL_XFR_TRB*)(UINTN)((XHCI_LINK_TRB*)ResidualTrb)->NextSegPtr; + } + *(UINT32*)Data += ResidualTrb->XferLength; + } + } + //<(EIP82555+) + } + *CompletionCode = Trb->CompletionCode; + Status = (Trb->CompletionCode == XHCI_TRB_SUCCESS || + Trb->CompletionCode == XHCI_TRB_SHORTPACKET)? USB_SUCCESS:USB_ERROR; + goto DoneWaiting; + } + } + } + // Advance TRB pointer + if (Trb == Usb3Hc->EvtRing.LastTrb) { + Trb = Usb3Hc->EvtRing.Base; + CycleBit ^= 1; + } else { + Trb++; + } + if (Trb == Usb3Hc->EvtRing.QueuePtr) { + // Event ring is full, return error + USB_DEBUG(3, "XHCI: Event Ring is full...\n"); + ASSERT(0); + *CompletionCode = XHCI_TRB_EVENTRINGFULL_ERROR; + Status = USB_ERROR; + break; + } + } + FixedDelay(10); // 10 us out of TimeOutMs + } + + USB_DEBUG(3, "XHCI: execution time-out.\n"); + + *CompletionCode = XHCI_TRB_EXECUTION_TIMEOUT_ERROR; + Status = USB_ERROR; + +DoneWaiting: + XHCI_ProcessInterrupt(HcStruc); + + return Status; +} + //<(EIP62376) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ExecuteCommand +// +// Description: +// This function places a given command in the Command Ring, rings HC doorbell, +// and waits for the command completion. +// +// Output: +// USB_ERROR on execution failure, otherwise USB_SUCCESS +// Params - pointer to the command specific data. +// +// Notes: +// Caller is responsible for a data placeholder. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ExecuteCommand( + HC_STRUC *HcStruc, + TRB_TYPE Cmd, + VOID *Params +) +{ + volatile UINT32 *Doorbell; + UINT8 CompletionCode = 0; + UINT8 SlotId; + UINT8 Status; + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + XHCI_TRB *Trb = XHCI_AdvanceEnqueuePtr(&Usb3Hc->CmdRing); + UINT16 TimeOut = XHCI_CMD_COMPLETE_TIMEOUT_MS; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + if (Trb == NULL) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)Trb, sizeof(XHCI_TRB)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR;; + } +#endif + + Trb->TrbType = Cmd; // Set TRB type + + // Fill in the command TRB fields + switch (Cmd) { + case XhciTAddressDeviceCmd: + TimeOut = XHCI_ADDR_CMD_COMPLETE_TIMEOUT_MS; + ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->InpCtxAddress = (UINT64)(UINTN)Usb3Hc->InputContext; + ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params); + ((XHCI_ADDRESSDEV_CMD_TRB*)Trb)->Bsr = *((UINT8*)Params + 1); + break; + case XhciTEvaluateContextCmd: + case XhciTConfigureEndpointCmd: + ((XHCI_CONFIGURE_EP_CMD_TRB*)Trb)->InpCtxAddress = (UINT64)(UINTN)Usb3Hc->InputContext; + ((XHCI_CONFIGURE_EP_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params); + ((XHCI_CONFIGURE_EP_CMD_TRB*)Trb)->Dc = 0; + break; + case XhciTResetEndpointCmd: + ((XHCI_RESET_EP_CMD_TRB*)Trb)->Tsp = 0; + ((XHCI_RESET_EP_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params); + ((XHCI_RESET_EP_CMD_TRB*)Trb)->EndpointId = *((UINT8*)Params+1); + break; + case XhciTSetTRDequeuePointerCmd: + ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->TrPointer = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->TrPointer; + ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->EndpointId = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->EndpointId; + ((XHCI_SET_TRPTR_CMD_TRB*)Trb)->SlotId = ((XHCI_SET_TRPTR_CMD_TRB*)Params)->SlotId; + break; + case XhciTDisableSlotCmd: + ((XHCI_DISABLESLOT_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params); + break; + //(EIP54300+)> + case XhciTStopEndpointCmd: + ((XHCI_STOP_EP_CMD_TRB*)Trb)->SlotId = *((UINT8*)Params); + ((XHCI_STOP_EP_CMD_TRB*)Trb)->EndpointId = *((UINT8*)Params+1); + break; + //<(EIP54300+) + } + + Trb->CycleBit = Usb3Hc->CmdRing.CycleBit; + + // Ring the door bell and see Event Ring update + Doorbell = (UINT32*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->DbOffset); + *Doorbell = 0; // HC doorbell is #0 + + Status = XHCI_WaitForEvent( + HcStruc, Trb, XhciTCmdCompleteEvt, 0, 0, //(EIP62376) + &CompletionCode, TimeOut, &SlotId); + + if (Status == USB_ERROR) { + USB_DEBUG(3, "XHCI command completion error code: %d\n", CompletionCode); + if (CompletionCode == XHCI_TRB_EXECUTION_TIMEOUT_ERROR) { + XHCI_Mmio64Write(HcStruc, Usb3Hc, (UINTN)&Usb3Hc->OpRegs->Crcr, CRCR_COMMAND_ABORT); + + CompletionCode = XHCI_TRB_COMMANDABORTED; + XHCI_WaitForEvent( + HcStruc, Trb, XhciTCmdCompleteEvt, 0, 0, + &CompletionCode, XHCI_CMD_COMPLETE_TIMEOUT_MS, NULL); + } + return Status; + } + + switch (Cmd) { + case XhciTEnableSlotCmd: + USB_DEBUG(3, "XHCI: Enable Slot command complete, SlotID %d\n", SlotId); + *((UINT8*)Params) = SlotId; + break; + case XhciTEvaluateContextCmd: + USB_DEBUG(3, "XHCI: Evaluate Context command complete.\n"); + break; + case XhciTConfigureEndpointCmd: + USB_DEBUG(3, "XHCI: Configure Endpoint command complete.\n"); + break; + case XhciTResetEndpointCmd: + USB_DEBUG(3, "XHCI: Reset Endpoint command complete (slot#%x dci#%x).\n", + *((UINT8*)Params), *((UINT8*)Params+1)); + // Xhci speci 1.1 4.6.8 Reset Endpoint + // Software shall be responsible for timing the Reset "recovery interval" required by USB. + FixedDelay(XHCI_RESET_EP_DELAY_MS * 1000); + break; + case XhciTSetTRDequeuePointerCmd: + USB_DEBUG(3, "XHCI: Set TR pointer command complete.\n"); + break; + case XhciTDisableSlotCmd: + USB_DEBUG(3, "XHCI: DisableSlot command complete.\n"); + break; + //(EIP54300+)> + case XhciTStopEndpointCmd: + USB_DEBUG(3, "XHCI: Stop Endpoint command complete (slot#%x dci#%x).\n", + *((UINT8*)Params), *((UINT8*)Params+1)); + break; + //<(EIP54300+) + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ProcessPortChanges +// +// Description: +// This function process root hub port changes. +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_SUCCESS or USB_ERROR +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ProcessPortChanges( + HC_STRUC *HcStruc, + USB3_HOST_CONTROLLER *Usb3Hc +) +{ + UINT8 Port; + BOOLEAN PortChanged; + volatile XHCI_PORTSC *PortSC; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + + if (gUsbData->bEnumFlag == TRUE) return USB_SUCCESS; + + gUsbData->bEnumFlag = TRUE; // disable recursive enumeration + + FixedDelay(XHCI_WAIT_PORT_STABLE_DELAY_MS * 1000); + + do { + PortChanged = FALSE; + + for (Port = 1; Port <= Usb3Hc->MaxPorts; Port++) { + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (Port - 1))); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + if (PortSC->Field.Csc) { + USBCheckPortChange(HcStruc, HcStruc->bHCNumber | BIT7, Port); + PortChanged = TRUE; + } + } + } while (PortChanged); + + Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_PCD; // Clear PortChangeDetect + + gUsbData->bEnumFlag = FALSE; // enable enumeration + + return USB_SUCCESS; +} + + //(EIP54283+)> +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_ResetEndpoint +// +// Description: +// This function is called to reset endpoint. +// +// Input: +// Stalled EP data - SlotId and DCI +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ResetEndpoint( + USB3_HOST_CONTROLLER *Usb3Hc, + HC_STRUC *HcStruc, + UINT8 SlotId, + UINT8 Dci +) +{ + UINT16 EpInfo; + UINT8 Status = USB_SUCCESS; + XHCI_EP_CONTEXT *EpCtx; + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, + XHCI_GetDeviceContext(Usb3Hc, SlotId), Dci); + + // The Reset Endpoint Command is issued by software to recover + // from a halted condition on an endpoint. + if (EpCtx->EpState == XHCI_EP_STATE_HALTED) { + // Reset stalled endpoint + EpInfo = (Dci << 8) + SlotId; + Status = XHCI_ExecuteCommand(HcStruc, XhciTResetEndpointCmd, &EpInfo); + } + //ASSERT(Status == USB_SUCCESS); + return Status; +} + //<(EIP54283+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_ClearStalledEp +// +// Description: +// This function is called to restart endpoint. After Endpoint STALLs, it +// transitions from Halted to Stopped state. It is restored back to Running +// state by moving the endpoint ring dequeue pointer past the failed control +// transfer with a Set TR Dequeue Pointer. Then it is restarted by ringing the +// doorbell. Alternatively endpint is restarted using Configure Endpoint command. +// +// Input: +// Stalled EP data - SlotId and DCI +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ClearStalledEp( + USB3_HOST_CONTROLLER *Usb3Hc, + HC_STRUC *HcStruc, + UINT8 SlotId, + UINT8 Dci +) +{ + UINT16 EpInfo; + TRB_RING *XfrRing; + UINT8 Status; + XHCI_SET_TRPTR_CMD_TRB Trb; + XHCI_EP_CONTEXT *EpCtx; +// volatile UINT32 *Doorbell; //(EIP61849-) + +/* +Stalled Endpoints By Sarah Sharp, Linux XHCI driver developer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + When a control endpoint stalls, the next control transfer will clear the stall. +The USB core doesn't call down to the host controller driver's endpoint_reset() +method when control endpoints stall, so the xHCI driver has to do all its stall +handling for internal state in its interrupt handler. + + When the host stalls on a control endpoint, it may stop on the data phase or +status phase of the control transfer. Like other stalled endpoints, the xHCI +driver needs to queue a Reset Endpoint command and move the hardware's control +endpoint ring dequeue pointer past the failed control transfer (with a Set TR +Dequeue Pointer or a Configure Endpoint command). + + Since the USB core doesn't call usb_hcd_reset_endpoint() for control endpoints, +we need to do this in interrupt context when we get notified of the stalled +transfer. URBs may be queued to the hardware before these two commands complete. +The endpoint queue will be restarted once both commands complete. + + When an endpoint on a device under an xHCI host controller stalls, the host +controller driver must let the hardware know that the USB core has successfully +cleared the halt condition. The HCD submits a Reset Endpoint Command, which will +clear the toggle bit for USB 2.0 devices, and set the sequence number to zero for +USB 3.0 devices. + + The xHCI urb_enqueue will accept new URBs while the endpoint is halted, and +will queue them to the hardware rings. However, the endpoint doorbell will not +be rung until the Reset Endpoint Command completes. Don't queue a reset endpoint +command for root hubs. khubd clears halt conditions on the roothub during the +initialization process, but the roothub isn't a real device, so the xHCI host +controller doesn't need to know about the cleared halt. +*/ + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, + XHCI_GetDeviceContext(Usb3Hc, SlotId), Dci); + + // The Reset Endpoint Command is issued by software to recover + // from a halted condition on an endpoint. + if (EpCtx->EpState == XHCI_EP_STATE_HALTED) { + // Reset stalled endpoint + EpInfo = (Dci << 8) + SlotId; + Status = XHCI_ExecuteCommand(HcStruc, XhciTResetEndpointCmd, &EpInfo); + } + //ASSERT(Status == USB_SUCCESS); + + // Set TR Dequeue Pointer command may be executed only if the target + // endpoint is in the Error or Stopped state. + if ((EpCtx->EpState == XHCI_EP_STATE_STOPPED) || + (EpCtx->EpState == XHCI_EP_STATE_ERROR)) { + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + + Trb.TrPointer = (UINT64)((UINTN)XfrRing->QueuePtr + XfrRing->CycleBit); // Set up DCS + Trb.EndpointId = Dci; + Trb.SlotId = SlotId; + + Status = XHCI_ExecuteCommand(HcStruc, XhciTSetTRDequeuePointerCmd, &Trb); + //ASSERT(Status == USB_SUCCESS); + } + +// Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); //(EIP61849-) +// *Doorbell = Dci; //(EIP61849-) + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ProcessXferEvt +// +// Description: +// This function processes a transfer event and gives control to the device +// specific routines. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +XHCI_ProcessXferEvt( + USB3_HOST_CONTROLLER *Usb3Hc, + HC_STRUC *HcStruc, + XHCI_TRANSFER_EVT_TRB *XferEvtTrb +) +{ + DEV_INFO *DevInfo; + UINT8 SlotId = XferEvtTrb->SlotId; + UINT8 Dci = XferEvtTrb->EndpointId; + XHCI_NORMAL_XFR_TRB *Trb = (XHCI_NORMAL_XFR_TRB*)XferEvtTrb->TrbPtr; + volatile UINT32 *Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); + TRB_RING *XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + UINT16 BytesTransferred; + UINT8 PortStatus = USB_PORT_STAT_DEV_ENABLED; + UINT8 i; + + DevInfo = XHCI_GetDevInfo((UINTN)Trb->DataBuffer); + if (DevInfo == NULL) return; + + switch (XferEvtTrb->CompletionCode) { + case XHCI_TRB_SUCCESS: + case XHCI_TRB_SHORTPACKET: + // Check for the keyboard event + + //(EIP38434+)> + if ((DevInfo->bCallBackIndex) && + (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION) && + (DevInfo->fpPollTDPtr != NULL)) { + + if (gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1]) { + + if (gUsbData->ProcessingPeriodicList == FALSE) { + for (i = 0; i < XHCI_MAX_PENDING_INTERRUPT_TRANSFER; i++) { + if (Usb3Hc->PendingInterruptTransfer[i].Trb == NULL) { + break; + } + } + if (i != XHCI_MAX_PENDING_INTERRUPT_TRANSFER) { + Usb3Hc->PendingInterruptTransfer[i].Trb = Trb; + Usb3Hc->PendingInterruptTransfer[i].TransferredLength = + DevInfo->PollingLength - XferEvtTrb->TransferLength; + return; + } + } + // + // Get the size of data transferred + // + BytesTransferred = DevInfo->PollingLength - XferEvtTrb->TransferLength; + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1]) + (HcStruc, DevInfo, NULL, DevInfo->fpPollTDPtr, + BytesTransferred); + } + } + //<(EIP38434+) + break; + + case XHCI_TRB_BABBLE_ERROR: + case XHCI_TRB_TRANSACTION_ERROR: + case XHCI_TRB_STALL_ERROR: + // When the device is disconnecting, the transaction will be error, + // we need to check the port status + PortStatus = USB_GetHubPortStatus(HcStruc, DevInfo->bHubDeviceNumber, DevInfo->bHubPortNumber, FALSE); + if (PortStatus == USB_ERROR) { + PortStatus = 0; + } + if (PortStatus & USB_PORT_STAT_DEV_ENABLED) { + XHCI_ClearStalledEp(Usb3Hc, HcStruc, SlotId, Dci); + } + break; + } + // Check if this device is still enabled + if ((PortStatus & USB_PORT_STAT_DEV_ENABLED) && (DevInfo->fpPollTDPtr != NULL)) { + Trb = (XHCI_NORMAL_XFR_TRB*)XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return; + } + Trb->TrbType = XhciTNormal; + Trb->DataBuffer = (UINT64)(UINTN)DevInfo->fpPollTDPtr; + Trb->XferLength = DevInfo->PollingLength; + Trb->Isp = 1; //(EIP51478+) + Trb->Ioc = 1; + Trb->CycleBit = XfrRing->CycleBit; + + // Ring the door bell to start polling interrupt endpoint + *Doorbell = Dci; + } +} + + //(EIP60460+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ProcessPortStsChgEvt +// +// Description: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +XHCI_ProcessPortStsChgEvt( + USB3_HOST_CONTROLLER *Usb3Hc, + HC_STRUC *HcStruc, + XHCI_PORTSTSCHG_EVT_TRB *PortStsChgEvtTrb +) +{ + volatile XHCI_PORTSC *PortSC; + DEV_INFO *DevInfo; + UINT8 i; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + if (((Usb3Hc->Vid != XHCI_FL100X_VID) || (Usb3Hc->Did != XHCI_FL1000_DID && + Usb3Hc->Did != XHCI_FL1009_DID)) && (Usb3Hc->Vid != XHCI_INTEL_VID)) { + return; + } + + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (PortStsChgEvtTrb->PortId - 1))); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return; + } +#endif + + if (PortSC->Field.Csc && PortSC->Field.Ccs == 0) { + for (i = 1; i < MAX_DEVICES; i++) { + DevInfo = &gUsbData->aDevInfoTable[i]; + if ((DevInfo->Flag & DEV_INFO_VALIDPRESENT) + != DEV_INFO_VALIDPRESENT) { + continue; + } + if ((DevInfo->bHubDeviceNumber == (HcStruc->bHCNumber | BIT7)) && + DevInfo->bHubPortNumber == PortStsChgEvtTrb->PortId) { + DevInfo->Flag |= DEV_INFO_DEV_DISCONNECTING; + } + } + } +} + //<(EIP60460+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: XHCI_ProcessInterrupt +// +// Description: This is the XHCI controller event handler. It walks through +// the Event Ring and executes the event associated code if needed. Updates +// the Event Ring Data Pointer in the xHC to let it know which events are +// completed. +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_ERROR - Need more Interrupt processing +// USB_SUCCESS - No interrupts pending +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ProcessInterrupt( + HC_STRUC *HcStruc +) +{ + XHCI_TRB *Trb; + UINTN XhciBaseAddress; + UINT32 Imod; + UINT8 i; + UINT8 SlotId; + UINT8 Dci; + volatile UINT32 *Doorbell; + TRB_RING *XfrRing; + DEV_INFO *DevInfo; + XHCI_NORMAL_XFR_TRB *XfrTrb; + USB3_HOST_CONTROLLER *Usb3Hc; + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (!(ReadPCIConfig(HcStruc->wBusDevFuncNum, USB_REG_COMMAND) & BIT1)) { + return USB_SUCCESS; + } + + XhciBaseAddress = ReadPCIConfig(HcStruc->wBusDevFuncNum, USB_MEM_BASE_ADDRESS); + if (((XhciBaseAddress & (BIT1 | BIT2)) == BIT2) && ((sizeof(VOID*) / sizeof(UINT32) == 2))){ + XhciBaseAddress |= Shl64((UINTN)ReadPCIConfig(HcStruc->wBusDevFuncNum, + USB_MEM_BASE_ADDRESS + 0x04), 32); + } + + XhciBaseAddress &= ~(0x7F); + + if (XhciBaseAddress != (UINTN)Usb3Hc->CapRegs) { +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)XhciBaseAddress, HcStruc->BaseAddressSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Usb Mmio address is invalid, it is in SMRAM\n"); + return USB_ERROR; + } +#endif + HcStruc->BaseAddress = XhciBaseAddress; + (UINTN)Usb3Hc->CapRegs = XhciBaseAddress; + Usb3Hc->OpRegs = (XHCI_HC_OP_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->CapLength); + Usb3Hc->RtRegs = (XHCI_HC_RT_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->RtsOff); + XhciExtCapParser(Usb3Hc); + } + + // Check if host controller interface version number is valid. + if (Usb3Hc->CapRegs->HciVersion == 0xFFFF) { + return USB_SUCCESS; + } + + // Check if USB Legacy Support Capability is present. + if (Usb3Hc->ExtLegCap) { + // Is ownership change? + if((Usb3Hc->ExtLegCap->LegCtlSts.UsbOwnershipChangeSmi == 1) && + (Usb3Hc->ExtLegCap->LegCtlSts.UsbOwnershipChangeSmiEnable==1) ) { + // Clear Ownership change SMI status + Usb3Hc->ExtLegCap->LegCtlSts.UsbOwnershipChangeSmi = 1; + // Process ownership change event + if (Usb3Hc->ExtLegCap->LegSup.HcOsOwned == 1 && + HcStruc->dHCFlag & HC_STATE_RUNNING) { + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + USB_DEBUG(3, "XHCI: Ownership change to XHCD\n"); + XHCI_Stop(HcStruc); + } else if (Usb3Hc->ExtLegCap->LegSup.HcOsOwned == 0 && + (HcStruc->dHCFlag & HC_STATE_RUNNING) == 0) { + gUsbData->dUSBStateFlag |= USB_FLAG_ENABLE_BEEP_MESSAGE; + USB_DEBUG(3, "XHCI: Ownership change to BIOS\n"); + XHCI_Start(HcStruc); + XHCI_EnumeratePorts(HcStruc); + } + return USB_SUCCESS; + } + } + + if ((HcStruc->dHCFlag & HC_STATE_RUNNING) == 0) return USB_SUCCESS; + + if ((UINT32)Usb3Hc->OpRegs->DcbAap != (UINT32)Usb3Hc->DcbaaPtr) return USB_SUCCESS; + + if (gUsbData->ProcessingPeriodicList == TRUE) { + for (i = 0; i < XHCI_MAX_PENDING_INTERRUPT_TRANSFER; i++) { + if (Usb3Hc->PendingInterruptTransfer[i].Trb != NULL) { + DevInfo = XHCI_GetDevInfo((UINTN)Usb3Hc->PendingInterruptTransfer[i].Trb->DataBuffer); + if (DevInfo == NULL) { + continue; + } + if ((DevInfo->bCallBackIndex) && + (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION) && + (DevInfo->fpPollTDPtr != NULL)) { + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + continue; + } + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + Dci = (DevInfo->IntInEndpoint & 0xF) * 2; + + if (DevInfo->IntInEndpoint & BIT7) { + Dci++; + } + + Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci - 1); + + Usb3Hc->PendingInterruptTransfer[i].Trb = NULL; + + if ((DevInfo->bCallBackIndex) && (DevInfo->fpPollTDPtr != NULL)) { + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex - 1]) + (HcStruc, DevInfo, NULL, DevInfo->fpPollTDPtr, + Usb3Hc->PendingInterruptTransfer[i].TransferredLength); + + XfrTrb = (XHCI_NORMAL_XFR_TRB*)XHCI_AdvanceEnqueuePtr(XfrRing); + if (XfrTrb == NULL) { + continue; + } + XfrTrb->TrbType = XhciTNormal; + XfrTrb->DataBuffer = (UINT64)(UINTN)DevInfo->fpPollTDPtr; + XfrTrb->XferLength = DevInfo->PollingLength; + XfrTrb->Isp = 1; + XfrTrb->Ioc = 1; + XfrTrb->CycleBit = XfrRing->CycleBit; + // Ring the door bell to start polling interrupt endpoint + *Doorbell = Dci; + } + } else { + Usb3Hc->PendingInterruptTransfer[i].Trb = NULL; + } + } + } + } + + if (Usb3Hc->OpRegs->UsbSts.Field.Pcd) { + //XHCI_EnumeratePorts(HcStruc); + XHCI_ProcessPortChanges(HcStruc, Usb3Hc); + } + +// if (Usb3Hc->OpRegs->UsbSts.Field.Eint == 0) return USB_SUCCESS; +// Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_EVT_INTERRUPT; // Clear event interrupt + if (Usb3Hc->OpRegs->UsbSts.Field.Eint) { + Usb3Hc->OpRegs->UsbSts.AllBits = XHCI_STS_EVT_INTERRUPT; + if ((gUsbData->fpKeyRepeatHCStruc == HcStruc) && (gUsbData->ProcessingPeriodicList == TRUE)) { + Imod = Usb3Hc->RtRegs->IntRegs[0].IMod; + if ((Imod & XHCI_KEYREPEAT_IMODI) == XHCI_KEYREPEAT_IMODI) { + USBKBDPeriodicInterruptHandler(HcStruc); + } + } + } + + // Check for pending interrupts: + // check the USBSTS[3] and IMAN [0] to determine if any interrupt generated + if (Usb3Hc->EvtRing.QueuePtr->CycleBit != Usb3Hc->EvtRing.CycleBit) { + if (gUsbData->fpKeyRepeatHCStruc == HcStruc) { + Imod = Usb3Hc->RtRegs->IntRegs[0].IMod; + if ((Imod & XHCI_KEYREPEAT_IMODI) == XHCI_KEYREPEAT_IMODI) { + Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)0 | BIT3); + } else { + Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr | BIT3); + } + } else { + Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr | BIT3); + } + return USB_SUCCESS; + } + + // See if there are any TRBs waiting in the event ring + //for (Count = 0; Count < Usb3Hc->EvtRing.Size; Count++) { + for (;;) { + Trb = Usb3Hc->EvtRing.QueuePtr; +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)Trb, sizeof(XHCI_TRB)); + if (EFI_ERROR(EfiStatus)) { + break; + } +#endif + if (Trb->CycleBit != Usb3Hc->EvtRing.CycleBit) break; // past the last + + if (Usb3Hc->EvtRing.QueuePtr == Usb3Hc->EvtRing.LastTrb) { + // Reached the end of the ring, wrap around + Usb3Hc->EvtRing.QueuePtr = Usb3Hc->EvtRing.Base; + Usb3Hc->EvtRing.CycleBit ^= 1; + } else { + Usb3Hc->EvtRing.QueuePtr++; + } + // error manager + if (Trb->CompletionCode == XHCI_TRB_SHORTPACKET) { + USB_DEBUG(3, "XHCI: short packet detected."); + } + + if (Trb->CompletionCode == XHCI_TRB_STALL_ERROR) { + USB_DEBUG(3, "XHCI: device STALLs."); + } + + if (Trb->CompletionCode != XHCI_TRB_SUCCESS + && Trb->CompletionCode != XHCI_TRB_STALL_ERROR + && Trb->CompletionCode != XHCI_TRB_SHORTPACKET) { + USB_DEBUG(3, "Trb completion code: %d\n", Trb->CompletionCode); + //ASSERT(FALSE); + } + + switch (Trb->TrbType) { + case XhciTTransferEvt: +// very frequent, debug message here might affect timings, +// uncomment only when needed +// USB_DEBUG(3, "TransferEvt\n"); + XHCI_ProcessXferEvt(Usb3Hc, HcStruc, (XHCI_TRANSFER_EVT_TRB*)Trb); + break; + case XhciTCmdCompleteEvt: + USB_DEBUG(3, "CmdCompleteEvt\n"); + break; + case XhciTPortStatusChgEvt: + USB_DEBUG(3, "PortStatusChgEvt, port #%d\n", ((XHCI_PORTSTSCHG_EVT_TRB*)Trb)->PortId); + XHCI_ProcessPortStsChgEvt(Usb3Hc, HcStruc, (XHCI_PORTSTSCHG_EVT_TRB*)Trb); //(EIP60460+) + break; + case XhciTDoorbellEvt: + USB_DEBUG(3, "DoorbellEvt\n"); + break; + case XhciTHostControllerEvt: + USB_DEBUG(3, "HostControllerEvt\n"); + break; + case XhciTDevNotificationEvt: + USB_DEBUG(3, "DevNotificationEvt\n"); + break; + case XhciTMfIndexWrapEvt: + USB_DEBUG(3, "MfIndexWrapEvt\n"); + break; + default: + USB_DEBUG(3, "UNKNOWN EVENT\n"); + } + } + //ASSERT(Count<Usb3Hc->EvtRing.Size); // Event ring is full + + // Update ERDP to inform xHC that we have processed another TRB + if ((gUsbData->fpKeyRepeatHCStruc == HcStruc) && + ((Usb3Hc->RtRegs->IntRegs[0].IMod & XHCI_KEYREPEAT_IMODI) == XHCI_KEYREPEAT_IMODI)) { + Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)0 | BIT3); + } else { + Usb3Hc->RtRegs->IntRegs[0].IMan |= BIT0; + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr | BIT3); + } + + return USB_SUCCESS; // Set as interrupt processed +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_GetRootHubStatus +// +// Description: +// This function returns the port connect status for the root hub port +// +// Input: +// HcStruc - Pointer to the HC structure +// PortNum - Port in the HC whose status is requested +// +// Output: +// Port status flags (see USB_PORT_STAT_XX equates) +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_GetRootHubStatus( + HC_STRUC* HcStruc, + UINT8 PortNum, + BOOLEAN ClearChangeBits +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + volatile XHCI_PORTSC *PortSC; + UINT32 i; + UINT32 PortStCtl; + UINT8 PortStatus = USB_PORT_STAT_DEV_OWNER; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + // Find the proper MMIO access offset for a given port + + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (PortNum-1))); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + USB_DEBUG(3, "XHCI port[%d] status: %08x\n", PortNum, PortSC->AllBits); + + for (i = 0; i < 200; i++) { + if (PortSC->Field.Pr == 0) break; + FixedDelay(1 * 1000); + } + + switch (PortSC->Field.Pls) { + case XHCI_PORT_LINK_U0: + case XHCI_PORT_LINK_RXDETECT: + break; + case XHCI_PORT_LINK_RECOVERY: + for (i = 0; i < 200; i++) { + FixedDelay(1 * 1000); + if (PortSC->Field.Pls != XHCI_PORT_LINK_RECOVERY) { + break; + } + } + break; + case XHCI_PORT_LINK_POLLING: + if (!XHCI_IsUsb3Port(Usb3Hc, PortNum)) { + break; + } + for (i = 0; i < 500; i++) { + FixedDelay(1 * 1000); + if (PortSC->Field.Pls != XHCI_PORT_LINK_POLLING) { + break; + } + } + if (PortSC->Field.Pls == XHCI_PORT_LINK_U0 || + PortSC->Field.Pls == XHCI_PORT_LINK_RXDETECT) { + break; + } + XHCI_ResetPort(Usb3Hc, PortNum, TRUE); + break; + case XHCI_PORT_LINK_INACTIVE: + for (i = 0; i < 12; i++) { + FixedDelay(1 * 1000); + if (PortSC->Field.Pls != XHCI_PORT_LINK_INACTIVE) { + break; + } + } + if (PortSC->Field.Pls == XHCI_PORT_LINK_RXDETECT) { + break; + } + case XHCI_PORT_LINK_COMPLIANCE_MODE: + XHCI_ResetPort(Usb3Hc, PortNum, TRUE); + break; + default: + PortStatus |= USB_PORT_STAT_DEV_CONNECTED; + break; + } + + if (PortSC->Field.Ccs != 0) { + PortStatus |= USB_PORT_STAT_DEV_CONNECTED; + UpdatePortStatusSpeed(PortSC->Field.PortSpeed, &PortStatus); + + // USB 3.0 device may not set Connect Status Change bit after reboot, + // set the connect change flag when we enumerate HC ports for devices. + if (gUsbData->bIgnoreConnectStsChng == TRUE) { + PortStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + } + + if (PortSC->Field.Ped) { + PortStatus |= USB_PORT_STAT_DEV_ENABLED; + } + } + + if (PortSC->Field.Csc != 0) { + PortStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; + // Clear connect status change bit + if (ClearChangeBits == TRUE) { + PortSC->AllBits = XHCI_PCS_CSC | XHCI_PCS_PP; + } + } + + // Clear all status change bits + if (ClearChangeBits == TRUE) { + PortStCtl = PortSC->AllBits; + PortSC->AllBits = PortStCtl & ~XHCI_PCS_PED; // DO NOT TOUCH PED + } + + return PortStatus; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_EnableRootHub +// +// Description: +// This function enables the XHCI HC Root hub port. +// +// Input: +// HcStruc - Pointer to the HC structure +// PortNum - Port in the HC to enable +// +// Output: +// USB_SUCCESS on success, USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_EnableRootHub( + HC_STRUC* HcStruc, + UINT8 PortNum +) +{ + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_DisableRootHub +// +// Description: +// This function disables the XHCI HC Root hub port. +// +// Input: +// HcStruc - Pointer to the HC structure +// PortNum - Port in the HC to disable +// +// Output: +// USB_SUCCESS on success, USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_DisableRootHub( + HC_STRUC *HcStruc, + UINT8 PortNum +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + volatile XHCI_PORTSC *PortSC = NULL; + UINT8 i = 0; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + +USB_DEBUG(3, "Disable XHCI root port %d\n", PortNum); + + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (PortNum - 1))); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + if (PortSC->Field.Ped) { + if (XHCI_IsUsb3Port(Usb3Hc, PortNum)) { + XHCI_ResetPort(Usb3Hc, PortNum, FALSE); + } else { + PortSC->AllBits = XHCI_PCS_PED | XHCI_PCS_PP; + for (i = 0; i < 200; i++) { + if (PortSC->Field.Ped == 0) { + break; + } + FixedDelay(100); + } + } + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ResetPort +// +// Description: +// This function resets the XHCI HC Root hub port. +// +// Input: +// HcStruc - Pointer to the HC structure +// PortNum - Port in the HC to disable +// +// Output: +// USB_SUCCESS on success, USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ResetPort( + USB3_HOST_CONTROLLER *Usb3Hc, + UINT8 Port, + BOOLEAN WarmReset +) +{ + volatile XHCI_PORTSC *PortSC; + UINT32 i; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (Port - 1))); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + if (WarmReset && XHCI_IsUsb3Port(Usb3Hc, Port)) { + PortSC->AllBits = XHCI_PCS_WPR | XHCI_PCS_PP; + + for (i = 0; i < 6000; i++) { //(EIP93368) + if (PortSC->Field.Wrc || PortSC->Field.Prc) { + break; + } + FixedDelay(100); + } + //ASSERT(PortSC->Field.Wrc || PortSC->Field.Prc); + if (PortSC->Field.Wrc == 0 && PortSC->Field.Prc == 0) { + return USB_ERROR; + } + + if (Usb3Hc->Vid == XHCI_EJ168A_VID && Usb3Hc->Did == XHCI_EJ168A_DID) { + FixedDelay(20 * 1000); + } + } else { + PortSC->AllBits = XHCI_PCS_PR | XHCI_PCS_PP; // Keep port power bit + + for (i = 0; i < 3000; i++) { + if (PortSC->Field.Prc) break; + FixedDelay(100); + } + //ASSERT(PortSC->Field.Prc); + if (PortSC->Field.Prc == 0) { + return USB_ERROR; + } + } + + // Clear Warm Port Reset Change and Port Reset Change bits + PortSC->AllBits = XHCI_PCS_WRC | XHCI_PCS_PRC | XHCI_PCS_PP; + // The USB System Software guarantees a minimum of 10 ms for reset recovery. + FixedDelay(XHCI_RESET_PORT_DELAY_MS * 1000); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ResetRootHub +// +// Description: +// This function resets the XHCI HC Root hub port. +// +// Input: +// HcStruc - Pointer to the HC structure +// PortNum - Port in the HC to disable +// +// Output: +// USB_SUCCESS on success, USB_ERROR on error +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ResetRootHub( + HC_STRUC* HcStruc, + UINT8 PortNum +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + UINT8 Status; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + Status = XHCI_ResetPort(Usb3Hc, PortNum, FALSE); + + if (!XHCI_IsUsb3Port(Usb3Hc, PortNum)) { + // After a short delay, SS device that was originally connected to HS port + // might get reconnected to the SS port... + FixedDelay(XHCI_SWITCH2SS_DELAY_MS * 1000); + } + + return Status; +} + + //(EIP54018+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: XHCI_GlobalSuspend +// +// Description: +// This function suspend the XHCI HC. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_GlobalSuspend( + HC_STRUC* HcStruc +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + volatile XHCI_PORTSC *PortSC; + UINT32 Port; + UINT32 i; + UINT32 PortStCtl; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + for (Port = 1; Port <= Usb3Hc->MaxPorts; Port++) { + + PortSC = (XHCI_PORTSC*)((UINTN)Usb3Hc->OpRegs + + XHCI_PORTSC_OFFSET + (0x10 * (Port - 1))); + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)PortSC, sizeof(XHCI_PORTSC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + USB_DEBUG(3, "XHCI port[%d] status: %08x\n", Port, PortSC->AllBits); + if ((PortSC->Field.Ped) && (PortSC->Field.Pls <XHCI_PORT_LINK_U3)){ + PortStCtl = PortSC->AllBits; + PortStCtl |= (XHCI_PCS_LWS | (UINT32)(XHCI_PORT_LINK_U3 << 5)); + PortSC->AllBits = PortStCtl & ~XHCI_PCS_PED; + for (i = 0;i < 10; i++) { + if (PortSC->Field.Pls == XHCI_PORT_LINK_U3) break; + FixedDelay(1 * 1000); + } + } + } + + + Usb3Hc->OpRegs->UsbCmd.AllBits &= ~XHCI_CMD_RS; + + for (i = 0; i < 16; i++) { + FixedDelay(1 * 1000); + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) break; + } + + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + HcStruc->dHCFlag |= HC_STATE_SUSPEND; + + return USB_SUCCESS; +} + //<(EIP54018+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_UpdateEp0MaxPacket +// +// Description: +// This function verifies the MaxPacket size of the control pipe. If it does +// not match the one received as a part of GET_DESCRIPTOR, then this function +// updates the MaxPacket data in DeviceContext and HC is notified via +// EvaluateContext command. +// +// Input: +// HcStruc Pointer to the HC structure +// Device Evaluated device context pointer +// SlotId Device context index in DCBAA +// Endp0MaxPacket Max packet size obtained from the device +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +XHCI_UpdateEp0MaxPacket( + HC_STRUC *HcStruc, + UINT8 SlotId, + UINT8 Endp0MaxPacket +) +{ + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + UINT8 Status; + UINT8 *DevCtx; + XHCI_INPUT_CONTROL_CONTEXT *CtlCtx; + XHCI_SLOT_CONTEXT *SlotCtx; + XHCI_EP_CONTEXT *EpCtx; + + DevCtx = (UINT8*)XHCI_GetDeviceContext(Usb3Hc, SlotId); + + SlotCtx = (XHCI_SLOT_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, DevCtx, 0); + if (SlotCtx->Speed != XHCI_DEVSPEED_FULL) return; + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, DevCtx, 1); + if (EpCtx->MaxPacketSize == Endp0MaxPacket) return; + + // Prepare input context for EvaluateContext comand + MemFill((UINT8*)Usb3Hc->InputContext, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0); + + CtlCtx = (XHCI_INPUT_CONTROL_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 0); + CtlCtx->AddContextFlags = BIT1; + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 2); + EpCtx->MaxPacketSize = Endp0MaxPacket; + + Status = XHCI_ExecuteCommand(HcStruc, XhciTEvaluateContextCmd, &SlotId); + ASSERT(Status == USB_SUCCESS); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_ControlTransfer +// +// Description: +// This function executes a device request command transaction on the USB. +// One setup packet is generated containing the device request parameters +// supplied by the caller. The setup packet may be followed by data in or +// data out packets containing data sent from the host to the device or +// vice-versa. This function will not return until the request either completes +// successfully or completes in error (due to time out, etc.) +// +// Input: +// HcStruc Pointer to the HC structure +// DevInfo DeviceInfo structure (if available else 0) +// Request 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: Get Configuration, +// Set Address, etc.) +// Index wIndex request parameter (meaning varies) +// Value wValue request parameter (meaning varies) +// Buffer Buffer containing data to be sent to the device or buffer +// to be used to receive data +// Length wLength request parameter, number of bytes of data to be +// transferred in or out of the host controller +// +// Output: +// Number of bytes actually transferred +// +// Notes: +// DevInfo->DevMiscInfo points to the device context +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +XHCI_ControlTransfer ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT16 Request, + UINT16 Index, + UINT16 Value, + UINT8 *Buffer, + UINT16 Length +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + XHCI_TRB *Trb; + UINT8 SlotId; + UINT8 CompletionCode; + UINT8 Status; + TRB_RING *XfrRing; + UINT16 TimeoutMs; + XHCI_SLOT_CONTEXT *SlotCtx = NULL; + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + if (Length != 0) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Buffer, Length); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Xhci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return 0; + } + + ASSERT(DevInfo != NULL); + + if(DevInfo->Flag & DEV_INFO_DEV_DISCONNECTING) return 0; //(EIP60460+) + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return 0; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + + // Skip SET_ADDRESS request if device is in addressed state + if (Request == USB_RQ_SET_ADDRESS) { + SlotCtx = XHCI_GetContextEntry(Usb3Hc, DevInfo->DevMiscInfo, 0); + + if (SlotCtx->SlotState == XHCI_SLOT_STATE_DEFAULT) { + Status = XhciAddressDevice(HcStruc, DevInfo, SlotId); + } + return Length; + } + + TimeoutMs = gUsbData->wTimeOutValue != 0 ? XHCI_CTL_COMPLETE_TIMEOUT_MS : 0; + + gUsbData->bLastCommandStatus &= ~(USB_CONTROL_STALLED); + gUsbData->dLastCommandStatusExtended = 0; + + // Insert Setup, Data(if needed), and Status TRBs into the transfer ring + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, 0); + + // Setup TRB + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return 0; + } + Trb->TrbType = XhciTSetupStage; + ((XHCI_SETUP_XFR_TRB*)Trb)->Idt = 1; + *(UINT16*)&((XHCI_SETUP_XFR_TRB*)Trb)->bmRequestType = Request; + ((XHCI_SETUP_XFR_TRB*)Trb)->wValue = Value; + ((XHCI_SETUP_XFR_TRB*)Trb)->wIndex = Index; + ((XHCI_SETUP_XFR_TRB*)Trb)->wLength = Length; + ((XHCI_SETUP_XFR_TRB*)Trb)->XferLength = 8; + + if (Usb3Hc->HciVersion >= 0x100) { + if (Length != 0) { + if (Request & USB_REQ_TYPE_INPUT) { + ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_DATA_IN; + } else { + ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_DATA_OUT; + } + } else { + ((XHCI_SETUP_XFR_TRB*)Trb)->Trt = XHCI_XFER_TYPE_NO_DATA; + } + } + ((XHCI_SETUP_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + + // Data TRB + if (Length != 0) { + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return 0; + } + Trb->TrbType = XhciTDataStage; + ((XHCI_DATA_XFR_TRB*)Trb)->Dir = ((Request & USB_REQ_TYPE_INPUT) != 0)? 1 : 0; + ((XHCI_DATA_XFR_TRB*)Trb)->XferLength = Length; + ((XHCI_DATA_XFR_TRB*)Trb)->DataBuffer = (UINT64)(UINTN)Buffer; + ((XHCI_DATA_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + } + + // Status TRB + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return 0; + } + Trb->TrbType = XhciTStatusStage; + ((XHCI_STATUS_XFR_TRB*)Trb)->Ioc = 1; + if ((Request & USB_REQ_TYPE_INPUT) == 0) { + ((XHCI_STATUS_XFR_TRB*)Trb)->Dir = 1; // Status is IN + } + ((XHCI_STATUS_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + + // Ring the doorbell and see Event Ring update + Status = XhciRingDoorbell(Usb3Hc, SlotId, 1); + + if (Status != USB_SUCCESS) { + return 0; + } + + Status = XHCI_WaitForEvent( + HcStruc, Trb, XhciTTransferEvt, SlotId, 1, //(EIP62376) + &CompletionCode, TimeoutMs, NULL); + + if (Status != USB_SUCCESS) { + //(EIP54283)> + switch (CompletionCode) { + case XHCI_TRB_BABBLE_ERROR: //(EIP62376+) + case XHCI_TRB_TRANSACTION_ERROR: + XHCI_ClearStalledEp(Usb3Hc, HcStruc, SlotId, 1); //(EIP60460+) + break; //(EIP60460+) + case XHCI_TRB_STALL_ERROR: + XHCI_ClearStalledEp(Usb3Hc, HcStruc, SlotId, 1); + gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; + break; + //(EIP84790+)> + case XHCI_TRB_EXECUTION_TIMEOUT_ERROR: + XHCI_ClearEndpointState(HcStruc, DevInfo, 0); + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + //<(EIP84790+) + default: + break; + } + //<(EIP54283) + return 0; + } + + if (Request == USB_RQ_GET_DESCRIPTOR && Length == 8) { + // Full speed device requires the update of MaxPacket size + XHCI_UpdateEp0MaxPacket(HcStruc, SlotId, ((DEV_DESC*)Buffer)->MaxPacketSize0); + } + + + if ((Request == (UINT16)(ENDPOINT_CLEAR_PORT_FEATURE)) && (Length == 0) && + (Value == (UINT16)ENDPOINT_HALT) && (Buffer == NULL)) { + XHCI_ClearEndpointState(HcStruc, DevInfo, (UINT8)Index); + } + + return Length; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_BulkTransfer +// +// Description: +// This function executes a bulk transaction on the USB +// +// Input: +// HcStruc Pointer to HCStruc of the host controller +// DevInfo DeviceInfo structure (if available else 0) +// XferDir Transfer direction +// Bit 7: Data direction +// 0 Host sending data to device +// 1 Device sending data to host +// Bit 6-0 : Reserved +// Buffer Buffer containing data to be sent to the device or buffer to +// be used to receive data value +// Length Length request parameter, number of bytes of data to be +// transferred in or out of the HC +// +// Output: +// Amount of data transferred +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +XHCI_BulkTransfer( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 XferDir, + UINT8 *Buffer, + UINT32 Length +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + XHCI_TRB *Trb; + XHCI_TRB *FirstTrb; + UINT8 SlotId; + UINT8 CompletionCode; + UINT8 Status; + TRB_RING *XfrRing; + UINT8 Endpoint; + UINT8 Dci; + UINT64 DataPointer; + UINT32 ResidualData; // Transferred amount return by Transfer Event + UINT32 TransferredSize; // Total transfer amount + UINT32 RingDataSize; // One TRB ring transfer amount + UINT32 RemainingXfrSize; + UINT32 RemainingDataSize; + UINT32 XfrSize; + UINT32 XfrTdSize; + UINT16 MaxPktSize; + UINT32 TdSize; + UINT16 TimeoutMs; + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Buffer, Length); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Xhci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + // Clear HW source of error + gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED | USB_BULK_TIMEDOUT ); + gUsbData->dLastCommandStatusExtended = 0; + + if(DevInfo->Flag & DEV_INFO_DEV_DISCONNECTING) return 0; //(EIP60460+) + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return 0; + }; + + TimeoutMs = gUsbData->wTimeOutValue; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return 0; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + Endpoint = (XferDir & BIT7)? DevInfo->bBulkInEndpoint : DevInfo->bBulkOutEndpoint; + MaxPktSize = (XferDir & BIT7)? DevInfo->wBulkInMaxPkt : DevInfo->wBulkOutMaxPkt; + Dci = (Endpoint & 0xf)* 2; + if (XferDir & BIT7) Dci++; + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + + // Make a chain of TDs to transfer the requested amount of data. If necessary, + // make multiple transfers in a loop. + + DataPointer = (UINT64)(UINTN)Buffer; + RemainingDataSize = Length; + + // Two loops are executing the transfer: + // The inner loop creates a transfer ring of chained TDs, XHCI_BOT_TD_MAXSIZE + // bytes each. This makes a ring capable of transferring + // XHCI_BOT_TD_MAXSIZE * (TRBS_PER_SEGMENT-1) bytes. + // The outter loop repeats the transfer if the requested transfer size exceeds + // XHCI_BOT_TD_MAXSIZE * (TRBS_PER_SEGMENT-1). + + for (TransferredSize = 0; TransferredSize < Length;) { + // Calculate the amount of data to transfer in the ring + RingDataSize = (RemainingDataSize > XHCI_BOT_MAX_XFR_SIZE)? + XHCI_BOT_MAX_XFR_SIZE : RemainingDataSize; + + RemainingXfrSize = RingDataSize; + + for (Trb = NULL, XfrSize = 0, FirstTrb = 0; XfrSize < RingDataSize;) + { + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return 0; + } + if (FirstTrb == NULL) FirstTrb = Trb; + + Trb->TrbType = XhciTNormal; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Isp = 1; + ((XHCI_NORMAL_XFR_TRB*)Trb)->DataBuffer = DataPointer; + + // See if we need a TD chain. Note that we do not need to + // place the chained TRB into Event Ring, since we will not be + // looking for it anyway. Set IOC only for the last-in-chain TRB. + if (RemainingXfrSize > XHCI_BOT_TD_MAXSIZE) { + XfrTdSize = XHCI_BOT_TD_MAXSIZE; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Chain = 1; + } else { + ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 1; + XfrTdSize = RemainingXfrSize; + } + // Data buffers referenced by Transfer TRBs shall not span 64KB boundaries. + // If a physical data buffer spans a 64KB boundary, software shall chain + // multiple TRBs to describe the buffer. + if (XfrTdSize > (UINT32)(0x10000 - (DataPointer & (0x10000 - 1)))) { + XfrTdSize = (UINT32)(0x10000 - (DataPointer & (0x10000 - 1))); + ((XHCI_NORMAL_XFR_TRB*)Trb)->Chain = 1; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 0; + } + + ((XHCI_NORMAL_XFR_TRB*)Trb)->XferLength = XfrTdSize; + + XfrSize += XfrTdSize; + DataPointer += XfrTdSize; + RemainingXfrSize -= XfrTdSize; + + if(Usb3Hc->HciVersion >= 0x100) { + TdSize = 0; + if (RemainingXfrSize != 0) { + TdSize = RemainingXfrSize/MaxPktSize; + if (RemainingXfrSize % MaxPktSize) { + TdSize++; + } + TdSize = (TdSize > 31)? 31 : TdSize; + } + } else { + TdSize = RemainingXfrSize + XfrTdSize; + TdSize = (TdSize < 32768)? (TdSize >> 10) : 31; + } + + ((XHCI_NORMAL_XFR_TRB*)Trb)->TdSize = TdSize; + if (Trb != FirstTrb) { + ((XHCI_NORMAL_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + } + } +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)XfrRing->LastTrb, sizeof(XHCI_NORMAL_XFR_TRB)); + if (EFI_ERROR(EfiStatus)) { + break; + } +#endif + // If transfer ring crossed Link TRB, set its Chain flag + if (Trb < FirstTrb) { + ((XHCI_NORMAL_XFR_TRB*)XfrRing->LastTrb)->Chain = 1; + + } + + ((XHCI_NORMAL_XFR_TRB*)FirstTrb)->CycleBit = XfrRing->CycleBit; + if (Trb < FirstTrb) { + ((XHCI_NORMAL_XFR_TRB*)FirstTrb)->CycleBit ^= 1; + } + + // Ring the door bell and see Event Ring update + Status = XhciRingDoorbell(Usb3Hc, SlotId, Dci); + + if (Status != USB_SUCCESS) { + break; + } + + Status = XHCI_WaitForEvent( + HcStruc, Trb, XhciTTransferEvt, SlotId, Dci, //(EIP62376) + &CompletionCode, TimeoutMs, &ResidualData); + + // Clear Link TRB chain flag + ((XHCI_NORMAL_XFR_TRB*)XfrRing->LastTrb)->Chain = 0; + + if (Status != USB_SUCCESS) { + //(EIP54283)> + switch (CompletionCode) { + case XHCI_TRB_BABBLE_ERROR: //(EIP62376+) + case XHCI_TRB_TRANSACTION_ERROR: + XHCI_ClearStalledEp(Usb3Hc, HcStruc, SlotId, Dci); //(EIP60460+) + break; //(EIP60460+) + case XHCI_TRB_STALL_ERROR: + XHCI_ResetEndpoint(Usb3Hc, HcStruc, SlotId, Dci); + gUsbData->bLastCommandStatus |= USB_BULK_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case XHCI_TRB_EXECUTION_TIMEOUT_ERROR: + XHCI_ClearEndpointState(HcStruc, DevInfo, Endpoint | XferDir); + gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; //(EIP84790+) + break; + default: + break; + } + //<(EIP54283) + break; + } + + TransferredSize += (RingDataSize - ResidualData); + if (ResidualData != 0) break; // Short packet detected, no more transfers + RemainingDataSize -= RingDataSize; + } + + return TransferredSize; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_InterruptTransfer +// +// Description: +// This function executes an interrupt transaction on the USB. The data +// transfer direction is always DATA_IN. This function wil not return until +// the request either completes successfully or completes in error (due to +// time out, etc.) +// +// Input: +// HcStruc Pointer to HCStruc of the host controller +// DevInfo DeviceInfo structure (if available else 0) +// EndpointAddress The destination USB device endpoint to which the device request +// is being sent. +// MaxPktSize Indicates the maximum packet size the target endpoint is capable +// of sending or receiving. +// Buffer Buffer containing data to be sent to the device or buffer to be +// used to receive data +// Length Length request parameter, number of bytes of data to be transferred +// +// Output: +// Number of bytes transferred +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +XHCI_InterruptTransfer ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *Buffer, + UINT16 Length +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + XHCI_TRB *Trb; + UINT8 SlotId; + UINT8 CompletionCode; + UINT8 Status; + TRB_RING *XfrRing; + UINT8 Dci; + UINT16 TimeoutMs; + UINT32 ResidualData; + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return 0; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Buffer, Length); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Xhci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + gUsbData->dLastCommandStatusExtended = 0; + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return 0; + } + + TimeoutMs = gUsbData->wTimeOutValue; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return 0; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + Dci = (EndpointAddress & 0xF) * 2; + if (EndpointAddress & BIT7) Dci++; + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return 0; + } + Trb->TrbType = XhciTNormal; + ((XHCI_NORMAL_XFR_TRB*)Trb)->DataBuffer = (UINTN)Buffer; + ((XHCI_NORMAL_XFR_TRB*)Trb)->XferLength = Length; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Isp = 1; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 1; + ((XHCI_NORMAL_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + + // Ring the doorbell and see Event Ring update + Status = XhciRingDoorbell(Usb3Hc, SlotId, Dci); + + if (Status != USB_SUCCESS) { + return 0; + } + + Status = XHCI_WaitForEvent( + HcStruc, Trb, XhciTTransferEvt, SlotId, Dci, //(EIP62376) + &CompletionCode, TimeoutMs, &ResidualData); + + if (Status != USB_SUCCESS) { + //(EIP54283)> + switch (CompletionCode) { + //(EIP62376+)> + case XHCI_TRB_BABBLE_ERROR: + case XHCI_TRB_TRANSACTION_ERROR: + XHCI_ClearStalledEp(Usb3Hc, HcStruc, SlotId, Dci); + break; + //<(EIP62376+) + case XHCI_TRB_STALL_ERROR: + XHCI_ResetEndpoint(Usb3Hc, HcStruc, SlotId, Dci); + break; + case XHCI_TRB_EXECUTION_TIMEOUT_ERROR: + XHCI_ClearEndpointState(HcStruc, DevInfo, EndpointAddress); + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + //<(EIP54283) + return 0; + } else { + Length = Length - (UINT16)ResidualData; + } + + return Length; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_DeactivatePolling +// +// Description: +// This function de-activates the polling QH for the requested device. The +// device may be a USB keyboard or USB hub. +// +// Input: +// HcStruc - Pointer to the HC structure +// DevInfo - Pointer to the device information structure +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_DeactivatePolling( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + UINT8 SlotId; + UINT8 Dci; + UINT16 EpInfo; + TRB_RING *XfrRing; + XHCI_SET_TRPTR_CMD_TRB Trb; + XHCI_EP_CONTEXT *EpCtx; + EFI_STATUS EfiStatus; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + if (DevInfo->fpPollTDPtr == NULL) { + return USB_ERROR; + } + + USB_MemFree(DevInfo->fpPollTDPtr, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + + DevInfo->fpPollTDPtr = NULL; + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + Dci = (DevInfo->IntInEndpoint & 0xF) * 2; + if (DevInfo->IntInEndpoint & BIT7) Dci++; + + EpInfo = (Dci << 8) + SlotId; + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return USB_ERROR; + } + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)DevInfo->DevMiscInfo, Dci); + + if (EpCtx->EpState == XHCI_EP_STATE_RUNNING) { + XHCI_ExecuteCommand(HcStruc, XhciTStopEndpointCmd, &EpInfo); + } + + // Set TR Dequeue Pointer command may be executed only if the target + // endpoint is in the Error or Stopped state. + if ((EpCtx->EpState == XHCI_EP_STATE_STOPPED) || + (EpCtx->EpState == XHCI_EP_STATE_ERROR)) { + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + + Trb.TrPointer = (UINT64)((UINTN)XfrRing->QueuePtr + XfrRing->CycleBit); // Set up DCS + Trb.EndpointId = Dci; + Trb.SlotId = SlotId; + XHCI_ExecuteCommand(HcStruc, XhciTSetTRDequeuePointerCmd, &Trb); + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_ActivatePolling +// +// Description: +// This function activates the polling QH for the requested device. The device +// may be a USB keyboard or USB hub. +// +// Input: +// HcStruc - Pointer to the HC structure +// DevInfo - Pointer to the device information structure +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ActivatePolling( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + XHCI_TRB *Trb; + volatile UINT32 *Doorbell; + UINT8 SlotId; + TRB_RING *XfrRing; + UINT8 Dci; + EFI_STATUS EfiStatus; + UINTN DeviceContextSize; + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return USB_ERROR; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + Dci = (DevInfo->IntInEndpoint & 0xF) * 2; + if (DevInfo->IntInEndpoint & BIT7) Dci++; + DevInfo->fpPollTDPtr = USB_MemAlloc(GET_MEM_BLK_COUNT(DevInfo->PollingLength)); + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci - 1); + + Trb = XHCI_AdvanceEnqueuePtr(XfrRing); + if (Trb == NULL) { + return USB_ERROR; + } + Trb->TrbType = XhciTNormal; + ((XHCI_NORMAL_XFR_TRB*)Trb)->DataBuffer = (UINT64)(UINTN)DevInfo->fpPollTDPtr; + ((XHCI_NORMAL_XFR_TRB*)Trb)->XferLength = DevInfo->PollingLength; + ((XHCI_NORMAL_XFR_TRB*)Trb)->Isp = 1; //(EIP51478+) + ((XHCI_NORMAL_XFR_TRB*)Trb)->Ioc = 1; + ((XHCI_NORMAL_XFR_TRB*)Trb)->CycleBit = XfrRing->CycleBit; + + // Ring the door bell + Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); + *Doorbell = Dci; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: XHCI_DisableKeyRepeat +// +// Description: +// This function disables the keyboard repeat rate logic +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_DisableKeyRepeat ( + HC_STRUC* HcStruc +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)Usb3Hc->EvtRing.QueuePtr | BIT3); + + Usb3Hc->RtRegs->IntRegs[0].IMod = XHCI_IMODI; + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_EnableKeyRepeat +// +// Description: +// This function disables the keyboard repeat rate logic +// +// Input: +// HcStruc - Pointer to the HC structure +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_EnableKeyRepeat( + HC_STRUC* HcStruc +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + XHCI_Mmio64Write(HcStruc, Usb3Hc, + (UINTN)&Usb3Hc->RtRegs->IntRegs->Erdp, (UINT64)(UINTN)0 | BIT3); + + Usb3Hc->RtRegs->IntRegs[0].IMod = (XHCI_KEYREPEAT_IMODC << 16 | XHCI_KEYREPEAT_IMODI); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_InitXfrRing +// +// Description: +// This function initializes transfer ring of given endpoint +// +// Output: +// Pointer to the transfer ring +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +TRB_RING* +XHCI_InitXfrRing( + USB3_HOST_CONTROLLER* Usb3Hc, + UINT8 Slot, + UINT8 Ep +) +{ + TRB_RING *XfrRing = Usb3Hc->XfrRings + (Slot-1)*32 + Ep; + UINTN Base = Usb3Hc->XfrTrbs + ((Slot-1)*32+Ep)*RING_SIZE; + + XHCI_InitRing(XfrRing, Base, TRBS_PER_SEGMENT, TRUE); + + return XfrRing; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: Xhci_TranslateInterval +// +// Description: +// This routine calculates the Interval field to be used in device's endpoint +// context. Interval is calculated using the following rules (Section 6.2.3.6): +// +// For SuperSpeed bulk and control endpoints, the Interval field shall not be +// used by the xHC. For all other endpoint types and speeds, system software +// shall translate the bInterval field in the USB Endpoint Descriptor to the +// appropriate value for this field. +// +// For high-speed and SuperSpeed Interrupt and Isoch endpoints the bInterval +// field the Endpoint Descriptor is computed as 125æs * 2^(bInterval-1), where +// bInterval = 1 to 16, therefore Interval = bInterval - 1. +// +// For low-speed Interrupt and full-speed Interrupt and Isoch endpoints the +// bInterval field declared by a Full or Low-speed device is computed as +// bInterval * 1ms., where bInterval = 1 to 255. +// +// For Full- and Low-speed devices software shall round the value of Endpoint +// Context Interval field down to the nearest base 2 multiple of bInterval * 8. +// +// Input: +// EpType Endpoint type, see XHCI_EP_CONTEXT.DW1.EpType field definitions +// Speed Endpoint speed, 1..4 for XHCI_DEVSPEED_FULL, _LOW, _HIGH, _SUPER +// Interval Poll interval value from endpoint descriptor +// +// Output: +// Interval value to be written to the endpoint context +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +Xhci_TranslateInterval( + UINT8 EpType, + UINT8 Speed, + UINT8 Interval +) +{ + UINT8 TempData; + UINT8 BitCount; + + if (Interval == 0) { + return 0; + } + + if (EpType == XHCI_EPTYPE_CTL || + EpType == XHCI_EPTYPE_BULK_OUT || + EpType == XHCI_EPTYPE_BULK_IN) { + + if (Speed == XHCI_DEVSPEED_HIGH) { + for (TempData = Interval, BitCount = 0; TempData != 0; BitCount++) { + TempData >>= 1; + } + return BitCount - 1; + } else { + return 0; // Interval field will not be used for LS, FS and SS + } + } + + // Control and Bulk endpoints are processed; translate intervals for Isoc and Interrupt + // endpoints + + // Translate SS and HS endpoints + if (Speed == XHCI_DEVSPEED_SUPER || + Speed == XHCI_DEVSPEED_SUPER_PLUS || + Speed == XHCI_DEVSPEED_HIGH) { + return (Interval - 1); + } + + // Translate interval for FS and LS endpoints + ASSERT(Interval > 0); + + for (TempData = Interval, BitCount = 0; TempData != 0; BitCount++) { + TempData >>= 1; + } + return (BitCount + 2); // return value, where Interval = 0.125*2^value +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_EnableEndpoints +// +// Description: +// This function parses the device descriptor data and enables the endpoints +// by 1)assigning the Transfer TRB and 2)executing ConfigureEndpoint command +// for the slot. Section 4.3.5. +// +// Input: +// DevInfo - A device for which the endpoins are being enabled +// Desc - Device Configuration Descriptor data pointer +// +// Output: +// USB_ERROR on error, USB_SUCCESS on success +// +// Notes: +// 1) DevInfo->DevMiscInfo points to the device context +// 2) This call is executed before SET_CONFIGURATION control transfer +// 3) EP0 information is valid in the Device +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_EnableEndpoints ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Desc +) +{ + UINT16 TotalLength; + UINT16 CurPos; + UINT8 Dci; + INTRF_DESC *IntrfDesc; + ENDP_DESC *EpDesc; + SS_ENDP_COMP_DESC *SsEpCompDesc = NULL; + HUB_DESC *HubDesc; + TRB_RING *XfrRing; + UINT8 EpType; + UINT8 Status; + UINT8 IsHub = 0; //(EIP73020) + UINT8 Speed; + XHCI_INPUT_CONTROL_CONTEXT *CtlCtx; + XHCI_SLOT_CONTEXT *SlotCtx; + XHCI_EP_CONTEXT *EpCtx; + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + UINT8 SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + + EFI_STATUS EfiStatus = EFI_SUCCESS; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Desc, sizeof(CNFG_DESC)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + } +#endif + + if (((CNFG_DESC*)Desc)->bDescType != DESC_TYPE_CONFIG) return USB_ERROR; + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return USB_ERROR; + } + + SlotCtx = (XHCI_SLOT_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)DevInfo->DevMiscInfo, 0); + Speed = SlotCtx->Speed; + + // Note (From 4.6.6): The Add Context flag A1 and Drop Context flags D0 and D1 + // of the Input Control Context (in the Input Context) shall be cleared to 0. + // Endpoint 0 Context does not apply to the Configure Endpoint Command and + // shall be ignored by the xHC. A0 shall be set to 1. + + // Note (From 6.2.2.2): If Hub = 1 and Speed = High-Speed (3), then the + // TT Think Time and Multi-TT (MTT) fields shall be initialized. + // If Hub = 1, then the Number of Ports field shall be initialized, else + // Number of Ports = 0. + + // Prepare input context for EvaluateContext comand + MemFill((UINT8*)Usb3Hc->InputContext, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0); + + CtlCtx = (XHCI_INPUT_CONTROL_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 0); + CtlCtx->AddContextFlags = BIT0; // EP0 + + SlotCtx = (XHCI_SLOT_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, 1); + + // Collect the endpoint information and update the Device Input Context + TotalLength = ((CNFG_DESC*)Desc)->wTotalLength; + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)Desc, TotalLength); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (TotalLength > (MAX_CONTROL_DATA_SIZE - 1)) { + TotalLength = MAX_CONTROL_DATA_SIZE - 1; + } + + for (CurPos = 0; CurPos < TotalLength; CurPos += EpDesc->bDescLength) { + EpDesc = (ENDP_DESC*)(IntrfDesc = (INTRF_DESC*)(Desc + CurPos)); + + if (IntrfDesc->bDescLength == 0) { + break; + } + + if ((CurPos + IntrfDesc->bDescLength) > TotalLength) { + break; + } + + if (IntrfDesc->bDescType == DESC_TYPE_INTERFACE) { + IsHub = IntrfDesc->bBaseClass == BASE_CLASS_HUB; + continue; + } + + if (EpDesc->bDescType != DESC_TYPE_ENDPOINT) continue; + + // Found Endpoint, fill up the information in the InputContext + + // Calculate Device Context Index (DCI), Section 4.5.1. + // 1) For Isoch, Interrupt, or Bulk type endpoints the DCI is calculated + // from the Endpoint Number and Direction with the following formula: + // DCI = (Endpoint Number * 2) + Direction, where Direction = 0 for OUT + // endpoints and 1 for IN endpoints. + // 2) For Control type endpoints: + // DCI = (Endpoint Number * 2) + 1 + // + // Also calculate XHCI EP type out of EpDesc->bEndpointFlags + + if ((EpDesc->bEndpointFlags & EP_DESC_FLAG_TYPE_BITS) == EP_DESC_FLAG_TYPE_CONT) { + Dci = (EpDesc->bEndpointAddr & 0xf) * 2 + 1; + EpType = XHCI_EPTYPE_CTL; + } else { + // Isoc, Bulk or Interrupt endpoint + Dci = (EpDesc->bEndpointAddr & 0xf) * 2; + EpType = EpDesc->bEndpointFlags & EP_DESC_FLAG_TYPE_BITS; // 1, 2, or 3 + + if (EpDesc->bEndpointAddr & BIT7) { + Dci++; // IN + EpType += 4; // 5, 6, or 7 + } + } + + // Update ContextEntries in the Slot context + if (Dci > SlotCtx->ContextEntries) { + SlotCtx->ContextEntries = Dci; + } + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)Usb3Hc->InputContext, Dci + 1); + + EpCtx->EpType = EpType; + + // The Endpoint Companion descriptor shall immediately follow the + // endpoint descriptor it is associated with in the configuration information. + + if ((DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER) || + (DevInfo->bEndpointSpeed == USB_DEV_SPEED_SUPER_PLUS)) { + SsEpCompDesc = (SS_ENDP_COMP_DESC*)(Desc + CurPos + EpDesc->bDescLength); + if (SsEpCompDesc->DescType == DESC_TYPE_SS_EP_COMP) { + EpCtx->MaxBurstSize = SsEpCompDesc->MaxBurst; + } + } + + // wMaxPacketSize + // USB 2.0 spec + // For all endpoints, bits 10..0 specify the maximum packet size (in bytes). + // For high-speed isochronous and interrupt endpoints: + // Bits 12..11 specify the number of additional transaction + // opportunities per microframe: + // 00 = None (1 transaction per microframe) + // 01 = 1 additional (2 per microframe) + // 10 = 2 additional (3 per microframe) + // 11 = Reserved + // Bits 15..13 are reserved and must be set to zero. + // USB 3.0 & 3.1 spec + // Maximum packet size this endpoint is capable of sending or receiving + // when this configuration is selected. + // For control endpoints this field shall be set to 512. For bulk endpoint + // types this field shall be set to 1024. + // For interrupt and isochronous endpoints this field shall be set to 1024 if + // this endpoint defines a value in the bMaxBurst field greater than zero. + // If the value in the bMaxBurst field is set to zero then this field can + // have any value from 0 to 1024 for an isochronous endpoint and 1 to + // 1024 for an interrupt endpoint. + + // Only reserve bits 10..0 + EpCtx->MaxPacketSize = (EpDesc->wMaxPacketSize & 0x07FF); + + // 4.14.1.1 System Bus Bandwidth Scheduling + // Reasonable initial values of Average TRB Length for Control endpoints + // Control endpoints would be 8B, Interrupt endpoints 1KB, + // and Bulk and Isoch endpoints 3KB. + + switch (EpCtx->EpType) { + case XHCI_EP_TYPE_ISO_OUT: + case XHCI_EP_TYPE_ISO_IN: + EpCtx->ErrorCount = 0; + EpCtx->AvgTrbLength = 0xC00; + break; + case XHCI_EP_TYPE_BLK_OUT: + case XHCI_EP_TYPE_BLK_IN: + EpCtx->ErrorCount = 3; + EpCtx->AvgTrbLength = 0xC00; + break; + case XHCI_EP_TYPE_INT_OUT: + case XHCI_EP_TYPE_INT_IN: + EpCtx->ErrorCount = 3; + EpCtx->AvgTrbLength = 0x400; + break; + case XHCI_EP_TYPE_CONTROL: + EpCtx->ErrorCount = 3; + EpCtx->AvgTrbLength = 0x08; + break; + default: + break; + } + + // Set Interval + EpCtx->Interval = Xhci_TranslateInterval(EpType, Speed, EpDesc->bPollInterval); + + XfrRing = XHCI_InitXfrRing(Usb3Hc, SlotId, Dci - 1); + EpCtx->TrDequeuePtr = (UINT64)(UINTN)XfrRing->Base + 1; + + CtlCtx->AddContextFlags |= (1 << Dci); + } + + // For a HUB update NumberOfPorts and TTT fields in the Slot context. For that get hub descriptor + // and use bNbrPorts and TT Think time fields (11.23.2.1 of USB2 specification) + // Notes: + // - Slot.Hub field is already updated + // - Do not set NumberOfPorts and TTT fields for 0.95 controllers + + if (IsHub) { + HubDesc = (HUB_DESC*)USB_MemAlloc(sizeof(MEM_BLK)); + UsbHubGetHubDescriptor(HcStruc, DevInfo, HubDesc, sizeof(MEM_BLK)); + //ASSERT(HubDesc->bDescType == DESC_TYPE_HUB || HubDesc->bDescType == DESC_TYPE_SS_HUB); + if ((HubDesc->bDescType == DESC_TYPE_HUB) || + (HubDesc->bDescType == DESC_TYPE_SS_HUB)) { + SlotCtx->Hub = 1; + SlotCtx->PortsNum = HubDesc->bNumPorts; + + if (Speed == XHCI_DEVSPEED_HIGH) { + SlotCtx->TThinkTime = (HubDesc->wHubFlags >> 5) & 0x3; + } + } + USB_MemFree(HubDesc, sizeof(MEM_BLK)); + } + + // Input context is updated with the endpoint information. Execute ConfigureEndpoint command. + Status = XHCI_ExecuteCommand(HcStruc, XhciTConfigureEndpointCmd, &SlotId); + ASSERT(Status == USB_SUCCESS); + + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_GetRootHubPort +// +// Description: +// This function returns a root hub number for a given device. If device is +// connected to the root through hub(s), it searches the parent's chain up +// to the root. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_GetRootHubPort( + DEV_INFO *DevInfo +) +{ + UINT8 i; + + if ((DevInfo->bHubDeviceNumber & BIT7) != 0) return DevInfo->bHubPortNumber; + + for (i = 1; i < MAX_DEVICES; i++) { + if ((gUsbData->aDevInfoTable[i].Flag & DEV_INFO_VALIDPRESENT) + != DEV_INFO_VALIDPRESENT) { + continue; + } + if (gUsbData->aDevInfoTable[i].bDeviceAddress == DevInfo->bHubDeviceNumber) { + return XHCI_GetRootHubPort(&gUsbData->aDevInfoTable[i]); + } + } + ASSERT(FALSE); // Device parent hub found + return 0; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_InitDeviceData +// +// Description: +// This is an API function for early device initialization. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_InitDeviceData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 PortStatus, + UINT8 **DeviceData +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + UINT8 Status; + UINT8 SlotId; + VOID *DevCtx; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + +#if USB_RUNTIME_DRIVER_IN_SMM + if (gCheckUsbApiParameter) { + EfiStatus = AmiValidateMemoryBuffer((VOID*)DeviceData, sizeof(UINT8*)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + // Obtain device slot using Enable Slot command, 4.3.2, 4.6.3 + Status = XHCI_ExecuteCommand(HcStruc, XhciTEnableSlotCmd, &SlotId); + //ASSERT(Status == USB_SUCCESS); + //ASSERT(SlotId != 0); + if (Status != USB_SUCCESS) { + return Status; + } + + DevCtx = XHCI_GetDeviceContext(Usb3Hc, SlotId); + MemSet(DevCtx, XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0); + + // Update DCBAA with the new device pointer (index = SlotId) + Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] = (UINT64)(UINTN)DevCtx; + USB_DEBUG(3, "XHCI: Slot[%d] enabled, device context at %x\n", SlotId, DevCtx); + + Status = XhciAddressDevice(HcStruc, DevInfo, SlotId); + if (Status != USB_SUCCESS) { + return Status; + } + + *DeviceData = (UINT8*)DevCtx; + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_DeinitDeviceData +// +// Description: +// This is an API function for removing device related information from HC. +// For xHCI this means: +// - execute DisableSlot commnand +// - clear all endpoint's transfer rings +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_DeinitDeviceData ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + UINT8 SlotId; + UINT8 Dci; + TRB_RING *XfrRing; + XHCI_SLOT_CONTEXT *SlotCtx; + XHCI_EP_CONTEXT *EpCtx; + UINT16 EpInfo; + EFI_STATUS EfiStatus; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(DevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return USB_SUCCESS; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + if (Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] == 0) return USB_SUCCESS; + + SlotCtx = (XHCI_SLOT_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)DevInfo->DevMiscInfo, 0); + + // Stop transfer rings + for (Dci = 1; Dci <= SlotCtx->ContextEntries; Dci++) { + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, (UINT8*)DevInfo->DevMiscInfo, Dci); + if (EpCtx->TrDequeuePtr != 0) { + if (EpCtx->EpState == XHCI_EP_STATE_RUNNING) { + EpInfo = (Dci << 8) + SlotId; + XHCI_ExecuteCommand(HcStruc, XhciTStopEndpointCmd, &EpInfo); + } + + // Clear transfer rings + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci - 1); + MemFill((UINT8*)XfrRing->Base, RING_SIZE, 0); + } + } + + XHCI_ExecuteCommand(HcStruc, XhciTDisableSlotCmd, &SlotId); + + Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] = 0; + DevInfo->DevMiscInfo = NULL; + + return USB_SUCCESS; +} + + //(EIP54283+)> +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_ClearEndpointState +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_ClearEndpointState( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 Endpoint +) +{ + USB3_HOST_CONTROLLER *Usb3Hc; + UINT8 SlotId; + UINT8 Dci; + TRB_RING *XfrRing; + UINT8 Status = USB_SUCCESS; + XHCI_SET_TRPTR_CMD_TRB Trb; + XHCI_EP_CONTEXT *EpCtx; + UINT16 EpInfo; + EFI_STATUS EfiStatus; + UINTN DeviceContextSize; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + + if (Usb3Hc->OpRegs->UsbSts.Field.HcHalted) { + return USB_ERROR; + } + + if (DevInfo->DevMiscInfo == NULL) { + return Status; + } + + SlotId = XHCI_GetSlotId(Usb3Hc, DevInfo); + if (Endpoint != 0) { + Dci = (Endpoint & 0xF) * 2 + (Endpoint >> 7); + } else { + Dci = 1; + } + + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((DevInfo->DevMiscInfo < Usb3Hc->DeviceContext) || + (DevInfo->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return USB_ERROR; + } + //<(EIP60460+) + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, DevInfo->DevMiscInfo, Dci); + + if (EpCtx->EpState == XHCI_EP_STATE_RUNNING) { + EpInfo = (Dci << 8) + SlotId; + Status = XHCI_ExecuteCommand(HcStruc, XhciTStopEndpointCmd, &EpInfo); + } //<(EIP54300+) + + // Set TR Dequeue Pointer command may be executed only if the target + // endpoint is in the Error or Stopped state. + if ((EpCtx->EpState == XHCI_EP_STATE_STOPPED) || + (EpCtx->EpState == XHCI_EP_STATE_ERROR)) { + + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, Dci-1); + + Trb.TrPointer = (UINT64)((UINTN)XfrRing->QueuePtr + XfrRing->CycleBit); // Set up DCS + Trb.EndpointId = Dci; + Trb.SlotId = SlotId; + + Status = XHCI_ExecuteCommand(HcStruc, XhciTSetTRDequeuePointerCmd, &Trb); + } + //ASSERT(Status == USB_SUCCESS); + +// Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); //(EIP61849-) +// *Doorbell = Dci; //(EIP61849-) + + return Status; +} + //<(EIP54283+) +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciAddressDevice +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XhciAddressDevice ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 SlotId +) +{ + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + XHCI_INPUT_CONTROL_CONTEXT *InputCtrl = NULL; + XHCI_SLOT_CONTEXT *InputSlot = NULL; + XHCI_SLOT_CONTEXT *OutputSlot = NULL; + XHCI_SLOT_CONTEXT *ParentHubSlotCtx = NULL; + XHCI_EP_CONTEXT *InputEp0 = NULL; + XHCI_EP_CONTEXT *OutputEp0 = NULL; + UINT8 Status = USB_ERROR; + VOID *DevCtx = XHCI_GetDeviceContext(Usb3Hc, SlotId); + VOID *InputCtx = Usb3Hc->InputContext; + TRB_RING *XfrRing = NULL; + DEV_INFO *ParentHub = NULL; + UINT8 HubPortNumber = 0; + UINT16 AddrDevParam = 0; + UINT8 Bsr = 0; + UINTN DeviceContextSize; + + OutputSlot = XHCI_GetContextEntry(Usb3Hc, DevCtx, 0); + if (OutputSlot->SlotState >= XHCI_SLOT_STATE_ADDRESSED) { + return USB_ERROR; + } + + // Zero the InputContext and DeviceContext + MemSet(InputCtx, XHCI_INPUT_CONTEXT_ENTRIES * Usb3Hc->ContextSize, 0); + + // Initialize the Input Control Context of the Input Context + // by setting the A0 flags to 1 + InputCtrl = XHCI_GetContextEntry(Usb3Hc, InputCtx, 0); + InputCtrl->AddContextFlags = BIT0 | BIT1; + + // Initialize the Input Slot Context data structure + InputSlot = XHCI_GetContextEntry(Usb3Hc, InputCtx, 1); + InputSlot->RouteString = 0; + InputSlot->ContextEntries = 1; + InputSlot->RootHubPort = XHCI_GetRootHubPort(DevInfo); + + switch (DevInfo->bEndpointSpeed) { + case USB_DEV_SPEED_SUPER_PLUS: + InputSlot->Speed = XHCI_DEVSPEED_SUPER_PLUS; + break; + case USB_DEV_SPEED_SUPER: + InputSlot->Speed = XHCI_DEVSPEED_SUPER; + break; + case USB_DEV_SPEED_HIGH: + InputSlot->Speed = XHCI_DEVSPEED_HIGH; + break; + case USB_DEV_SPEED_LOW: + InputSlot->Speed = XHCI_DEVSPEED_LOW; + break; + case USB_DEV_SPEED_FULL: + InputSlot->Speed = XHCI_DEVSPEED_FULL; + break; + } + + // Initialize Route String and TT fields + ParentHub = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, + 0, DevInfo->bHubDeviceNumber, 0); + if (ParentHub != NULL) { + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->CapRegs->HcsParams1.MaxSlots; + + if ((ParentHub->DevMiscInfo < Usb3Hc->DeviceContext) || + (ParentHub->DevMiscInfo > (VOID*)((UINTN)(Usb3Hc->DeviceContext) + DeviceContextSize))) { + return 0; + } + ParentHubSlotCtx = XHCI_GetContextEntry(Usb3Hc, ParentHub->DevMiscInfo, 0); + HubPortNumber = (DevInfo->bHubPortNumber > 15)? 15 : DevInfo->bHubPortNumber; + InputSlot->RouteString = ParentHubSlotCtx->RouteString | + (HubPortNumber << (ParentHub->HubDepth * 4)); //(EIP51503) + + // Update TT fields in the Slot context for LS/FS device connected to HS hub + if (InputSlot->Speed == XHCI_DEVSPEED_FULL || InputSlot->Speed == XHCI_DEVSPEED_LOW) { + if (ParentHubSlotCtx->Speed == XHCI_DEVSPEED_HIGH) { + InputSlot->TtHubSlotId = XHCI_GetSlotId(Usb3Hc, ParentHub); + InputSlot->TtPortNumber = DevInfo->bHubPortNumber; + InputSlot->MultiTT = ParentHubSlotCtx->MultiTT; + } else { + InputSlot->TtHubSlotId = ParentHubSlotCtx->TtHubSlotId; + InputSlot->TtPortNumber = ParentHubSlotCtx->TtPortNumber; + InputSlot->MultiTT = ParentHubSlotCtx->MultiTT; + } + } + } + + OutputEp0 = XHCI_GetContextEntry(Usb3Hc, DevCtx, 1); + switch (OutputEp0->EpState) { + case XHCI_EP_STATE_DISABLED: + XfrRing = XHCI_InitXfrRing(Usb3Hc, SlotId, 0); + break; + case XHCI_EP_STATE_RUNNING: + case XHCI_EP_STATE_STOPPED: + XfrRing = XHCI_GetXfrRing(Usb3Hc, SlotId, 0); + break; + default: + break; + } + + // Initialize the Input default control Endpoint 0 Context + InputEp0 = XHCI_GetContextEntry(Usb3Hc, InputCtx, 2); + InputEp0->EpType = XHCI_EPTYPE_CTL; + InputEp0->MaxPacketSize = DevInfo->wEndp0MaxPacket; + InputEp0->TrDequeuePtr = (UINT64)(UINTN)XfrRing->QueuePtr | XfrRing->CycleBit; + InputEp0->AvgTrbLength = 8; + InputEp0->ErrorCount = 3; + + Bsr = (InputSlot->Speed != XHCI_DEVSPEED_SUPER && + InputSlot->Speed != XHCI_DEVSPEED_SUPER_PLUS && + OutputSlot->SlotState == XHCI_SLOT_STATE_DISABLED) ? 1 : 0; + + AddrDevParam = (UINT16)SlotId | (Bsr << 8); + + // Assign a new address 4.3.4, 4.6.5 + Status = XHCI_ExecuteCommand(HcStruc, XhciTAddressDeviceCmd, &AddrDevParam); + if (Status != USB_SUCCESS) { + XHCI_ExecuteCommand(HcStruc, XhciTDisableSlotCmd, &SlotId); + Usb3Hc->DcbaaPtr->DevCntxtAddr[SlotId-1] = 0; + return Status; + } + + if (Bsr == 0) { + USB_DEBUG(3, "XHCI: new device address %d\n", OutputSlot->DevAddr); + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciRingDoorbell +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XhciRingDoorbell( + USB3_HOST_CONTROLLER *Usb3Hc, + UINT8 SlotId, + UINT8 Dci +) +{ + volatile UINT32 *Doorbell; + XHCI_EP_CONTEXT *EpCtx = NULL; + UINT32 Count; + + Doorbell = XHCI_GetTheDoorbell(Usb3Hc, SlotId); + *Doorbell = Dci; + + if (SlotId == 0) { + return USB_ERROR; + } + + EpCtx = (XHCI_EP_CONTEXT*)XHCI_GetContextEntry(Usb3Hc, + XHCI_GetDeviceContext(Usb3Hc, SlotId), Dci); + // Wait for the endpoint running + for (Count = 0; Count < 10 * 1000; Count++) { + if (EpCtx->EpState == XHCI_EP_STATE_RUNNING) { + break; + } + FixedDelay(1); // 1 us delay + } + //ASSERT(EpCtx->EpState == XHCI_EP_STATE_RUNNING); + + if (EpCtx->EpState != XHCI_EP_STATE_RUNNING) { + return USB_ERROR; + } + + return USB_SUCCESS; +} + //<(EIP54283+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_Mmio64Write +// +// Description: +// HC may or may not support 64-bit writes to MMIO area. If it does, write +// Data directly, otherwise split into two DWORDs. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT64 +XHCI_Mmio64Read( + HC_STRUC *HcStruc, + USB3_HOST_CONTROLLER *Usb3Hc, + UINTN Address +) +{ + UINT64 Data = 0; + UINT32 Offset; + + Offset = (UINT32)(Address - HcStruc->BaseAddress); + + if ((Offset + sizeof(UINT64)) > HcStruc->BaseAddressSize) { + return 0; + } + + if (Usb3Hc->Access64) { + Data = *(UINT64*)Address; + } + else { + Data = *(UINT32*)Address; + Data = Shl64(*(UINT32*)(Address + sizeof(UINT32)), 32); + } + return Data; +} + +VOID +XHCI_Mmio64Write( + HC_STRUC *HcStruc, + USB3_HOST_CONTROLLER *Usb3Hc, + UINTN Address, + UINT64 Data +) +{ + UINT32 Offset; + + Offset = (UINT32)(Address - HcStruc->BaseAddress); + + if ((Offset + sizeof(UINT64)) > HcStruc->BaseAddressSize) { + return; + } + + if (Usb3Hc->Access64) { + *(UINT64*)Address = Data; + } + else { + *(UINT32*)Address = (UINT32)Data; + *(UINT32*)(Address + sizeof(UINT32)) = (UINT32)(Shr64(Data, 32)); + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_InitRing +// +// Description: +// Transfer ring initialization. There is an option to create a Link TRB in +// the end of the ring. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +XHCI_InitRing ( + IN OUT TRB_RING *Ring, + IN UINTN RingBase, + IN UINT32 RingSize, + IN BOOLEAN PlaceLinkTrb +) +{ + XHCI_LINK_TRB *LinkTrb; + EFI_STATUS Status = EFI_SUCCESS; + + Ring->Base = (XHCI_TRB*)RingBase; + Ring->Size = RingSize; + Ring->LastTrb = Ring->Base + RingSize - 1; + Ring->CycleBit = 1; + Ring->QueuePtr = (XHCI_TRB*)RingBase; + + // Initialize ring with zeroes + { + UINT8 *p = (UINT8*)RingBase; + UINTN i; + for (i = 0; i < RingSize*sizeof(XHCI_TRB); i++, p++) *p = 0; + } + + if (PlaceLinkTrb) { + // Place a Link TRB in the end of the ring pointing to the beginning + LinkTrb = (XHCI_LINK_TRB*)Ring->LastTrb; +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)LinkTrb, sizeof(XHCI_LINK_TRB)); + if (EFI_ERROR(Status)) { + return Status; + } +#endif + LinkTrb->NextSegPtr = (UINT64)(UINTN)RingBase; + LinkTrb->ToggleCycle = 1; + LinkTrb->TrbType = XhciTLink; + } + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: UpdatePortStatusSpeed +// +// Description: +// This function sets USB_PORT_STAT... fields that are related to device +// speed (LS/FS/HS/SS) in a given PortStatus variable. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +UpdatePortStatusSpeed( + UINT8 Speed, + UINT8 *PortStatus +) +{ + UINT8 PortSts = *PortStatus; + + ASSERT(Speed < 6); + PortSts &= ~USB_PORT_STAT_DEV_SPEED_MASK; + + switch (Speed) { + case XHCI_DEVSPEED_UNDEFINED: + break; + case XHCI_DEVSPEED_FULL: + PortSts |= USB_PORT_STAT_DEV_FULLSPEED; + break; + case XHCI_DEVSPEED_LOW: + PortSts |= USB_PORT_STAT_DEV_LOWSPEED; + break; + case XHCI_DEVSPEED_HIGH: + PortSts |= USB_PORT_STAT_DEV_HISPEED; + break; + case XHCI_DEVSPEED_SUPER: + PortSts |= USB_PORT_STAT_DEV_SUPERSPEED; + break; + case XHCI_DEVSPEED_SUPER_PLUS: + PortSts |= USB_PORT_STAT_DEV_SUPERSPEED_PLUS; + break; + default: + USB_DEBUG(3, "XHCI ERROR: unknown device speed.\n"); + } + + *PortStatus = PortSts; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciExtCapParser +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +XhciExtCapParser( + IN USB3_HOST_CONTROLLER *Usb3Hc +) +{ + XHCI_EXT_CAP *CurPtr; + + if (Usb3Hc->CapRegs->HccParams1.Xecp == 0) return EFI_SUCCESS; + + // Starts from first capability + CurPtr = (XHCI_EXT_CAP *)((UINTN)Usb3Hc->CapRegs + (Usb3Hc->CapRegs->HccParams1.Xecp << 2)); + + // Traverse all capability structures + for(;;) { + switch (CurPtr->CapId) { + case XHCI_EXT_CAP_USB_LEGACY: + Usb3Hc->ExtLegCap = (XHCI_EXT_LEG_CAP *)CurPtr; + USB_DEBUG(3, "XHCI: USB Legacy Ext Cap Ptr %x\n", Usb3Hc->ExtLegCap); + break; + + case XHCI_EXT_CAP_SUPPORTED_PROTOCOL: + if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x02) { + Usb3Hc->Usb2Protocol = (XHCI_EXT_PROTOCOL*)CurPtr; + USB_DEBUG(3, "XHCI: USB2 Support Protocol %x, PortOffset %x PortCount %x\n", + Usb3Hc->Usb2Protocol, Usb3Hc->Usb2Protocol->PortOffset, Usb3Hc->Usb2Protocol->PortCount); + } else if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x03) { + Usb3Hc->Usb3Protocol = (XHCI_EXT_PROTOCOL*)CurPtr; + USB_DEBUG(3, "XHCI: USB3 Support Protocol %x, PortOffset %x PortCount %x\n", + Usb3Hc->Usb3Protocol, Usb3Hc->Usb3Protocol->PortOffset, Usb3Hc->Usb3Protocol->PortCount); + } + break; + + case XHCI_EXT_CAP_POWERMANAGEMENT: + case XHCI_EXT_CAP_IO_VIRTUALIZATION: + break; + case XHCI_EXT_CAP_USB_DEBUG_PORT: + Usb3Hc->DbCapRegs = (XHCI_DB_CAP_REGS*)CurPtr; + USB_DEBUG(3, "XHCI: USB Debug Capability Ptr %x\n", Usb3Hc->DbCapRegs); + break; + } + if(CurPtr->NextCapPtr == 0) break; + // Point to next capability + CurPtr=(XHCI_EXT_CAP *)((UINTN)CurPtr+ (((UINTN)CurPtr->NextCapPtr) << 2)); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: XHCI_IsUsb3Port +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +XHCI_IsUsb3Port( + USB3_HOST_CONTROLLER *Usb3Hc, + UINT8 Port +) +{ + if ((Port >= Usb3Hc->Usb3Protocol->PortOffset) && + (Port < Usb3Hc->Usb3Protocol->PortOffset + Usb3Hc->Usb3Protocol->PortCount)) { + return TRUE; + } + return FALSE; +} + +//**************************************************************************** +// The following set of functions are the helpers to get the proper locations +// of xHCI data structures using the available pointers. +//**************************************************************************** + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_GetSlotId +// +// Description: +// This function calculates the slot ID out of a given DEV_INFO data pointer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +XHCI_GetSlotId( + USB3_HOST_CONTROLLER *Usb3Hc, + DEV_INFO *DevInfo +) +{ + UINT32 DevCtxSize = XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize; + return (UINT8)(((UINTN)DevInfo->DevMiscInfo - (UINTN)Usb3Hc->DeviceContext)/DevCtxSize) + 1; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XHCI_GetXfrRing +// +// Description: +// This routine calculates the address of the address ring of a particular +// Slot/Endpoint. +// +// Output: +// Pointer to the transfer ring +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +TRB_RING* +XHCI_GetXfrRing( + USB3_HOST_CONTROLLER* Usb3Hc, + UINT8 Slot, + UINT8 Ep +) +{ + return Usb3Hc->XfrRings + (Slot-1)*32 + Ep; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_GetTheDoorbell +// +// Description: +// This function calculates and returns the pointer to a doorbell for a +// given Slot. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32* +XHCI_GetTheDoorbell( + USB3_HOST_CONTROLLER *Usb3Hc, + UINT8 SlotId +) +{ + return (UINT32*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->DbOffset + sizeof(UINT32)*SlotId); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_GetDevInfo +// +// Description: +// This function searches for DEV_INFO data pointer that belongs to a given XHCI +// device context. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +XHCI_GetDevInfo( + UINTN PollTdPtr +) +{ + UINT8 i; + DEV_INFO *DevInfo; + + if (PollTdPtr == 0) return NULL; + + for (i=1; i<MAX_DEVICES; i++) { + DevInfo = &gUsbData->aDevInfoTable[i]; + if ((DevInfo->Flag & DEV_INFO_VALIDPRESENT) != DEV_INFO_VALIDPRESENT) { + continue; + } + if (DevInfo->fpPollTDPtr == NULL) { + continue; + } + if ((UINTN)DevInfo->fpPollTDPtr == (UINTN)PollTdPtr) { + return DevInfo; + } + } + return NULL; // Device not found +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_GetDeviceContext +// +// Description: +// This function calculates and returns the pointer to a device context for +// a given Slot. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID* +XHCI_GetDeviceContext( + USB3_HOST_CONTROLLER *Usb3Hc, + UINT8 SlotId +) +{ + UINT32 DevCtxSize = XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize; + return (UINT8*)((UINTN)Usb3Hc->DeviceContext + (SlotId - 1) * DevCtxSize); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: XHCI_GetContextEntry +// +// Description: +// This function calculates and returns the pointer to a context entry for +// a given index. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID* +XHCI_GetContextEntry( + USB3_HOST_CONTROLLER *Usb3Hc, + VOID *Context, + UINT8 Index +) +{ + return (UINT8*)((UINTN)Context + Index * Usb3Hc->ContextSize); +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** diff --git a/Core/EM/usb/rt/xhci.h b/Core/EM/usb/rt/xhci.h new file mode 100644 index 0000000..9cbb9cc --- /dev/null +++ b/Core/EM/usb/rt/xhci.h @@ -0,0 +1,1189 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: xhci.h +// +// Description: XHCI equates and structure definitions +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _XHCI_H_ +#define _XHCI_H_ + +#include <Token.h> +#include "usbkbd.h" + +#pragma pack(push, 1) + +// XHCI Device Context structures +//--------------------------------------------------------------------------- + +typedef struct { + UINT64 ScratchpadBufArrayPtr; + UINT64 DevCntxtAddr[255]; +} XHCI_DCBAA; // Total size is 256 64-bit entries, or 2K Bytes (section 6.1) + +// XHCI PCI Configuration Registers +//--------------------------------------------------------------------------- + +// Serial Bus Release Number Register +#define XHCI_PCI_SBRN 0x60 + +// Frame Length Adjustment Register +#define XHCI_PCI_FLADJ 0x61 + +// Host Controller Capability Registers +//--------------------------------------------------------------------------- + +typedef struct { + UINT32 MaxSlots : 8; // Number of Device Slots + UINT32 MaxIntrs : 11; // Number of Interrupters + UINT32 Rsvd : 5; // Reserved + UINT32 MaxPorts : 8; // Number of ports +} HCSPARAMS1; + +typedef struct { + UINT32 Ist : 4; // Isochronous Scheduling Threshold + UINT32 ErstMax : 4; // Event Ring Segment Table Max + UINT32 Rsvd : 13; + UINT32 MaxScratchPadBufsHi : 5; // Max Scratchpad Buffers (Max Scratchpad Bufs Hi). + UINT32 Spr : 1; // Scratchpad restore + UINT32 MaxScratchPadBufsLo : 5; // Max Scratchpad Buffers (Max Scratchpad Bufs Lo). +} HCSPARAMS2; + +typedef struct { + UINT32 U1DevExitLatency : 8; // Worst case latency of U1->U0, mks + UINT32 Rsvd : 8; + UINT32 U2DevExitLatency : 16; // Worst case latency of U2->U0, mks +} HCSPARAMS3; + +typedef struct { + UINT32 Ac64 : 1; // 64-bit Addressing Capability + UINT32 Bnc : 1; // Bandwidth Negotiation Capability + UINT32 Csz : 1; // Context data structures width (32 or 64 bit) + UINT32 Ppc : 1; // Power Port Control + UINT32 Pind : 1; // Port Indicators + UINT32 Lhrc : 1; // Light HC Reset Capability + UINT32 Ltc : 1; // Latency Tolerance Capability + UINT32 Nss : 1; // No Secondary SID Support + UINT32 Pae : 1; // Parse All Event Data + UINT32 Spc : 1; // Stopped - Short Packet Capability + UINT32 Sec : 1; // Stopped EDTLA Capability + UINT32 Cfc : 1; // Contiguous Frame ID Capability + UINT32 MaxPsaSize : 4; // Maximum Primary Stream Array Size + UINT32 Xecp : 16; // xHCI Extended Capabilities Pointer +} HCCPARAMS1; + +typedef struct { + UINT32 U3c : 1; // U3 Entry Capability + UINT32 Cmc : 1; // Configure Endpoint Command Max Exit Latency Too Large Capability + UINT32 Fsc : 1; // Force Save Context Capability + UINT32 Ctc : 1; // Compliance Transition Capability + UINT32 Lec : 1; // Large ESIT Payload Capability + UINT32 Cic : 1; // Configuration Information Capability + UINT32 Rsvd : 26; +} HCCPARAMS2; + +typedef struct { + UINT8 CapLength; // 00 + UINT8 Rsvd; // 01 + UINT16 HciVersion; // 02 + HCSPARAMS1 HcsParams1; // 04 + HCSPARAMS2 HcsParams2; // 08 + HCSPARAMS3 HcsParams3; // 0C + HCCPARAMS1 HccParams1; // 10 + UINT32 DbOff; // 14 + UINT32 RtsOff; // 18 + HCCPARAMS2 HccParams2; // 1C +} XHCI_HC_CAP_REGS; + +//----------------------------------------------------------- +// Host Controller Operational Registers +//----------------------------------------------------------- +typedef struct { + union { + UINT32 AllBits; // can be used for clearing status + #define XHCI_CMD_RS BIT0 + #define XHCI_CMD_HCRST BIT1 + #define XHCI_CMD_INTE BIT2 + #define XHCI_CMD_HSEE BIT3 + #define XHCI_CMD_LHCRST BIT4 + struct { + UINT32 RunStop : 1; + UINT32 HcRst : 1; // HC Reset + UINT32 Inte : 1; // Interrupter Enable + UINT32 HsEe : 1; // Host System Error Enable + UINT32 Rsvd : 3; + UINT32 LhcRst : 1; // Light Host Controller Reset + UINT32 Css : 1; // Controller Save State + UINT32 Crs : 1; // Controller Restore State + UINT32 Ewe : 1; // Enable Wrap Event + UINT32 Eu3S : 1; // Enable U3 MFINDEX Stop + UINT32 Rsvd1 : 20; + } Field; + }; +} XHCI_USBCMD; + +typedef struct { + union { + UINT32 AllBits; // can be used for clearing status + #define XHCI_STS_HALTED BIT0 + #define XHCI_STS_HOSTSYSTEM_ERROR BIT2 + #define XHCI_STS_EVT_INTERRUPT BIT3 + #define XHCI_STS_PCD BIT4 + struct { + UINT32 HcHalted : 1; + UINT32 Rsvd1 : 1; + UINT32 Hse : 1; // Host System Error + UINT32 Eint : 1; // Event Interrupt + UINT32 Pcd : 1; // Port Change Detect + UINT32 Rsvd2 : 3; + UINT32 Sss : 1; // Save State Status + UINT32 Rss : 1; // Restore State Status + UINT32 Sre : 1; // Save/Restore Error + UINT32 Cnr : 1; // Controller Not Ready + UINT32 Hce : 1; // Host Controller Error + UINT32 Rsvd3 : 19; + } Field; + }; +} XHCI_USBSTS; + +typedef struct { + UINT32 Rcs : 1; // Ring Cycle State + UINT32 Cs : 1; // Command Stop + UINT32 Ca : 1; // Command Abort + UINT32 Crr : 1; // Command Ring Running + UINT32 Rsvd : 2; + UINT32 CrPointer : 26; // Command Ring Pointer +} XHCI_CRCR; + +#define XHCI_PORT_CONNECT BIT0 +#define XHCI_PORT_ENABLE BIT1 +#define XHCI_PORT_RESET BIT4 +#define XHCI_PORT_RESET_CHG BIT21 + +#define XHCI_PORTSC_OFFSET 0x400 + +// Port speed definitions as read from PortSpeed field of PORTSC +#define XHCI_DEVSPEED_UNDEFINED 0 +#define XHCI_DEVSPEED_FULL 1 +#define XHCI_DEVSPEED_LOW 2 +#define XHCI_DEVSPEED_HIGH 3 +#define XHCI_DEVSPEED_SUPER 4 +#define XHCI_DEVSPEED_SUPER_PLUS 5 + +// Port link definitions +#define XHCI_PORT_LINK_U0 0 +#define XHCI_PORT_LINK_U1 1 +#define XHCI_PORT_LINK_U2 2 +#define XHCI_PORT_LINK_U3 3 +#define XHCI_PORT_LINK_DISABLED 4 +#define XHCI_PORT_LINK_RXDETECT 5 +#define XHCI_PORT_LINK_INACTIVE 6 +#define XHCI_PORT_LINK_POLLING 7 +#define XHCI_PORT_LINK_RECOVERY 8 +#define XHCI_PORT_LINK_HOT_RESET 9 +#define XHCI_PORT_LINK_COMPLIANCE_MODE 10 +#define XHCI_PORT_LINK_TEST_MODE 11 +#define XHCI_PORT_LINK_RESUME 15 + +typedef struct { + union { + UINT32 AllBits; // can be used for clearing status + #define XHCI_PCS_CCS BIT0 + #define XHCI_PCS_PED BIT1 + #define XHCI_PCS_OCA BIT3 + #define XHCI_PCS_PR BIT4 + #define XHCI_PCS_PP BIT9 + #define XHCI_PCS_LWS BIT16 + #define XHCI_PCS_CSC BIT17 + #define XHCI_PCS_WRC BIT19 + #define XHCI_PCS_PRC BIT21 + #define XHCI_PCS_WPR BIT31 + struct { + UINT32 Ccs : 1; // 0 Current Connect Status - RO + UINT32 Ped : 1; // 1 Port Enabled/Disabled - RW1CS + UINT32 RsvdZ1 : 1; // 2 + UINT32 Oca : 1; // 3 Over-current Active - RO + UINT32 Pr : 1; // 4 Port Reset - RW1S + UINT32 Pls : 4; // 5..8 Port Link State - RWS + UINT32 Pp : 1; // 9 Port Power - RWS + UINT32 PortSpeed : 4; // 10..13 Port Speed - RO + UINT32 Pic : 2; // 14..15 Port Indicator Ctl - RWS + UINT32 Lws : 1; // 16 Port Link State Write Strobe - RW + UINT32 Csc : 1; // 17 Connect Status Change - RW1CS + UINT32 Pec : 1; // 18 Port Enabled/Disabled Change - RW1CS + UINT32 Wrc : 1; // 19 Warm Port Reset Change - RW1CS/RsvdZ + UINT32 Occ : 1; // 20 Over-current Change - RW1CS + UINT32 Prc : 1; // 21 Port Reset Change - RW1CS + UINT32 Plc : 1; // 22 Port Link State Change - RW1CS + UINT32 Cec : 1; // 23 Port Config Error Change - RW1CS/RsvdZ + UINT32 Cas : 1; // 24 Cold Attach Status - RO + UINT32 Wce : 1; // 25 Wake on Connect Enable - RWS + UINT32 Wde : 1; // 26 Wake on Disconnect Enable - RWS + UINT32 Woe : 1; // 27 Wake on Over-current Enable - RWS + UINT32 RsvdZ2 : 2; // 28..29 + UINT32 Dr : 1; // 30 Device Removable (0 removable) - RO + UINT32 Wpr : 1; // 31 Warm Port Reset - RW1S/RsvdZ + } Field; + }; +} XHCI_PORTSC; + +typedef struct { + XHCI_USBCMD UsbCmd; // 00 + XHCI_USBSTS UsbSts; // 04 + UINT32 PageSize; // 08 + UINT8 Rsvd1[8]; // 0C + UINT32 DnCtrl; // 14 Device Notification Control + UINT64 Crcr; // 18 Command Ring Control + UINT8 Rsvd2[16]; // 20 + UINT64 DcbAap; // 30 Device Context Base Address Array Pointer + UINT32 Config; // 38 Max Device Slots Enabled +} XHCI_HC_OP_REGS; + + +#define CRCR_RING_CYCLE_STATE BIT0 +#define CRCR_COMMAND_STOP BIT1 +#define CRCR_COMMAND_ABORT BIT2 +#define CRCR_COMMAND_RUNNING BIT3 + +// 6.5 +typedef struct { + UINT64 RsBase; + UINT16 RsSize; + UINT16 Rsvd1; + UINT32 Rsvd2; +} XHCI_ER_SEGMENT_ENTRY; + +// Interrupt Moderation Interval (5.5.2.2) +// Minimum inter-interrupt interval, in 250ns units. The value of 4000 makes 1ms interval. +#define XHCI_IMODI 4000 +#define XHCI_KEYREPEAT_IMODI REPEAT_INTERVAL * 4000 +#define XHCI_KEYREPEAT_IMODC REPEAT_INTERVAL * 4000 + +// Note: the following structure defines 32-bit and 64-bits fields +// without detailing; this MMIO data must be accessed using Dword +// access for 32-bit fields and Qword access for 64-bit, Section 5.5. +typedef struct { + UINT32 IMan; // Interrupter Management + UINT32 IMod; // Interrupter Moderation + UINT32 Erstz; // Event Ring Segment Table Size + UINT32 RsrvP; + UINT64 Erstba; // Event Ring Segment Table Base Address + UINT64 Erdp; // Event Ring Dequeue Pointer +} XHCI_INTERRUPTER_REGS; + +typedef struct { + UINT32 MfIndex; + UINT32 Reserved[7]; + XHCI_INTERRUPTER_REGS IntRegs[1024]; +} XHCI_HC_RT_REGS; + +typedef enum { + XhciTNormal = 1, + XhciTSetupStage, // 2 + XhciTDataStage, // 3 + XhciTStatusStage,// 4 + XhciTIsoch, // 5 + XhciTLink, // 6 + XhciTEventData, // 7 + XhciTNoOp, // 8 + XhciTEnableSlotCmd, // 9 + XhciTDisableSlotCmd, // 10 + XhciTAddressDeviceCmd, // 11 + XhciTConfigureEndpointCmd, //12 + XhciTEvaluateContextCmd, //13 + XhciTResetEndpointCmd, //14 + XhciTStopEndpointCmd, // 15 + XhciTSetTRDequeuePointerCmd, //16 + XhciTResetDeviceCmd, // 17 + XhciTForceEventCmd, // 18 + XhciTNegotiateBandwidthCmd, // 19 + XhciTSetLatencyToleranceCmd, // 20 + XhciTGetPortBandwidthCmd, // 21 + XhciTForceHeaderCmd, // 22 + XhciTNoOpCmd, // 23 +// 24..31 reserved + XhciTTransferEvt = 32, + XhciTCmdCompleteEvt, // 33 + XhciTPortStatusChgEvt, // 34 + XhciTBandwidthRequestEvt, // 35 + XhciTDoorbellEvt, // 36 + XhciTHostControllerEvt, // 37 + XhciTDevNotificationEvt, // 38 + XhciTMfIndexWrapEvt // 39 +} TRB_TYPE; + +//--------------------------------------------------------- +// Slot context definitions, Section 6.2.2 +//--------------------------------------------------------- +typedef struct { + UINT32 RouteString : 20; + UINT32 Speed : 4; + UINT32 RsvdZ1 : 1; + UINT32 MultiTT : 1; + UINT32 Hub : 1; + UINT32 ContextEntries : 5; + + UINT32 MaxExitLatency : 16; + UINT32 RootHubPort : 8; + UINT32 PortsNum : 8; + + UINT32 TtHubSlotId : 8; + UINT32 TtPortNumber : 8; + UINT32 TThinkTime : 2; + UINT32 RsvdZ3 : 4; + UINT32 Interrupter : 10; + + UINT32 DevAddr : 8; + UINT32 RsvdZ4 : 19; + UINT32 SlotState : 5; + + UINT32 RsvdO[4]; +} XHCI_SLOT_CONTEXT; + +// XHCI_SLOT_CONTEXT.DW3.SlotState definitions +#define XHCI_SLOT_STATE_DISABLED 0 +#define XHCI_SLOT_STATE_DEFAULT 1 +#define XHCI_SLOT_STATE_ADDRESSED 2 +#define XHCI_SLOT_STATE_CONFIGURED 3 + + +//--------------------------------------------------------- +// Endpoint Context context definitions, Section 6.2.3 +//--------------------------------------------------------- + +// Endpoint types, Table 57 + +#define XHCI_EPTYPE_NOT_VALID 0 +#define XHCI_EPTYPE_ISOCH_OUT 1 +#define XHCI_EPTYPE_BULK_OUT 2 +#define XHCI_EPTYPE_INT_OUT 3 +#define XHCI_EPTYPE_CTL 4 +#define XHCI_EPTYPE_ISOCH_IN 5 +#define XHCI_EPTYPE_BULK_IN 6 +#define XHCI_EPTYPE_INT_IN 7 + +typedef struct { + UINT32 EpState : 3; + UINT32 RsvdZ1 : 5; + UINT32 Mult : 2; + UINT32 MaxPStreams : 5; + UINT32 Lsa : 1; + UINT32 Interval : 8; + UINT32 RzvdZ2 : 8; + + UINT32 RzvdZ3 : 1; + UINT32 ErrorCount : 2; + UINT32 EpType : 3; + UINT32 RsvdZ : 1; + UINT32 Hid : 1; + UINT32 MaxBurstSize : 8; + UINT32 MaxPacketSize : 16; + + UINT64 TrDequeuePtr; // BIT0 of this field is DCS (Dequeue Cycle State) + UINT16 AvgTrbLength; + UINT16 MaxEsitPayload; + UINT32 RsvdO[3]; +} XHCI_EP_CONTEXT; + +// XHCI_EP_CONTEXT.DW0.State definitions +#define XHCI_EP_STATE_DISABLED 0 +#define XHCI_EP_STATE_RUNNING 1 +#define XHCI_EP_STATE_HALTED 2 +#define XHCI_EP_STATE_STOPPED 3 +#define XHCI_EP_STATE_ERROR 4 + +// XHCI_EP_CONTEXT.DW1.EpType definitions +#define XHCI_EP_TYPE_NOTVALID 0 +#define XHCI_EP_TYPE_ISO_OUT 1 +#define XHCI_EP_TYPE_BLK_OUT 2 +#define XHCI_EP_TYPE_INT_OUT 3 +#define XHCI_EP_TYPE_CONTROL 4 +#define XHCI_EP_TYPE_ISO_IN 5 +#define XHCI_EP_TYPE_BLK_IN 6 +#define XHCI_EP_TYPE_INT_IN 7 + +//--------------------------------------------------------- +// Device context definition +//--------------------------------------------------------- +typedef struct { + XHCI_SLOT_CONTEXT Slot; + XHCI_EP_CONTEXT Ep[31]; +} XHCI_DEVICE_CONTEXT; + +#define XHCI_DEVICE_CONTEXT_ENTRIES 32 + +// TRB completion codes Table 130 +#define XHCI_TRB_INVALID 0 +#define XHCI_TRB_SUCCESS 1 +#define XHCI_TRB_DATABUF_ERROR 2 +#define XHCI_TRB_BABBLE_ERROR 3 +#define XHCI_TRB_TRANSACTION_ERROR 4 +#define XHCI_TRB_TRB_ERROR 5 +#define XHCI_TRB_STALL_ERROR 6 +#define XHCI_TRB_RESOURCE_ERROR 7 +#define XHCI_TRB_BANDWIDTH_ERROR 8 +#define XHCI_TRB_OUTOFSLOTS_ERROR 9 +#define XHCI_TRB_INVALIDSTREAMTYPE_ERROR 10 +#define XHCI_TRB_SLOTNOTENABLED_ERROR 11 +#define XHCI_TRB_ENDPOINTNOTENABLED_ERROR 12 +#define XHCI_TRB_SHORTPACKET 13 +#define XHCI_TRB_RINGUNDERRUN 14 +#define XHCI_TRB_RINGOVERRUN 15 +#define XHCI_TRB_VFRINGFULL_ERROR 16 +#define XHCI_TRB_PARAMETER_ERROR 17 +#define XHCI_TRB_BANDWIDTHOVERRUN_ERROR 18 +#define XHCI_TRB_CONTEXTSTATE_ERROR 19 +#define XHCI_TRB_NOPINGRESPONSE_ERROR 20 +#define XHCI_TRB_EVENTRINGFULL_ERROR 21 +#define XHCI_TRB_MISSEDSERVICE_ERROR 23 +#define XHCI_TRB_CMDRINGSTOPPED 24 +#define XHCI_TRB_COMMANDABORTED 25 +#define XHCI_TRB_STOPPED 26 +#define XHCI_TRB_STOPPEDLENGTHINVALID 27 +#define XHCI_TRB_CONTROLABORT_ERROR 28 +#define XHCI_TRB_ISOCHBUFOVERRUN 31 +#define XHCI_TRB_EVENTLOST_ERROR 32 +#define XHCI_TRB_UNDEFINED_ERROR 33 +#define XHCI_TRB_INVALIDSTREAMID_ERROR 34 +#define XHCI_TRB_SECONDARYBANDWIDTH_ERROR 35 +#define XHCI_TRB_SPLITTRANSACTION_ERROR 36 + +#define XHCI_TRB_EXECUTION_TIMEOUT_ERROR 255 + +//--------------------------------------------------------- +// Transfer Descriptor Block (TRB) definitions, section 4.11 +//--------------------------------------------------------- +// TRB Template +typedef struct { + UINT32 Param1; + UINT32 Param2; + + UINT32 RsvdZ1 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 16; +} XHCI_TRB; + +// Event TRB types, Section 6.4.2 +typedef struct { + UINT64 TrbPtr; + + UINT32 TransferLength : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ1 : 1; + UINT32 EventData : 1; + UINT32 RsvdZ2 : 7; + UINT32 TrbType : 6; + UINT32 EndpointId : 5; + UINT32 RzvdZ3 : 3; + UINT32 SlotId : 8; +} XHCI_TRANSFER_EVT_TRB; + +typedef struct { + UINT64 CmdTrbPtr; + + UINT32 RsvdZ1 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 VfId : 8; + UINT32 SlotId : 8; +} XHCI_CMDCOMPLETE_EVT_TRB; + +typedef struct { + UINT32 RsvdZ1 : 24; + UINT32 PortId : 8; + + UINT32 RsvdZ2; + + UINT32 RsvdZ3 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ4 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ5 : 16; +} XHCI_PORTSTSCHG_EVT_TRB; + +typedef struct { + UINT32 RsvdZ1[2]; + + UINT32 RsvdZ2 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ3 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ4 : 8; + UINT32 SlotId : 8; +} XHCI_BANDWIDTHRQ_EVT_TRB; + +typedef struct { + UINT32 DbReason : 5; + UINT32 RsvdZ1 : 27; + + UINT32 Rsvd2; + + UINT32 RsvdZ3 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ4 : 9; + UINT32 TrbType : 6; + UINT32 VfId : 8; + UINT32 SlotId : 8; +} XHCI_DORBELL_EVT_TRB; + +typedef struct { + UINT32 RsvdZ1[2]; + + UINT32 RsvdZ2 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ3 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ4 : 16; +} XHCI_HC_EVT_TRB; + +typedef struct { + UINT8 RsvdZ1 : 4; + UINT8 NtfType : 4; + + UINT8 DevNtfData[7]; + + UINT32 RsvdZ2 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ3 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ4 : 8; + UINT32 SlotId : 8; +} XHCI_DEVNOTIFY_EVT_TRB; + +typedef struct { + UINT32 RsvdZ[2]; + + UINT32 RsvdZ2 : 24; + UINT32 CompletionCode : 8; + + UINT32 CycleBit : 1; + UINT32 RsvdZ3 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ4 : 16; +} XHCI_MFINDXWRAP_EVT_TRB; + +typedef union { + XHCI_TRANSFER_EVT_TRB TransferEvt; + XHCI_CMDCOMPLETE_EVT_TRB CmdEvt; + XHCI_PORTSTSCHG_EVT_TRB PortStsChgEvt; + XHCI_BANDWIDTHRQ_EVT_TRB BandwidthRqEvt; + XHCI_DORBELL_EVT_TRB DoorbellEvt; + XHCI_HC_EVT_TRB HcEvt; + XHCI_DEVNOTIFY_EVT_TRB DevNotificationEvt; + XHCI_MFINDXWRAP_EVT_TRB MicroframeIndxWrapEvt; +} XHCI_EVENT_TRB; + +// Command TRB types, Section 6.4.3 +typedef struct { + UINT32 RsvdZ1[3]; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 16; +} XHCI_COMMON_CMD_TRB; + +typedef struct { + UINT32 RsvdZ1[3]; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 8; + UINT32 SlotId : 8; +} XHCI_DISABLESLOT_CMD_TRB; + +typedef struct { + UINT64 InpCtxAddress; + UINT32 RsvdZ1; + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 8; + UINT32 Bsr : 1; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 8; + UINT32 SlotId : 8; +} XHCI_ADDRESSDEV_CMD_TRB; + +typedef struct { + UINT64 InpCtxAddress; + UINT32 RsvdZ1; + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 8; + UINT32 Dc : 1; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 8; + UINT32 SlotId : 8; +} XHCI_CONFIGURE_EP_CMD_TRB; + +typedef struct { + UINT64 InpCtxAddress; + UINT32 RsvdZ1; + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 RsvdZ3 : 8; + UINT32 SlotId : 8; +} XHCI_EVALUATE_CONTEXT_CMD_TRB; + +typedef struct { + UINT32 RsvdZ1[3]; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 8; + UINT32 Tsp : 1; + UINT32 TrbType : 6; + UINT32 EndpointId : 5; + UINT32 RsvdZ3 : 3; + UINT32 SlotId : 8; +} XHCI_RESET_EP_CMD_TRB; + +typedef struct { + UINT64 TrPointer; + + UINT32 RsvdZ1 :16; + UINT32 StreamId :16; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 EndpointId : 5; + UINT32 RsvdZ3 : 3; + UINT32 SlotId : 8; +} XHCI_SET_TRPTR_CMD_TRB; + //(EIP54300+)> +typedef struct { + UINT32 RsvdZ1[3]; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 9; + UINT32 TrbType : 6; + UINT32 EndpointId : 5; + UINT32 RsvdZ3 : 2; + UINT32 Suspend : 1; + UINT32 SlotId : 8; +} XHCI_STOP_EP_CMD_TRB; + //<(EIP54300+) +typedef union { + XHCI_COMMON_CMD_TRB GenericCmdTrb; + XHCI_COMMON_CMD_TRB NoOpCmdTrb; + XHCI_COMMON_CMD_TRB EnableSlotCmdTrb; + XHCI_DISABLESLOT_CMD_TRB DisableSlotCmdTrb; + XHCI_ADDRESSDEV_CMD_TRB AddressDevCmdTrb; + XHCI_SET_TRPTR_CMD_TRB SetTrPtrCmdTrb; +} XHCI_CMD_TRB; + +// Transfer TRB types, Section 6.4.1 + +typedef struct { + UINT64 DataBuffer; + + UINT32 XferLength : 17; + UINT32 TdSize : 5; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 EvalNext : 1; + UINT32 Isp : 1; + UINT32 NoSnoop : 1; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 Idt : 1; + UINT32 RsvdZ1 : 2; + UINT32 Bei : 1; + UINT32 TrbType : 6; + UINT32 Rsvd2 : 16; +} XHCI_NORMAL_XFR_TRB; + +#define XHCI_XFER_TYPE_NO_DATA 0 +#define XHCI_XFER_TYPE_DATA_OUT 2 +#define XHCI_XFER_TYPE_DATA_IN 3 + +typedef struct { + UINT8 bmRequestType; + UINT8 bRequest; + UINT16 wValue; + UINT16 wIndex; + UINT16 wLength; + + UINT32 XferLength : 17; + UINT32 RsvdZ1 : 5; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 RsvdZ2 : 4; + UINT32 Ioc : 1; + UINT32 Idt : 1; + UINT32 RsvdZ3 : 3; + UINT32 TrbType : 6; + UINT32 Trt : 2; + UINT32 RsvdZ4 : 14; +} XHCI_SETUP_XFR_TRB; + +typedef struct { + UINT64 DataBuffer; + + UINT32 XferLength : 17; + UINT32 TdLength : 5; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 EvalNext : 1; + UINT32 Isp : 1; + UINT32 NoSnoop : 1; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 Idt : 1; + UINT32 RsvdZ1 : 3; + UINT32 TrbType : 6; + UINT32 Dir : 1; + UINT32 Rsvd2 : 15; +} XHCI_DATA_XFR_TRB; + +typedef struct { + UINT64 RsvdZ1; + + UINT32 RsvdZ2 : 22; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 EvalNext : 1; + UINT32 RsvdZ3 : 2; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 RsvdZ4 : 4; + UINT32 TrbType : 6; + UINT32 Dir : 1; + UINT32 Rsvd2 : 15; +} XHCI_STATUS_XFR_TRB; + +typedef struct { + UINT64 DataBuffer; + + UINT32 XferLength : 17; + UINT32 TdLength : 5; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 EvalNext : 1; + UINT32 Isp : 1; + UINT32 NoSnoop : 1; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 Idt : 1; + UINT32 RsvdZ1 : 3; + UINT32 TrbType : 6; + UINT32 Rsvd2 : 4; + UINT32 FrameId : 11; + UINT32 Sia : 1; +} XHCI_ISOCH_XFR_TRB; + +typedef struct { + UINT64 RsvdZ1; + + UINT32 RsvdZ2 : 22; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 EvalNext : 1; + UINT32 RsvdZ3 : 2; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 RsvdZ4 : 4; + UINT32 TrbType : 6; + UINT32 Rsvd2 : 16; +} XHCI_NOOP_XFR_TRB; + +typedef union { + XHCI_NORMAL_XFR_TRB NormalXfrTrb; + XHCI_SETUP_XFR_TRB SetupXfrTrb; + XHCI_DATA_XFR_TRB DataXfrTrb; + XHCI_STATUS_XFR_TRB StatusXfrTrb; + XHCI_ISOCH_XFR_TRB IsockXfrTrb; + XHCI_NOOP_XFR_TRB NoopXfrTrb; +} XHCI_XFR_TRB; + + +// Other TRB types +typedef struct { + UINT64 NextSegPtr; + + UINT32 RsvdZ1 : 22; + UINT32 Interrupter : 10; + + UINT32 CycleBit : 1; + UINT32 ToggleCycle : 1; + UINT32 RsvdZ2 : 2; + UINT32 Chain : 1; + UINT32 Ioc : 1; + UINT32 RsvdZ3 : 4; + UINT32 TrbType : 6; + UINT32 RsvdZ4 : 16; +} XHCI_LINK_TRB; + +typedef struct { + XHCI_TRB *Base; + UINT32 Size; // #of TRBs in the ring + XHCI_TRB* LastTrb; + XHCI_TRB* QueuePtr; + UINT8 CycleBit; + UINT8 Pad[27-3*sizeof(VOID*)]; // Make size 32 Bytes +} TRB_RING; + +// The following definition fixes the size of ring +// segment to TRBS_PER_SEGMENT * sizeof(XHCI_TRB) +#define TRBS_PER_SEGMENT 64 +#define RING_SIZE TRBS_PER_SEGMENT*sizeof(XHCI_TRB) + +// Default timeouts +#ifndef XHCI_CMD_COMPLETE_TIMEOUT_MS +#define XHCI_CMD_COMPLETE_TIMEOUT_MS 20 +#endif +#ifndef XHCI_ADDR_CMD_COMPLETE_TIMEOUT_MS +#define XHCI_ADDR_CMD_COMPLETE_TIMEOUT_MS 2000 +#endif +#ifndef XHCI_CTL_COMPLETE_TIMEOUT_MS +#define XHCI_CTL_COMPLETE_TIMEOUT_MS 2000 +#endif +//#define XHCI_BULK_COMPLETE_TIMEOUT_MS 15000 //(EIP61193) +#ifndef XHCI_INT_COMPLETE_TIMEOUT_MS +#define XHCI_INT_COMPLETE_TIMEOUT_MS 1500 +#endif + +#ifndef XHCI_RESET_PORT_DELAY_MS +#define XHCI_RESET_PORT_DELAY_MS 10 +#endif + +#ifndef XHCI_RESET_EP_DELAY_MS +#define XHCI_RESET_EP_DELAY_MS 10 +#endif + +//#define XHCI_BOT_TD_MAXSIZE 512 +#define XHCI_BOT_TD_MAXSIZE 0x10000 +#define XHCI_BOT_MAX_XFR_SIZE XHCI_BOT_TD_MAXSIZE*8 + +#ifndef XHCI_SWITCH2SS_DELAY_MS +#define XHCI_SWITCH2SS_DELAY_MS 5 +#endif + +#ifndef XHCI_WAIT_PORT_STABLE_DELAY_MS +#define XHCI_WAIT_PORT_STABLE_DELAY_MS 50 +#endif + +#ifndef XHCI_MAX_PENDING_INTERRUPT_TRANSFER +#define XHCI_MAX_PENDING_INTERRUPT_TRANSFER 16 +#endif + +//--------------------------------------------------------- +// Input context definition +//--------------------------------------------------------- +typedef struct { + UINT32 DropContextFlags; + UINT32 AddContextFlags; + UINT32 RzvdZ[6]; +} XHCI_INPUT_CONTROL_CONTEXT; + +typedef struct { + XHCI_INPUT_CONTROL_CONTEXT CtlCtx; + XHCI_DEVICE_CONTEXT DevCtx; +} XHCI_INPUT_CONTEXT; + +#define XHCI_INPUT_CONTEXT_ENTRIES 33 + +//--------------------------------------------------------- +// Extended Capabilities +//--------------------------------------------------------- +#define XHCI_EXT_CAP_USB_LEGACY 1 +#define XHCI_EXT_CAP_SUPPORTED_PROTOCOL 2 +#define XHCI_EXT_CAP_POWERMANAGEMENT 3 +#define XHCI_EXT_CAP_IO_VIRTUALIZATION 4 +#define XHCI_EXT_CAP_USB_DEBUG_PORT 10 + +typedef struct { + UINT32 CapId:8; // Capability ID + UINT32 NextCapPtr:8; // Next xHCI Extended Capability Pointer + UINT32 Cap:16; // Capability Specific +} XHCI_EXT_CAP; + +#define XHCI_BIOS_OWNED_SEMAPHORE BIT16 +#define XHCI_OS_OWNED_SEMAPHORE BIT24 + +typedef struct { + UINT32 CapId:8; + UINT32 NextCapPtr:8; + UINT32 HcBiosOwned:1; + UINT32 RsvdP1:7; + UINT32 HcOsOwned:1; + UINT32 RsvdP2:7; +} XHCI_LEGSUP; + +#define XHCI_SMI_ENABLE BIT0 +#define XHCI_SMI_HOST_ERROR_ENABLE BIT4 +#define XHCI_SMI_OWNERSHIP_CHANGE_ENABLE BIT13 +#define XHCI_SMI_PCI_CMD_ENABLE BIT14 +#define XHCI_SMI_PCI_BAR_ENABLE BIT15 +#define XHCI_SMI_EVENT_INT BIT16 +#define XHCI_SMI_HOST_ERROR BIT20 +#define XHCI_SMI_OWNERSHIP_CHANGE BIT29 +#define XHCI_SMI_PCI_CMD BIT30 +#define XHCI_SMI_PCI_BAR BIT31 + +typedef union { + UINT32 AllBits; + struct { + UINT32 UsbSmiEnable:1; + UINT32 RsvdP1:3; + UINT32 UsbHostErrorSmiEnable:1; + UINT32 RsvdP2:8; + UINT32 UsbOwnershipChangeSmiEnable:1; + UINT32 UsbPciCmdSmiEnable:1; + UINT32 UsbPciBarSmiEnable:1; + UINT32 UsbEventInterruptSmi:1; + UINT32 RsvdP3:3; + UINT32 UsbHostErrorSmi:1; + UINT32 RsvdP4:8; + UINT32 UsbOwnershipChangeSmi:1; + UINT32 UsbPciCmdSmi:1; + UINT32 UsbPciBarSmi:1; + }; +} XHCI_LEGCTLSTS; + +typedef struct { + XHCI_LEGSUP LegSup; + XHCI_LEGCTLSTS LegCtlSts; +} XHCI_EXT_LEG_CAP; + +typedef struct { + struct { + UINT32 CapId:8; + UINT32 NextCapPtr:8; + UINT32 MinorRev:8; + UINT32 MajorRev:8; + }; + + UINT32 NameString; + + struct { + UINT32 PortOffset:8; + UINT32 PortCount:8; + UINT32 L1c:1; // L1 Capability + UINT32 Hso:1; // High-speed Only + UINT32 Ihi:1; // Integrated Hub Implemented + UINT32 RsvdZ:13; + }; +} XHCI_EXT_PROTOCOL; + +typedef struct { + UINT32 CapId:8; + UINT32 NextCapPtr:8; + UINT32 DcerstMax:5; + UINT32 RsvdP:11; +} XHCI_DCID; + +typedef struct { + UINT32 RsvdP1:8; + UINT32 DbTarget:8; + UINT32 RsvdP2:16; +} XHCI_DCDB; + +typedef struct { + UINT32 Erstsz:16; + UINT32 RsvdP:16; +} XHCI_DCERSTSZ; + +typedef struct { + UINT64 RsvdP:4; + UINT64 Erstba:60; +} XHCI_DCERSTBA; + +typedef struct { + UINT64 Desi:3; + UINT64 RsvdP:1; + UINT64 Erdp:60; +} XHCI_DCERDP; + +typedef struct { + UINT32 Dcr:1; + UINT32 Lse:1; + UINT32 Hot:1; + UINT32 Hit:1; + UINT32 Drc:1; + UINT32 RsvdP:11; + UINT32 DbMaxBurstSize:8; + UINT32 DeviceAddr:7; + UINT32 Dce:1; +} XHCI_DCCTRL; + +typedef struct { + UINT32 Er:1; + UINT32 Sbr:1; + UINT32 RsvdP:22; + UINT32 DbPortNum:8; +} XHCI_DCST; + +typedef struct { + UINT32 Ccs:1; + UINT32 Ped:1; + UINT32 RsvdZ1:2; + UINT32 Pr:1; + UINT32 Pls:4; + UINT32 RsvdZ2:1; + UINT32 PortSpeed:4; + UINT32 RsvdZ3:3; + UINT32 Csc:1; + UINT32 RsvdZ4:3; + UINT32 Prc:1; + UINT32 Plc:1; + UINT32 Cec:1; + UINT32 RsvdZ5:8; +} XHCI_DCPORTSC; + +typedef struct { + UINT64 RsvdP:4; + UINT64 Dccp:60; +} XHCI_DCCP; + +typedef struct { + UINT32 DbcProtocol:8; + UINT32 RsvdP:8; + UINT32 VendorId:16; +} XHCI_DCDDI1; + +typedef struct { + UINT32 ProductId:16; + UINT32 DeviceRevision:16; +} XHCI_DCDDI2; + +typedef struct { + XHCI_DCID DcId; + XHCI_DCDB DcDb; + XHCI_DCERSTSZ DcErstsz; + UINT32 RsvdZ; + XHCI_DCERSTBA DcErstba; + XHCI_DCERDP DcErdp; + XHCI_DCCTRL DcCtrl; + XHCI_DCST DcSt; + XHCI_DCPORTSC DcPortSc; + UINT32 RsvdP; + XHCI_DCCP DcCp; + XHCI_DCDDI1 DcDdi1; + XHCI_DCDDI2 DcDdi2; +} XHCI_DB_CAP_REGS; + +#pragma pack(pop) + + //(EIP60460)> +#define XHCI_FL100X_VID 0x1b73 +#define XHCI_FL1000_DID 0x1000 +#define XHCI_FL1009_DID 0x1009 + //<(EIP60460) + //(EIP58979+)> +#define XHCI_TUSB73X0_VID 0x104C +#define XHCI_TUSB73X0_DID 0x8241 + //<(EIP58979+) + //(EIP60327+)> +#define XHCI_VL800_VID 0x1106 +#define XHCI_VL800_DID 0x3432 + //<(EIP60327+) +#define XHCI_EJ168A_VID 0x1B6F +#define XHCI_EJ168A_DID 0x7023 + +#define XHCI_AMD_SB900_VID 0x1022 +#define XHCI_AMD_SB900_DID 0x7812 + +#define XHCI_NEC_VID 0x1033 +#define XHCI_NEC_200_DID 0x0194 + +#define XHCI_INTEL_VID 0x8086 + +typedef struct _XHCI_PENDING_POLLING{ + XHCI_NORMAL_XFR_TRB *Trb; + UINT16 TransferredLength; +}XHCI_PENDING_INTERRUPT_TRANSFER; + +typedef struct _USB3_HOST_CONTROLLER { + EFI_HANDLE Controller; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_USB2_HC_PROTOCOL Usb2HcProtocol; + XHCI_HC_CAP_REGS *CapRegs; + XHCI_HC_OP_REGS *OpRegs; + XHCI_HC_RT_REGS *RtRegs; + XHCI_EXT_LEG_CAP *ExtLegCap; + XHCI_EXT_PROTOCOL *Usb2Protocol; + XHCI_EXT_PROTOCOL *Usb3Protocol; + XHCI_DB_CAP_REGS *DbCapRegs; + + UINT16 Vid; + UINT16 Did; + UINT16 HciVersion; + UINT8 MaxSlots; + UINT8 MaxPorts; + UINT16 MaxIntrs; + EFI_USB_HC_STATE HcState; + UINT32 PageSize4K; + UINT8 SBRN; + UINT8 ContextSize; + XHCI_DCBAA *DcbaaPtr; + TRB_RING CmdRing; + TRB_RING EvtRing; + TRB_RING *XfrRings; + UINTN XfrTrbs; + VOID *DeviceContext; + VOID *InputContext; + UINT32 DbOffset; + BOOLEAN Access64; + UINT64 *ScratchBufEntry; + XHCI_PENDING_INTERRUPT_TRANSFER PendingInterruptTransfer[XHCI_MAX_PENDING_INTERRUPT_TRANSFER]; +} USB3_HOST_CONTROLLER; + +#endif + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + |