source: mainline/uspace/app/lspci/libpci/i386-ports.c@ 24f27bb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 24f27bb 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
RevLine 
[4a7c273]1/*
2 * The PCI Library -- Direct Configuration access via i386 Ports
3 *
4 * Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
5 *
[8071af9f]6 * May 8, 2006 - Modified and ported to HelenOS by Jakub Jermar.
[4a7c273]7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
11#include <unistd.h>
[cb0ea39]12#include <ddi.h>
13#include <libarch/ddi.h>
[4a7c273]14
15#include "internal.h"
16
[cb0ea39]17#define PCI_CONF1 0xcf8
18#define PCI_CONF1_SIZE 8
[20a9b85]19
[4a7c273]20
[20a9b85]21static void conf12_init(struct pci_access *a)
[cb0ea39]22{
[4a7c273]23}
24
[20a9b85]25static void conf12_cleanup(struct pci_access *a UNUSED)
[4a7c273]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
[20a9b85]40static int intel_sanity_check(struct pci_access *a, struct pci_methods *m)
[4a7c273]41{
[20a9b85]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;
[cb0ea39]49 if (m->read(&d, PCI_CLASS_DEVICE, (byte *) & class,
[20a9b85]50 sizeof(class))
51 && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST)
[cb0ea39]52 || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA))
53 || m->read(&d, PCI_VENDOR_ID, (byte *) & vendor,
[20a9b85]54 sizeof(vendor))
55 && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL)
[cb0ea39]56 || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) {
[20a9b85]57 a->debug("...outside the Asylum at 0/%02x/0",
58 d.dev);
59 return 1;
60 }
[4a7c273]61 }
[20a9b85]62 a->debug("...insane");
63 return 0;
[4a7c273]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
[20a9b85]72static int conf1_detect(struct pci_access *a)
[4a7c273]73{
[20a9b85]74 unsigned int tmp;
75 int res = 0;
[cb0ea39]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 }
[20a9b85]84
[cb0ea39]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) {
[20a9b85]89 res = 1;
[cb0ea39]90 }
91 pio_write_32(0xCF8, tmp);
92 if (res) {
[20a9b85]93 res = intel_sanity_check(a, &pm_intel_conf1);
[cb0ea39]94 }
[20a9b85]95 return res;
[4a7c273]96}
97
[20a9b85]98static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len)
[4a7c273]99{
[20a9b85]100 int addr = 0xcfc + (pos & 3);
101
102 if (pos >= 256)
103 return 0;
104
[cb0ea39]105 pio_write_32(0xcf8, 0x80000000 | ((d->bus & 0xff) << 16) |
106 (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3));
[20a9b85]107
108 switch (len) {
109 case 1:
[cb0ea39]110 buf[0] = pio_read_8(addr);
[20a9b85]111 break;
112 case 2:
[cb0ea39]113 ((u16 *) buf)[0] = cpu_to_le16(pio_read_16(addr));
[20a9b85]114 break;
115 case 4:
[cb0ea39]116 ((u32 *) buf)[0] = cpu_to_le32(pio_read_32(addr));
[20a9b85]117 break;
118 default:
119 return pci_generic_block_read(d, pos, buf, len);
120 }
121 return 1;
[4a7c273]122}
123
[20a9b85]124static int conf1_write(struct pci_dev *d, int pos, byte * buf, int len)
[4a7c273]125{
[20a9b85]126 int addr = 0xcfc + (pos & 3);
127
128 if (pos >= 256)
129 return 0;
130
[cb0ea39]131 pio_write_32(0xcf8, 0x80000000 | ((d->bus & 0xff) << 16) |
132 (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3));
[20a9b85]133
134 switch (len) {
135 case 1:
[cb0ea39]136 pio_write_8(addr, buf[0]);
[20a9b85]137 break;
138 case 2:
[cb0ea39]139 pio_write_16(addr, le16_to_cpu(((u16 *) buf)[0]));
[20a9b85]140 break;
141 case 4:
[cb0ea39]142 pio_write_32(addr, le32_to_cpu(((u32 *) buf)[0]));
[20a9b85]143 break;
144 default:
145 return pci_generic_block_write(d, pos, buf, len);
146 }
147 return 1;
[4a7c273]148}
149
150/*
151 * Configuration type 2. Obsolete and brain-damaged, but existing.
152 */
153
[20a9b85]154static int conf2_detect(struct pci_access *a)
[4a7c273]155{
[cb0ea39]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
[20a9b85]167 /* This is ugly and tends to produce false positives. Beware. */
[cb0ea39]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)
[20a9b85]172 return intel_sanity_check(a, &pm_intel_conf2);
173 else
174 return 0;
[4a7c273]175}
176
[20a9b85]177static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len)
[4a7c273]178{
[20a9b85]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;
[cb0ea39]187 pio_write_8(0xcf8, (d->func << 1) | 0xf0);
188 pio_write_8(0xcfa, d->bus);
[20a9b85]189 switch (len) {
190 case 1:
[cb0ea39]191 buf[0] = pio_read_8(addr);
[20a9b85]192 break;
193 case 2:
[cb0ea39]194 ((u16 *) buf)[0] = cpu_to_le16(pio_read_16(addr));
[20a9b85]195 break;
196 case 4:
[cb0ea39]197 ((u32 *) buf)[0] = cpu_to_le32(pio_read_32(addr));
[20a9b85]198 break;
199 default:
[cb0ea39]200 pio_write_8(0xcf8, 0);
[20a9b85]201 return pci_generic_block_read(d, pos, buf, len);
202 }
[cb0ea39]203 pio_write_8(0xcf8, 0);
[20a9b85]204 return 1;
[4a7c273]205}
206
[20a9b85]207static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len)
[4a7c273]208{
[20a9b85]209 int addr = 0xc000 | (d->dev << 8) | pos;
210
211 if (pos >= 256)
212 return 0;
213
214 if (d->dev >= 16)
[46ec2c06]215 d->access->error("conf2_write: only first 16 devices exist.");
[cb0ea39]216 pio_write_8(0xcf8, (d->func << 1) | 0xf0);
217 pio_write_8(0xcfa, d->bus);
[20a9b85]218 switch (len) {
219 case 1:
[cb0ea39]220 pio_write_8(addr, buf[0]);
[20a9b85]221 break;
222 case 2:
[cb0ea39]223 pio_write_16(addr, le16_to_cpu(*(u16 *) buf));
[20a9b85]224 break;
225 case 4:
[cb0ea39]226 pio_write_32(addr, le32_to_cpu(*(u32 *) buf));
[20a9b85]227 break;
228 default:
[cb0ea39]229 pio_write_8(0xcf8, 0);
[20a9b85]230 return pci_generic_block_write(d, pos, buf, len);
231 }
[cb0ea39]232 pio_write_8(0xcf8, 0);
[20a9b85]233 return 1;
[4a7c273]234}
235
236struct pci_methods pm_intel_conf1 = {
[20a9b85]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 */
[4a7c273]248};
249
250struct pci_methods pm_intel_conf2 = {
[20a9b85]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 */
[4a7c273]262};
Note: See TracBrowser for help on using the repository browser.