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