source: mainline/uspace/app/lspci/libpci/i386-ports.c@ 92413de

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 92413de was cb0ea39, checked in by Lenka Trochtova <trochtova.lenka@…>, 16 years ago

dd: initial import of the original svn branch

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