]> mj.ucw.cz Git - pciutils.git/blob - lib/obsd-device.c
lib/i386-ports.c: Define _GNU_SOURCE, it's needed by the Hurd module.
[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   a->method_params[PCI_ACCESS_OBSD_DEVICE] = PCI_PATH_OBSD_DEVICE;
23 }
24
25 static int
26 obsd_detect(struct pci_access *a)
27 {
28   char *name = a->method_params[PCI_ACCESS_OBSD_DEVICE];
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 = a->method_params[PCI_ACCESS_OBSD_DEVICE];
43
44   a->fd = open(name, O_RDWR, 0);
45   if (a->fd < 0)
46     {
47       a->error("obsd_init: %s open failed", name);
48     }
49 }
50
51 static void
52 obsd_cleanup(struct pci_access *a)
53 {
54   close(a->fd);
55 }
56
57 static int
58 obsd_read(struct pci_dev *d, int pos, byte *buf, int len)
59 {
60   struct pci_io pi;
61   union {
62           u_int32_t u32;
63           u_int16_t u16[2];
64           u_int8_t u8[4];
65   } u;
66
67   if (!(len == 1 || len == 2 || len == 4))
68     {
69       return pci_generic_block_read(d, pos, buf, len);
70     }
71
72   if (pos >= 256)
73     return 0;
74
75   pi.pi_sel.pc_bus = d->bus;
76   pi.pi_sel.pc_dev = d->dev;
77   pi.pi_sel.pc_func = d->func;
78
79   pi.pi_reg = pos - (pos % 4);
80   pi.pi_width = 4;
81         
82   if (ioctl(d->access->fd, PCIOCREAD, &pi) < 0) {
83           if (errno == ENXIO) {
84                   pi.pi_data = 0xffffffff;
85           } else {
86                   d->access->error("obsd_read: ioctl(PCIOCREAD) failed");
87           }
88   }
89   u.u32 = pi.pi_data;
90
91   switch (len)
92     {
93     case 1:
94       buf[0] = (u8) u.u8[pos % 4];
95       break;
96     case 2:
97       ((u16 *) buf)[0] = letoh16(u.u16[(pos % 4) / 2]);
98       break;
99     case 4:
100       ((u32 *) buf)[0] = (u32) letoh32(pi.pi_data);
101       break;
102     }
103   return 1;
104 }
105
106 static int
107 obsd_write(struct pci_dev *d, int pos, byte *buf, int len)
108 {
109   struct pci_io pi;
110
111   if (!(len == 1 || len == 2 || len == 4))
112     {
113       return pci_generic_block_write(d, pos, buf, len);
114     }
115
116   if (pos >= 256)
117     return 0;
118
119   pi.pi_sel.pc_bus = d->bus;
120   pi.pi_sel.pc_dev = d->dev;
121   pi.pi_sel.pc_func = d->func;
122
123   pi.pi_reg = pos;
124   pi.pi_width = len;
125         
126   switch (len)
127     {
128     case 1:
129       pi.pi_data = buf[0];
130       break;
131     case 2:
132       pi.pi_data = ((u16 *) buf)[0];
133       break;
134     case 4:
135       pi.pi_data = ((u32 *) buf)[0];
136       break;
137     }
138   
139   if (ioctl(d->access->fd, PCIOCWRITE, &pi) < 0)
140     {
141       d->access->error("obsd_write: ioctl(PCIOCWRITE) failed");
142     }
143
144   return 1;
145 }
146
147 struct pci_methods pm_obsd_device = {
148   "OpenBSD-device",
149   obsd_config,
150   obsd_detect,
151   obsd_init,
152   obsd_cleanup,
153   pci_generic_scan,
154   pci_generic_fill_info,
155   obsd_read,
156   obsd_write,
157   NULL,                                 /* dev_init */
158   NULL                                  /* dev_cleanup */
159 };