]> mj.ucw.cz Git - pciutils.git/blob - lib/aix-device.c
libpci: i386-io-windows.h: Do not define __readeflags() for GCC 4.9+
[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_dev *d)
64 {
65   struct pci_access *a = d->access;
66   aix_pci_bus *bp = aix_find_bus(a, d->bus);
67
68   if (bp->bus_fd < 0)
69     {
70       char devbuf[256];
71       int mode = a->writeable ? O_RDWR : O_RDONLY;
72
73       snprintf(devbuf, sizeof (devbuf), "/dev/%s", bp->bus_name);
74       bp->bus_fd = open(devbuf, mode, 0);
75       if (bp->bus_fd < 0)
76         a->error("aix_open_bus: %s open failed", devbuf);
77     }
78
79   return bp->bus_fd;
80 }
81
82 static int
83 aix_bus_number(char *name)
84 {
85   int bus_number;
86   FILE *odmget_pipe;
87   char command[256];
88   char buf[256];
89   char *bp;
90   char *ep;
91
92   snprintf(command, sizeof (command), AIX_ODMGET_CMD, name);
93   odmget_pipe = popen(command, "r");
94   if (odmget_pipe == NULL)
95     {
96       /* popen failed */
97       return -1;
98     }
99
100   if (fgets(buf, sizeof (buf) - 1, odmget_pipe) != NULL)
101     {
102       bp = buf + 1;     /* skip leading double quote */
103       bus_number = strtol(bp, &ep, 0);
104       if (bp == ep)
105         {
106           /* strtol failed */
107           bus_number = -1;
108         }
109     }
110   else
111     {
112       /* first PCI bus_number is not recorded in ODM CuAt; default to 0 */
113       bus_number = 0;
114     }
115
116   (void) pclose(odmget_pipe);
117
118   return bus_number;
119 }
120
121
122 /* Method entries */
123
124 static int
125 aix_detect(struct pci_access *a)
126 {
127   int len;
128   int mode = a->writeable ? W_OK : R_OK;
129   char *command = AIX_LSDEV_CMD;
130   FILE *lsdev_pipe;
131   char buf[256];
132   char *name;
133
134   lsdev_pipe = popen(command, "r");
135   if (lsdev_pipe == NULL)
136     {
137       a->error("aix_config: popen(\"%s\") failed", command);
138     }
139
140   while (fgets(buf, sizeof (buf) - 1, lsdev_pipe) != NULL)
141     {
142       len = strlen(buf);
143       while (buf[len-1] == '\n' || buf[len-1] == '\r')
144           len--;
145       buf[len] = '\0';                          /* clobber the newline */
146
147       name = (char *) pci_malloc(a, len + 1);
148       strcpy(name, buf);
149       pci_buses[pci_bus_count].bus_name = name;
150       pci_buses[pci_bus_count].bus_number = 0;
151       pci_buses[pci_bus_count].bus_fd = -1;
152       if (!pci_bus_count)
153           a->debug("...using %s", name);
154       else
155           a->debug(", %s", name);
156       pci_bus_count++;
157       if (pci_bus_count >= PCI_BUS_MAX)
158           break;
159     }
160
161   (void) pclose(lsdev_pipe);
162
163   return pci_bus_count;
164 }
165
166 static void
167 aix_init(struct pci_access *a)
168 {
169   char *name;
170   int i;
171
172   for (i = 0; i < pci_bus_count; i++)
173     {
174       name = pci_buses[i].bus_name;
175       pci_buses[i].bus_number = aix_bus_number(name);
176     }
177 }
178
179 static void
180 aix_cleanup(struct pci_access *a)
181 {
182   aix_pci_bus *bp;
183
184   while (pci_bus_count-- > 0)
185     {
186       bp = &pci_buses[pci_bus_count];
187       (void) free(bp->bus_name);
188       if (bp->bus_fd >= 0)
189         {
190           (void) close(bp->bus_fd);
191           bp->bus_fd = -1;
192         }
193     }
194 }
195
196 void
197 aix_scan(struct pci_access *a)
198 {
199   int i;
200   int bus_number;
201   byte busmap[256];
202
203   memset(busmap, 0, sizeof(busmap));
204   for (i = 0; i < pci_bus_count; i++)
205     {
206       bus_number = pci_buses[i].bus_number;
207       if (!busmap[bus_number])
208         {
209           pci_generic_scan_bus(a, busmap, bus_number);
210         }
211     }
212 }
213
214 static int
215 aix_read(struct pci_dev *d, int pos, byte *buf, int len)
216 {
217   struct mdio mdio;
218   int fd;
219
220   if (d->domain || pos + len > 256)
221     return 0;
222
223   fd = aix_bus_open(d);
224   mdio.md_addr = (ulong) pos;
225   mdio.md_size = len;
226   mdio.md_incr = MV_BYTE;
227   mdio.md_data = (char *) buf;
228   mdio.md_sla = PCI_DEVFN(d->dev, d->func);
229
230   if (ioctl(fd, MIOPCFGET, &mdio) < 0)
231     d->access->error("aix_read: ioctl(MIOPCFGET) failed");
232
233   return 1;
234 }
235
236 static int
237 aix_write(struct pci_dev *d, int pos, byte *buf, int len)
238 {
239   struct mdio mdio;
240   int fd;
241
242   if (d->domain || pos + len > 256)
243     return 0;
244
245   fd = aix_bus_open(d);
246   mdio.md_addr = (ulong) pos;
247   mdio.md_size = len;
248   mdio.md_incr = MV_BYTE;
249   mdio.md_data = (char *) buf;
250   mdio.md_sla = PCI_DEVFN(d->dev, d->func);
251
252   if (ioctl(fd, MIOPCFPUT, &mdio) < 0)
253     {
254       d->access->error("aix_write: ioctl(MIOPCFPUT) failed");
255     }
256
257   return 1;
258 }
259
260 struct pci_methods pm_aix_device = {
261   "aix-device",
262   "AIX /dev/pci[0-n]",
263   NULL,
264   aix_detect,
265   aix_init,
266   aix_cleanup,
267   aix_scan,
268   pci_generic_fill_info,
269   aix_read,
270   aix_write,
271   NULL,                                 /* read_vpd */
272   NULL,                                 /* dev_init */
273   NULL                                  /* dev_cleanup */
274 };