]> git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/darwin-device.c
e34c423712a7472cfa637bdb63ef6bbf9efc1a1e
[thirdparty/pciutils.git] / lib / darwin-device.c
1 /*
2 * The PCI Library -- Darwin kIOACPI access
3 *
4 * Copyright (c) 2013 Apple, Inc.
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdint.h>
15
16 #include "internal.h"
17
18 #include <mach/mach_error.h>
19 #include <CoreFoundation/CoreFoundation.h>
20 #include <IOKit/IOKitLib.h>
21 #include <IOKit/IOKitKeys.h>
22
23 enum {
24 kACPIMethodAddressSpaceRead = 0,
25 kACPIMethodAddressSpaceWrite = 1,
26 kACPIMethodDebuggerCommand = 2,
27 kACPIMethodCount
28 };
29
30 #pragma pack(1)
31
32 typedef UInt32 IOACPIAddressSpaceID;
33
34 enum {
35 kIOACPIAddressSpaceIDSystemMemory = 0,
36 kIOACPIAddressSpaceIDSystemIO = 1,
37 kIOACPIAddressSpaceIDPCIConfiguration = 2,
38 kIOACPIAddressSpaceIDEmbeddedController = 3,
39 kIOACPIAddressSpaceIDSMBus = 4
40 };
41
42 /*
43 * 64-bit ACPI address
44 */
45 union IOACPIAddress {
46 UInt64 addr64;
47 struct {
48 unsigned int offset :16;
49 unsigned int function :3;
50 unsigned int device :5;
51 unsigned int bus :8;
52 unsigned int segment :16;
53 unsigned int reserved :16;
54 } pci;
55 };
56 typedef union IOACPIAddress IOACPIAddress;
57
58 #pragma pack()
59
60 struct AddressSpaceParam {
61 UInt64 value;
62 UInt32 spaceID;
63 IOACPIAddress address;
64 UInt32 bitWidth;
65 UInt32 bitOffset;
66 UInt32 options;
67 };
68 typedef struct AddressSpaceParam AddressSpaceParam;
69
70 static void
71 darwin_config(struct pci_access *a UNUSED)
72 {
73 }
74
75 static int
76 darwin_detect(struct pci_access *a)
77 {
78 io_registry_entry_t service;
79 io_connect_t connect;
80 kern_return_t status;
81
82 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleACPIPlatformExpert"));
83 if (service)
84 {
85 status = IOServiceOpen(service, mach_task_self(), 0, &connect);
86 IOObjectRelease(service);
87 }
88
89 if (!service || (kIOReturnSuccess != status))
90 {
91 a->warning("Cannot open AppleACPIPlatformExpert (add boot arg debug=0x144 & run as root)");
92 return 0;
93 }
94 a->debug("...using AppleACPIPlatformExpert");
95 a->fd = connect;
96 return 1;
97 }
98
99 static void
100 darwin_init(struct pci_access *a UNUSED)
101 {
102 }
103
104 static void
105 darwin_cleanup(struct pci_access *a UNUSED)
106 {
107 }
108
109 static int
110 darwin_read(struct pci_dev *d, int pos, byte *buf, int len)
111 {
112 if (!(len == 1 || len == 2 || len == 4))
113 return pci_generic_block_read(d, pos, buf, len);
114
115 AddressSpaceParam param;
116 kern_return_t status;
117
118 param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration;
119 param.bitWidth = len * 8;
120 param.bitOffset = 0;
121 param.options = 0;
122
123 param.address.pci.offset = pos;
124 param.address.pci.function = d->func;
125 param.address.pci.device = d->dev;
126 param.address.pci.bus = d->bus;
127 param.address.pci.segment = d->domain;
128 param.address.pci.reserved = 0;
129 param.value = -1ULL;
130
131 size_t outSize = sizeof(param);
132 status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceRead,
133 &param, sizeof(param),
134 &param, &outSize);
135 if ((kIOReturnSuccess != status))
136 d->access->error("darwin_read: kACPIMethodAddressSpaceRead failed: %s", mach_error_string(status));
137
138 switch (len)
139 {
140 case 1:
141 buf[0] = (u8) param.value;
142 break;
143 case 2:
144 ((u16 *) buf)[0] = cpu_to_le16((u16) param.value);
145 break;
146 case 4:
147 ((u32 *) buf)[0] = cpu_to_le32((u32) param.value);
148 break;
149 }
150 return 1;
151 }
152
153 static int
154 darwin_write(struct pci_dev *d, int pos, byte *buf, int len)
155 {
156 if (!(len == 1 || len == 2 || len == 4))
157 return pci_generic_block_write(d, pos, buf, len);
158
159 AddressSpaceParam param;
160 kern_return_t status;
161
162 param.spaceID = kIOACPIAddressSpaceIDPCIConfiguration;
163 param.bitWidth = len * 8;
164 param.bitOffset = 0;
165 param.options = 0;
166
167 param.address.pci.offset = pos;
168 param.address.pci.function = d->func;
169 param.address.pci.device = d->dev;
170 param.address.pci.bus = d->bus;
171 param.address.pci.segment = d->domain;
172 param.address.pci.reserved = 0;
173
174 switch (len)
175 {
176 case 1:
177 param.value = buf[0];
178 break;
179 case 2:
180 param.value = le16_to_cpu(((u16 *) buf)[0]);
181 break;
182 case 4:
183 param.value = le32_to_cpu(((u32 *) buf)[0]);
184 break;
185 }
186
187 size_t outSize = 0;
188 status = IOConnectCallStructMethod(d->access->fd, kACPIMethodAddressSpaceWrite,
189 &param, sizeof(param),
190 NULL, &outSize);
191 if ((kIOReturnSuccess != status))
192 d->access->error("darwin_read: kACPIMethodAddressSpaceWrite failed: %s", mach_error_string(status));
193
194 return 1;
195 }
196
197 struct pci_methods pm_darwin_device = {
198 "darwin-device",
199 "Darwin device",
200 darwin_config,
201 darwin_detect,
202 darwin_init,
203 darwin_cleanup,
204 pci_generic_scan,
205 pci_generic_fill_info,
206 darwin_read,
207 darwin_write,
208 NULL, /* read_vpd */
209 NULL, /* dev_init */
210 NULL /* dev_cleanup */
211 };