]> mj.ucw.cz Git - pciutils.git/blob - lib/darwin.c
libpci: i386-io-windows.h: Do not define __readeflags() for GCC 4.9+
[pciutils.git] / lib / darwin.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 = {
198     "darwin",
199     "Darwin",
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 };