]> mj.ucw.cz Git - pciutils.git/blob - lib/aix-device.c
Import initial Darwin Support from Apple
[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 };