| #include <efi.h> | 
 | #include <efilib.h> | 
 |  | 
 | /* this example program changes the Reserved Page Route (RPR) bit on ICH10's General | 
 |  * Control And Status Register (GCS) from LPC to PCI.  In practical terms, it routes | 
 |  * outb to port 80h to the PCI bus. */ | 
 |  | 
 | #define GCS_OFFSET_ADDR 0x3410 | 
 | #define GCS_RPR_SHIFT 2 | 
 | #define GCS_RPR_PCI 1 | 
 | #define GCS_RPR_LPC 0 | 
 |  | 
 | #define VENDOR_ID_INTEL 0x8086 | 
 | #define DEVICE_ID_LPCIF 0x3a16 | 
 | #define DEVICE_ID_COUGARPOINT_LPCIF 0x1c56 | 
 |  | 
 | static EFI_HANDLE ImageHandle; | 
 |  | 
 | typedef struct { | 
 | 	uint16_t vendor_id;	/* 00-01 */ | 
 | 	uint16_t device_id;	/* 02-03 */ | 
 | 	char pad[0xEB];		/* 04-EF */ | 
 | 	uint32_t rcba;		/* F0-F3 */ | 
 | 	uint32_t reserved[3];	/* F4-FF */ | 
 | } lpcif_t; | 
 |  | 
 | static inline void set_bit(volatile uint32_t *flag, int bit, int value) | 
 | { | 
 | 	uint32_t val = *flag; | 
 | 	Print(L"current value is 0x%2x\n", val); | 
 |  | 
 | 	if (value) { | 
 | 		val |= (1 << bit); | 
 | 	} else { | 
 | 		val &= ~(1 << bit); | 
 | 	} | 
 | 	Print(L"setting value to 0x%2x\n", val); | 
 | 	*flag = val; | 
 | 	val = *flag; | 
 | 	Print(L"new value is 0x%2x\n", val); | 
 | } | 
 |  | 
 | static inline int configspace_matches_ids(void *config, uint32_t vendor_id, | 
 | 				uint32_t device_id) | 
 | { | 
 | 	uint32_t *cfg = config; | 
 | 	if (cfg[0] == vendor_id && cfg[1] == device_id) | 
 | 		return 1; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int is_device(EFI_PCI_IO *pciio, uint16_t vendor_id, uint16_t device_id) | 
 | { | 
 | 	lpcif_t lpcif; | 
 | 	EFI_STATUS rc; | 
 |  | 
 | 	rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint16, 0, 2, &lpcif); | 
 | 	if (EFI_ERROR(rc)) | 
 | 		return 0; | 
 |  | 
 | 	if (vendor_id == lpcif.vendor_id && device_id == lpcif.device_id) | 
 | 		return 1; | 
 | 	return 0; | 
 | } | 
 |  | 
 | static EFI_STATUS find_pci_device(uint16_t vendor_id, uint16_t device_id, | 
 | 				EFI_PCI_IO **pciio) | 
 | { | 
 | 	EFI_STATUS rc; | 
 | 	EFI_HANDLE *Handles; | 
 | 	UINTN NoHandles; | 
 | 	int i; | 
 |  | 
 | 	if (!pciio) | 
 | 		return EFI_INVALID_PARAMETER; | 
 |  | 
 | 	rc = LibLocateHandle(ByProtocol, &PciIoProtocol, NULL, &NoHandles, | 
 | 			     &Handles); | 
 | 	if (EFI_ERROR(rc)) | 
 | 		return rc; | 
 |  | 
 | 	for (i = 0; i < NoHandles; i++) { | 
 | 		void *pciio_tmp = NULL; | 
 | 		rc = uefi_call_wrapper(BS->OpenProtocol, 6, Handles[i], | 
 | 				    &PciIoProtocol, &pciio_tmp, ImageHandle, | 
 | 				    NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); | 
 | 		if (EFI_ERROR(rc)) | 
 | 			continue; | 
 | 		*pciio = pciio_tmp; | 
 | 		if (!is_device(*pciio, vendor_id, device_id)) { | 
 | 			*pciio = NULL; | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		return EFI_SUCCESS; | 
 | 	} | 
 | 	return EFI_NOT_FOUND; | 
 | } | 
 |  | 
 | EFI_STATUS | 
 | efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab) | 
 | { | 
 | 	InitializeLib(image_handle, systab); | 
 | 	EFI_PCI_IO *pciio = NULL; | 
 | 	lpcif_t lpcif; | 
 | 	EFI_STATUS rc; | 
 | 	struct { | 
 | 		uint16_t vendor; | 
 | 		uint16_t device; | 
 | 	} devices[] = { | 
 | 		{ VENDOR_ID_INTEL, DEVICE_ID_LPCIF }, | 
 | 		{ VENDOR_ID_INTEL, DEVICE_ID_COUGARPOINT_LPCIF }, | 
 | 		{ 0, 0 } | 
 | 	}; | 
 | 	int i; | 
 |  | 
 | 	ImageHandle = image_handle; | 
 | 	for (i = 0; devices[i].vendor != 0; i++) { | 
 | 		rc = find_pci_device(devices[i].vendor, devices[i].device, &pciio); | 
 | 		if (EFI_ERROR(rc)) | 
 | 			continue; | 
 | 	} | 
 |  | 
 | 	if (rc == EFI_NOT_FOUND) { | 
 | 		Print(L"Device not found.\n"); | 
 | 		return rc; | 
 | 	} else if (EFI_ERROR(rc)) { | 
 | 		return rc; | 
 | 	} | 
 |  | 
 | 	rc = uefi_call_wrapper(pciio->Pci.Read, 5, pciio, EfiPciIoWidthUint32, | 
 | 		EFI_FIELD_OFFSET(lpcif_t, rcba), 1, &lpcif.rcba); | 
 | 	if (EFI_ERROR(rc)) | 
 | 		return rc; | 
 | 	if (!(lpcif.rcba & 1)) { | 
 | 		Print(L"rcrb is not mapped, cannot route port 80h\n"); | 
 | 		return EFI_UNSUPPORTED; | 
 | 	} | 
 | 	lpcif.rcba &= ~1UL; | 
 |  | 
 | 	Print(L"rcba: 0x%8x\n", lpcif.rcba, lpcif.rcba); | 
 | 	set_bit((uint32_t *)(uint64_t)(lpcif.rcba + GCS_OFFSET_ADDR), | 
 | 		     GCS_RPR_SHIFT, GCS_RPR_PCI); | 
 |  | 
 | 	return EFI_SUCCESS; | 
 | } |