]> git.ipfire.org Git - thirdparty/pciutils.git/blob - lib/aix-device.c
Use symbol versioning for our new member of struct pci_dev
[thirdparty/pciutils.git] / lib / aix-device.c
1 /*
2 * The PCI Library -- AIX /dev/pci[0-n] access
3 *
4 * Copyright (c) 1999 Jari Kirma <kirma@cs.hut.fi>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /*
10 * Read functionality of this driver is briefly tested, and seems
11 * to supply basic information correctly, but I promise no more.
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19
20 #include <sys/types.h>
21 #include <sys/mdio.h>
22
23 #include "internal.h"
24
25 #define AIX_LSDEV_CMD "/usr/sbin/lsdev -C -c bus -t pci\\* -S available -F name"
26 #define AIX_ODMGET_CMD \
27 "/usr/bin/odmget -q 'name=%s and attribute=bus_number' CuAt | \
28 /usr/bin/awk '$1 == \"value\" { print $3 }'"
29
30
31 /* AIX PCI bus device information */
32
33 typedef struct aix_pci_bus {
34 char *bus_name;
35 int bus_number;
36 int bus_fd;
37 } aix_pci_bus;
38
39 #define PCI_BUS_MAX 16 /* arbitrary choice */
40 static aix_pci_bus pci_buses[PCI_BUS_MAX];
41 static int pci_bus_count = 0;
42
43
44 /* Utility Routines */
45
46 static aix_pci_bus *
47 aix_find_bus(struct pci_access *a, int bus_number)
48 {
49 int i;
50
51 for (i = 0; i < pci_bus_count; i++)
52 {
53 if (pci_buses[i].bus_number == bus_number)
54 {
55 return &pci_buses[i];
56 }
57 }
58
59 a->error("aix_find_bus: bus number %d not found", bus_number);
60 }
61
62 static int
63 aix_bus_open(struct pci_access *a, int bus_number)
64 {
65 aix_pci_bus *bp = aix_find_bus(a, bus_number);
66
67 if (bp->bus_fd < 0)
68 {
69 char devbuf[256];
70 int mode = a->writeable ? O_RDWR : O_RDONLY;
71
72 snprintf(devbuf, sizeof (devbuf), "/dev/%s", bp->bus_name);
73 bp->bus_fd = open(devbuf, mode, 0);
74 if (bp->bus_fd < 0)
75 {
76 a->error("aix_open_bus: %s open failed", devbuf);
77 }
78 }
79
80 return bp->bus_fd;
81 }
82
83 static int
84 aix_bus_number(char *name)
85 {
86 int bus_number;
87 FILE *odmget_pipe;
88 char command[256];
89 char buf[256];
90 char *bp;
91 char *ep;
92
93 snprintf(command, sizeof (command), AIX_ODMGET_CMD, name);
94 odmget_pipe = popen(command, "r");
95 if (odmget_pipe == NULL)
96 {
97 /* popen failed */
98 return -1;
99 }
100
101 if (fgets(buf, sizeof (buf) - 1, odmget_pipe) != NULL)
102 {
103 bp = buf + 1; /* skip leading double quote */
104 bus_number = strtol(bp, &ep, 0);
105 if (bp == ep)
106 {
107 /* strtol failed */
108 bus_number = -1;
109 }
110 }
111 else
112 {
113 /* first PCI bus_number is not recorded in ODM CuAt; default to 0 */
114 bus_number = 0;
115 }
116
117 (void) pclose(odmget_pipe);
118
119 return bus_number;
120 }
121
122
123 /* Method entries */
124
125 static int
126 aix_detect(struct pci_access *a)
127 {
128 int len;
129 int mode = a->writeable ? W_OK : R_OK;
130 char *command = AIX_LSDEV_CMD;
131 FILE *lsdev_pipe;
132 char buf[256];
133 char *name;
134
135 lsdev_pipe = popen(command, "r");
136 if (lsdev_pipe == NULL)
137 {
138 a->error("aix_config: popen(\"%s\") failed", command);
139 }
140
141 while (fgets(buf, sizeof (buf) - 1, lsdev_pipe) != NULL)
142 {
143 len = strlen(buf);
144 while (buf[len-1] == '\n' || buf[len-1] == '\r')
145 len--;
146 buf[len] = '\0'; /* clobber the newline */
147
148 name = (char *) pci_malloc(a, len + 1);
149 strcpy(name, buf);
150 pci_buses[pci_bus_count].bus_name = name;
151 pci_buses[pci_bus_count].bus_number = 0;
152 pci_buses[pci_bus_count].bus_fd = -1;
153 if (!pci_bus_count)
154 a->debug("...using %s", name);
155 else
156 a->debug(", %s", name);
157 pci_bus_count++;
158 if (pci_bus_count >= PCI_BUS_MAX)
159 break;
160 }
161
162 (void) pclose(lsdev_pipe);
163
164 return pci_bus_count;
165 }
166
167 static void
168 aix_init(struct pci_access *a)
169 {
170 char *name;
171 int i;
172
173 for (i = 0; i < pci_bus_count; i++)
174 {
175 name = pci_buses[i].bus_name;
176 pci_buses[i].bus_number = aix_bus_number(name);
177 }
178 }
179
180 static void
181 aix_cleanup(struct pci_access *a)
182 {
183 aix_pci_bus *bp;
184
185 while (pci_bus_count-- > 0)
186 {
187 bp = &pci_buses[pci_bus_count];
188 (void) free(bp->bus_name);
189 if (bp->bus_fd >= 0)
190 {
191 (void) close(bp->bus_fd);
192 bp->bus_fd = -1;
193 }
194 }
195 }
196
197 void
198 aix_scan(struct pci_access *a)
199 {
200 int i;
201 int bus_number;
202 byte busmap[256];
203
204 memset(busmap, 0, sizeof(busmap));
205 for (i = 0; i < pci_bus_count; i++)
206 {
207 bus_number = pci_buses[i].bus_number;
208 if (!busmap[bus_number])
209 {
210 pci_generic_scan_bus(a, busmap, bus_number);
211 }
212 }
213 }
214
215 static int
216 aix_read(struct pci_dev *d, int pos, byte *buf, int len)
217 {
218 struct mdio mdio;
219 int fd;
220
221 if (pos + len > 256)
222 return 0;
223
224 fd = aix_bus_open(d->access, d->bus);
225 mdio.md_addr = (ulong) pos;
226 mdio.md_size = len;
227 mdio.md_incr = MV_BYTE;
228 mdio.md_data = (char *) buf;
229 mdio.md_sla = PCI_DEVFN(d->dev, d->func);
230
231 if (ioctl(fd, MIOPCFGET, &mdio) < 0)
232 d->access->error("aix_read: ioctl(MIOPCFGET) failed");
233
234 return 1;
235 }
236
237 static int
238 aix_write(struct pci_dev *d, int pos, byte *buf, int len)
239 {
240 struct mdio mdio;
241 int fd;
242
243 if (pos + len > 256)
244 return 0;
245
246 fd = aix_bus_open(d->access, d->bus);
247 mdio.md_addr = (ulong) pos;
248 mdio.md_size = len;
249 mdio.md_incr = MV_BYTE;
250 mdio.md_data = (char *) buf;
251 mdio.md_sla = PCI_DEVFN(d->dev, d->func);
252
253 if (ioctl(fd, MIOPCFPUT, &mdio) < 0)
254 {
255 d->access->error("aix_write: ioctl(MIOPCFPUT) failed");
256 }
257
258 return 1;
259 }
260
261 struct pci_methods pm_aix_device = {
262 "aix-device",
263 "AIX /dev/pci[0-n]",
264 NULL,
265 aix_detect,
266 aix_init,
267 aix_cleanup,
268 aix_scan,
269 pci_generic_fill_info,
270 aix_read,
271 aix_write,
272 NULL, /* read_vpd */
273 NULL, /* dev_init */
274 NULL /* dev_cleanup */
275 };