| /* |
| * The PCI Library -- Darwin kIOACPI access |
| * |
| * Copyright (c) 2013 Apple, Inc. |
| * |
| * Can be freely distributed and used under the terms of the GNU GPL. |
| */ |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <stdint.h> |
| |
| #include "internal.h" |
| |
| #include <mach/mach_error.h> |
| #include <CoreFoundation/CoreFoundation.h> |
| #include <IOKit/IOKitLib.h> |
| #include <IOKit/IOKitKeys.h> |
| |
| enum { |
| kACPIMethodAddressSpaceRead = 0, |
| kACPIMethodAddressSpaceWrite = 1, |
| kACPIMethodDebuggerCommand = 2, |
| kACPIMethodCount |
| }; |
| |
| #pragma pack(1) |
| |
| typedef UInt32 IOACPIAddressSpaceID; |
| |
| enum { |
| kIOACPIAddressSpaceIDSystemMemory = 0, |
| kIOACPIAddressSpaceIDSystemIO = 1, |
| kIOACPIAddressSpaceIDPCIConfiguration = 2, |
| kIOACPIAddressSpaceIDEmbeddedController = 3, |
| kIOACPIAddressSpaceIDSMBus = 4 |
| }; |
| |
| /* |
| * 64-bit ACPI address |
| */ |
| union IOACPIAddress { |
| UInt64 addr64; |
| struct { |
| unsigned int offset :16; |
| unsigned int function :3; |
| unsigned int device :5; |
| unsigned int bus :8; |
| unsigned int segment :16; |
| unsigned int reserved :16; |
| } pci; |
| }; |
| typedef union IOACPIAddress IOACPIAddress; |
| |
| #pragma pack() |
| |
| struct AddressSpaceParam { |
| UInt64 value; |
| UInt32 spaceID; |
| IOACPIAddress address; |
| UInt32 bitWidth; |
| UInt32 bitOffset; |
| UInt32 options; |
| }; |
| typedef struct AddressSpaceParam AddressSpaceParam; |
| |
| static void |
| darwin_config(struct pci_access *a UNUSED) |
| { |
| } |
| |
| static int |
| darwin_detect(struct pci_access *a) |
| { |
| io_registry_entry_t service; |
| io_connect_t connect; |
| kern_return_t status; |
| |
| service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleACPIPlatformExpert")); |
| if (service) |
| { |
| status = IOServiceOpen(service, mach_task_self(), 0, &connect); |
| IOObjectRelease(service); |
| } |
| |
| if (!service || (kIOReturnSuccess != status)) |
| { |
| a->warning("Cannot open AppleACPIPlatformExpert (add boot arg debug=0x144 & run as root)"); |
| return 0; |
| } |
| a->debug("...using AppleACPIPlatformExpert"); |
| a->fd = connect; |
| return 1; |
| } |
| |
| static void |
| darwin_init(struct pci_access *a UNUSED) |
| { |
| } |
| |
| static void |
| darwin_cleanup(struct pci_access *a UNUSED) |
| { |
| } |
| |
| static int |
| darwin_read(struct pci_dev *d, int pos, byte *buf, int len) |
| { |
| if (!(len == 1 || len == 2 || len == 4)) |
| return pci_generic_block_read(d, pos, buf, len); |
| |
| AddressSpaceParam param; |
| kern_return_t status; |
| |
| param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration; |
| param.bitWidth = len * 8; |
| param.bitOffset = 0; |
| param.options = 0; |
| |
| param.address.pci.offset = pos; |
| param.address.pci.function = d->func; |
| param.address.pci.device = d->dev; |
| param.address.pci.bus = d->bus; |
| param.address.pci.segment = d->domain; |
| param.address.pci.reserved = 0; |
| param.value = -1ULL; |
| |
| size_t outSize = sizeof(param); |
| status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceRead, |
| ¶m, sizeof(param), |
| ¶m, &outSize); |
| if ((kIOReturnSuccess != status)) |
| d->access->error("darwin_read: kACPIMethodAddressSpaceRead failed: %s", mach_error_string(status)); |
| |
| switch (len) |
| { |
| case 1: |
| buf[0] = (u8) param.value; |
| break; |
| case 2: |
| ((u16 *) buf)[0] = cpu_to_le16((u16) param.value); |
| break; |
| case 4: |
| ((u32 *) buf)[0] = cpu_to_le32((u32) param.value); |
| break; |
| } |
| return 1; |
| } |
| |
| static int |
| darwin_write(struct pci_dev *d, int pos, byte *buf, int len) |
| { |
| if (!(len == 1 || len == 2 || len == 4)) |
| return pci_generic_block_write(d, pos, buf, len); |
| |
| AddressSpaceParam param; |
| kern_return_t status; |
| |
| param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration; |
| param.bitWidth = len * 8; |
| param.bitOffset = 0; |
| param.options = 0; |
| |
| param.address.pci.offset = pos; |
| param.address.pci.function = d->func; |
| param.address.pci.device = d->dev; |
| param.address.pci.bus = d->bus; |
| param.address.pci.segment = d->domain; |
| param.address.pci.reserved = 0; |
| |
| switch (len) |
| { |
| case 1: |
| param.value = buf[0]; |
| break; |
| case 2: |
| param.value = le16_to_cpu(((u16 *) buf)[0]); |
| break; |
| case 4: |
| param.value = le32_to_cpu(((u32 *) buf)[0]); |
| break; |
| } |
| |
| size_t outSize = 0; |
| status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceWrite, |
| ¶m, sizeof(param), |
| NULL, &outSize); |
| if ((kIOReturnSuccess != status)) |
| d->access->error("darwin_read: kACPIMethodAddressSpaceWrite failed: %s", mach_error_string(status)); |
| |
| return 1; |
| } |
| |
| struct pci_methods pm_darwin = { |
| "darwin", |
| "Darwin", |
| darwin_config, |
| darwin_detect, |
| darwin_init, |
| darwin_cleanup, |
| pci_generic_scan, |
| pci_generic_fill_info, |
| darwin_read, |
| darwin_write, |
| NULL, /* read_vpd */ |
| NULL, /* dev_init */ |
| NULL /* dev_cleanup */ |
| }; |