source: mainline/uspace/lib/libpci/i386-ports.c@ 2e07f62c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2e07f62c was e5773c6, checked in by Jiri Svoboda <jiri@…>, 16 years ago

Extract common makefile part for apps and servers, use for all apps and most servers.

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