]> mj.ucw.cz Git - pciutils.git/blob - lib/i386-ports.c
Added support for GNU Hurd
[pciutils.git] / lib / i386-ports.c
1 /*
2  *      The PCI Library -- Direct Configuration access via i386 Ports
3  *
4  *      Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <unistd.h>
10
11 #ifdef __GLIBC__
12 #include <sys/io.h>
13 #else
14 #include <asm/io.h>
15 #endif
16
17 #include "internal.h"
18
19 #ifdef OS_LINUX
20 static int intel_iopl_set = -1;
21
22 static int
23 intel_setup_io(void)
24 {
25   if (intel_iopl_set < 0)
26     intel_iopl_set = (iopl(3) < 0) ? 0 : 1;
27   return intel_iopl_set;
28 }
29
30 static inline void
31 intel_cleanup_io(void)
32 {
33   if (intel_iopl_set > 0)
34     iopl(3);
35   intel_iopl_set = -1;
36 }
37 #endif
38
39 #ifdef OS_GNU
40 /* The GNU Hurd doesn't have an iopl() call */
41
42 static inline int
43 intel_setup_io(void)
44 {
45   return 1;
46 }
47
48 static inline int
49 intel_cleanup_io(void)
50 {
51 }
52 #endif
53
54 static void
55 conf12_init(struct pci_access *a)
56 {
57   if (!intel_setup_io())
58     a->error("You need to be root to have access to I/O ports.");
59 }
60
61 static void
62 conf12_cleanup(struct pci_access *a UNUSED)
63 {
64   intel_cleanup_io();
65 }
66
67 /*
68  * Before we decide to use direct hardware access mechanisms, we try to do some
69  * trivial checks to ensure it at least _seems_ to be working -- we just test
70  * whether bus 00 contains a host bridge (this is similar to checking
71  * techniques used in XFree86, but ours should be more reliable since we
72  * attempt to make use of direct access hints provided by the PCI BIOS).
73  *
74  * This should be close to trivial, but it isn't, because there are buggy
75  * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
76  */
77
78 static int
79 intel_sanity_check(struct pci_access *a, struct pci_methods *m)
80 {
81   struct pci_dev d;
82
83   a->debug("...sanity check");
84   d.bus = 0;
85   d.func = 0;
86   for(d.dev = 0; d.dev < 32; d.dev++)
87     {
88       u16 class, vendor;
89       if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
90           (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) ||
91           m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
92           (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))
93         {
94           a->debug("...outside the Asylum at 0/%02x/0", d.dev);
95           return 1;
96         }
97     }
98   a->debug("...insane");
99   return 0;
100 }
101
102 /*
103  *      Configuration type 1
104  */
105
106 #define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
107
108 static int
109 conf1_detect(struct pci_access *a)
110 {
111   unsigned int tmp;
112   int res = 0;
113
114   if (!intel_setup_io())
115     {
116       a->debug("...no I/O permission");
117       return 0;
118     }
119   outb (0x01, 0xCFB);
120   tmp = inl (0xCF8);
121   outl (0x80000000, 0xCF8);
122   if (inl (0xCF8) == 0x80000000)
123     res = 1;
124   outl (tmp, 0xCF8);
125   if (res)
126     res = intel_sanity_check(a, &pm_intel_conf1);
127   return res;
128 }
129
130 static int
131 conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
132 {
133   int addr = 0xcfc + (pos&3);
134   outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
135
136   switch (len)
137     {
138     case 1:
139       buf[0] = inb(addr);
140       break;
141     case 2:
142       ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
143       break;
144     case 4:
145       ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
146       break;
147     default:
148       return pci_generic_block_read(d, pos, buf, len);
149     }
150   return 1;
151 }
152
153 static int
154 conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
155 {
156   int addr = 0xcfc + (pos&3);
157   outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
158
159   switch (len)
160     {
161     case 1:
162       outb(buf[0], addr);
163       break;
164     case 2:
165       outw(le16_to_cpu(((u16 *) buf)[0]), addr);
166       break;
167     case 4:
168       outl(le32_to_cpu(((u32 *) buf)[0]), addr);
169       break;
170     default:
171       return pci_generic_block_write(d, pos, buf, len);
172     }
173   return 1;
174 }
175
176 /*
177  *      Configuration type 2. Obsolete and brain-damaged, but existing.
178  */
179
180 static int
181 conf2_detect(struct pci_access *a)
182 {
183   if (!intel_setup_io())
184     {
185       a->debug("...no I/O permission");
186       return 0;
187     }
188
189   /* This is ugly and tends to produce false positives. Beware. */
190
191   outb(0x00, 0xCFB);
192   outb(0x00, 0xCF8);
193   outb(0x00, 0xCFA);
194   if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
195     return intel_sanity_check(a, &pm_intel_conf2);
196   else
197     return 0;
198 }
199
200 static int
201 conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
202 {
203   int addr = 0xc000 | (d->dev << 8) | pos;
204
205   if (d->dev >= 16)
206     /* conf2 supports only 16 devices per bus */
207     return 0;
208   outb((d->func << 1) | 0xf0, 0xcf8);
209   outb(d->bus, 0xcfa);
210   switch (len)
211     {
212     case 1:
213       buf[0] = inb(addr);
214       break;
215     case 2:
216       ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
217       break;
218     case 4:
219       ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
220       break;
221     default:
222       outb(0, 0xcf8);
223       return pci_generic_block_read(d, pos, buf, len);
224     }
225   outb(0, 0xcf8);
226   return 1;
227 }
228
229 static int
230 conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
231 {
232   int addr = 0xc000 | (d->dev << 8) | pos;
233
234   if (d->dev >= 16)
235     d->access->error("conf2_write: only first 16 devices exist.");
236   outb((d->func << 1) | 0xf0, 0xcf8);
237   outb(d->bus, 0xcfa);
238   switch (len)
239     {
240     case 1:
241       outb(buf[0], addr);
242       break;
243     case 2:
244       outw(le16_to_cpu(* (u16 *) buf), addr);
245       break;
246     case 4:
247       outl(le32_to_cpu(* (u32 *) buf), addr);
248       break;
249     default:
250       outb(0, 0xcf8);
251       return pci_generic_block_write(d, pos, buf, len);
252     }
253   outb(0, 0xcf8);
254   return 1;
255 }
256
257 struct pci_methods pm_intel_conf1 = {
258   "Intel-conf1",
259   NULL,                                 /* config */
260   conf1_detect,
261   conf12_init,
262   conf12_cleanup,
263   pci_generic_scan,
264   pci_generic_fill_info,
265   conf1_read,
266   conf1_write,
267   NULL,                                 /* init_dev */
268   NULL                                  /* cleanup_dev */
269 };
270
271 struct pci_methods pm_intel_conf2 = {
272   "Intel-conf2",
273   NULL,                                 /* config */
274   conf2_detect,
275   conf12_init,
276   conf12_cleanup,
277   pci_generic_scan,
278   pci_generic_fill_info,
279   conf2_read,
280   conf2_write,
281   NULL,                                 /* init_dev */
282   NULL                                  /* cleanup_dev */
283 };