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