]> mj.ucw.cz Git - pciutils.git/blob - lib/obsd-device.c
lspci: Decode PCIe Link Capabilities 2, expand Link Status 2
[pciutils.git] / lib / obsd-device.c
1 /*
2  *      The PCI Library -- OpenBSD /dev/pci access
3  *
4  *      Adapted from fbsd-device.c by Matthieu Herrb <matthieu.herrb@laas.fr>, 2006
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <fcntl.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <sys/endian.h>
14 #include <sys/types.h>
15 #include <sys/ioctl.h>
16 #include <sys/pciio.h>
17 #include "internal.h"
18
19 static void
20 obsd_config(struct pci_access *a)
21 {
22   pci_define_param(a, "obsd.path", PCI_PATH_OBSD_DEVICE, "Path to the OpenBSD PCI device");
23 }
24
25 static int
26 obsd_detect(struct pci_access *a)
27 {
28   char *name = pci_get_param(a, "obsd.path");
29
30   if (access(name, R_OK))
31     {
32       a->warning("Cannot open %s", name);
33       return 0;
34     }
35   a->debug("...using %s", name);
36   return 1;
37 }
38
39 static void
40 obsd_init(struct pci_access *a)
41 {
42   char *name = pci_get_param(a, "obsd.path");
43
44   a->fd = open(name, O_RDWR, 0);
45   if (a->fd < 0)
46     a->error("obsd_init: %s open failed", name);
47 }
48
49 static void
50 obsd_cleanup(struct pci_access *a)
51 {
52   close(a->fd);
53 }
54
55 static int
56 obsd_read(struct pci_dev *d, int pos, byte *buf, int len)
57 {
58   struct pci_io pi;
59   union {
60           u_int32_t u32;
61           u_int16_t u16[2];
62           u_int8_t u8[4];
63   } u;
64
65   if (!(len == 1 || len == 2 || len == 4))
66     return pci_generic_block_read(d, pos, buf, len);
67
68   if (pos >= 256)
69     return 0;
70
71   pi.pi_sel.pc_bus = d->bus;
72   pi.pi_sel.pc_dev = d->dev;
73   pi.pi_sel.pc_func = d->func;
74
75   pi.pi_reg = pos - (pos % 4);
76   pi.pi_width = 4;
77
78   if (ioctl(d->access->fd, PCIOCREAD, &pi) < 0) {
79           if (errno == ENXIO)
80                   pi.pi_data = 0xffffffff;
81           else
82                   d->access->error("obsd_read: ioctl(PCIOCREAD) failed");
83   }
84   u.u32 = pi.pi_data;
85
86   switch (len)
87     {
88     case 1:
89       buf[0] = (u8) u.u8[pos % 4];
90       break;
91     case 2:
92       ((u16 *) buf)[0] = letoh16(u.u16[(pos % 4) / 2]);
93       break;
94     case 4:
95       ((u32 *) buf)[0] = (u32) letoh32(pi.pi_data);
96       break;
97     }
98   return 1;
99 }
100
101 static int
102 obsd_write(struct pci_dev *d, int pos, byte *buf, int len)
103 {
104   struct pci_io pi;
105
106   if (!(len == 1 || len == 2 || len == 4))
107     return pci_generic_block_write(d, pos, buf, len);
108
109   if (pos >= 256)
110     return 0;
111
112   pi.pi_sel.pc_bus = d->bus;
113   pi.pi_sel.pc_dev = d->dev;
114   pi.pi_sel.pc_func = d->func;
115
116   pi.pi_reg = pos;
117   pi.pi_width = len;
118
119   switch (len)
120     {
121     case 1:
122       pi.pi_data = buf[0];
123       break;
124     case 2:
125       pi.pi_data = ((u16 *) buf)[0];
126       break;
127     case 4:
128       pi.pi_data = ((u32 *) buf)[0];
129       break;
130     }
131
132   if (ioctl(d->access->fd, PCIOCWRITE, &pi) < 0)
133     d->access->error("obsd_write: ioctl(PCIOCWRITE) failed");
134
135   return 1;
136 }
137
138 struct pci_methods pm_obsd_device = {
139   "obsd-device",
140   "/dev/pci on OpenBSD",
141   obsd_config,
142   obsd_detect,
143   obsd_init,
144   obsd_cleanup,
145   pci_generic_scan,
146   pci_generic_fill_info,
147   obsd_read,
148   obsd_write,
149   NULL,                                 /* read_vpd */
150   NULL,                                 /* dev_init */
151   NULL                                  /* dev_cleanup */
152 };