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