Annotation of embedaddon/pciutils/lib/i386-ports.c, revision 1.1
1.1 ! misho 1: /*
! 2: * The PCI Library -- Direct Configuration access via i386 Ports
! 3: *
! 4: * Copyright (c) 1997--2006 Martin Mares <mj@ucw.cz>
! 5: *
! 6: * Can be freely distributed and used under the terms of the GNU GPL.
! 7: */
! 8:
! 9: #define _GNU_SOURCE
! 10:
! 11: #include "internal.h"
! 12:
! 13: #include <unistd.h>
! 14:
! 15: #if defined(PCI_OS_LINUX)
! 16: #include "i386-io-linux.h"
! 17: #elif defined(PCI_OS_GNU)
! 18: #include "i386-io-hurd.h"
! 19: #elif defined(PCI_OS_SUNOS)
! 20: #include "i386-io-sunos.h"
! 21: #elif defined(PCI_OS_WINDOWS)
! 22: #include "i386-io-windows.h"
! 23: #elif defined(PCI_OS_CYGWIN)
! 24: #include "i386-io-cygwin.h"
! 25: #elif defined(PCI_OS_HAIKU)
! 26: #include "i386-io-haiku.h"
! 27: #elif defined(PCI_OS_BEOS)
! 28: #include "i386-io-beos.h"
! 29: #else
! 30: #error Do not know how to access I/O ports on this OS.
! 31: #endif
! 32:
! 33: static int conf12_io_enabled = -1; /* -1=haven't tried, 0=failed, 1=succeeded */
! 34:
! 35: static int
! 36: conf12_setup_io(struct pci_access *a)
! 37: {
! 38: if (conf12_io_enabled < 0)
! 39: conf12_io_enabled = intel_setup_io(a);
! 40: return conf12_io_enabled;
! 41: }
! 42:
! 43: static void
! 44: conf12_init(struct pci_access *a)
! 45: {
! 46: if (!conf12_setup_io(a))
! 47: a->error("No permission to access I/O ports (you probably have to be root).");
! 48: }
! 49:
! 50: static void
! 51: conf12_cleanup(struct pci_access *a UNUSED)
! 52: {
! 53: if (conf12_io_enabled > 0)
! 54: conf12_io_enabled = intel_cleanup_io(a);
! 55: }
! 56:
! 57: /*
! 58: * Before we decide to use direct hardware access mechanisms, we try to do some
! 59: * trivial checks to ensure it at least _seems_ to be working -- we just test
! 60: * whether bus 00 contains a host bridge (this is similar to checking
! 61: * techniques used in XFree86, but ours should be more reliable since we
! 62: * attempt to make use of direct access hints provided by the PCI BIOS).
! 63: *
! 64: * This should be close to trivial, but it isn't, because there are buggy
! 65: * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
! 66: */
! 67:
! 68: static int
! 69: intel_sanity_check(struct pci_access *a, struct pci_methods *m)
! 70: {
! 71: struct pci_dev d;
! 72:
! 73: a->debug("...sanity check");
! 74: d.bus = 0;
! 75: d.func = 0;
! 76: for (d.dev = 0; d.dev < 32; d.dev++)
! 77: {
! 78: u16 class, vendor;
! 79: if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
! 80: (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) ||
! 81: m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
! 82: (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))
! 83: {
! 84: a->debug("...outside the Asylum at 0/%02x/0", d.dev);
! 85: return 1;
! 86: }
! 87: }
! 88: a->debug("...insane");
! 89: return 0;
! 90: }
! 91:
! 92: /*
! 93: * Configuration type 1
! 94: */
! 95:
! 96: #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
! 97:
! 98: static int
! 99: conf1_detect(struct pci_access *a)
! 100: {
! 101: unsigned int tmp;
! 102: int res = 0;
! 103:
! 104: if (!conf12_setup_io(a))
! 105: {
! 106: a->debug("...no I/O permission");
! 107: return 0;
! 108: }
! 109: outb (0x01, 0xCFB);
! 110: tmp = inl (0xCF8);
! 111: outl (0x80000000, 0xCF8);
! 112: if (inl (0xCF8) == 0x80000000)
! 113: res = 1;
! 114: outl (tmp, 0xCF8);
! 115: if (res)
! 116: res = intel_sanity_check(a, &pm_intel_conf1);
! 117: return res;
! 118: }
! 119:
! 120: static int
! 121: 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) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
! 129:
! 130: switch (len)
! 131: {
! 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:
! 147: static int
! 148: conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
! 149: {
! 150: int addr = 0xcfc + (pos&3);
! 151:
! 152: if (pos >= 256)
! 153: return 0;
! 154:
! 155: outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
! 156:
! 157: switch (len)
! 158: {
! 159: case 1:
! 160: outb(buf[0], addr);
! 161: break;
! 162: case 2:
! 163: outw(le16_to_cpu(((u16 *) buf)[0]), addr);
! 164: break;
! 165: case 4:
! 166: outl(le32_to_cpu(((u32 *) buf)[0]), addr);
! 167: break;
! 168: default:
! 169: return pci_generic_block_write(d, pos, buf, len);
! 170: }
! 171: return 1;
! 172: }
! 173:
! 174: /*
! 175: * Configuration type 2. Obsolete and brain-damaged, but existing.
! 176: */
! 177:
! 178: static int
! 179: conf2_detect(struct pci_access *a)
! 180: {
! 181: if (!conf12_setup_io(a))
! 182: {
! 183: a->debug("...no I/O permission");
! 184: return 0;
! 185: }
! 186:
! 187: /* This is ugly and tends to produce false positives. Beware. */
! 188:
! 189: outb(0x00, 0xCFB);
! 190: outb(0x00, 0xCF8);
! 191: outb(0x00, 0xCFA);
! 192: if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
! 193: return intel_sanity_check(a, &pm_intel_conf2);
! 194: else
! 195: return 0;
! 196: }
! 197:
! 198: static int
! 199: conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
! 200: {
! 201: int addr = 0xc000 | (d->dev << 8) | pos;
! 202:
! 203: if (pos >= 256)
! 204: return 0;
! 205:
! 206: if (d->dev >= 16)
! 207: /* conf2 supports only 16 devices per bus */
! 208: return 0;
! 209: outb((d->func << 1) | 0xf0, 0xcf8);
! 210: outb(d->bus, 0xcfa);
! 211: switch (len)
! 212: {
! 213: case 1:
! 214: buf[0] = inb(addr);
! 215: break;
! 216: case 2:
! 217: ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
! 218: break;
! 219: case 4:
! 220: ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
! 221: break;
! 222: default:
! 223: outb(0, 0xcf8);
! 224: return pci_generic_block_read(d, pos, buf, len);
! 225: }
! 226: outb(0, 0xcf8);
! 227: return 1;
! 228: }
! 229:
! 230: static int
! 231: conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
! 232: {
! 233: int addr = 0xc000 | (d->dev << 8) | pos;
! 234:
! 235: if (pos >= 256)
! 236: return 0;
! 237:
! 238: if (d->dev >= 16)
! 239: d->access->error("conf2_write: only first 16 devices exist.");
! 240: outb((d->func << 1) | 0xf0, 0xcf8);
! 241: outb(d->bus, 0xcfa);
! 242: switch (len)
! 243: {
! 244: case 1:
! 245: outb(buf[0], addr);
! 246: break;
! 247: case 2:
! 248: outw(le16_to_cpu(* (u16 *) buf), addr);
! 249: break;
! 250: case 4:
! 251: outl(le32_to_cpu(* (u32 *) buf), addr);
! 252: break;
! 253: default:
! 254: outb(0, 0xcf8);
! 255: return pci_generic_block_write(d, pos, buf, len);
! 256: }
! 257: outb(0, 0xcf8);
! 258: return 1;
! 259: }
! 260:
! 261: struct pci_methods pm_intel_conf1 = {
! 262: "intel-conf1",
! 263: "Raw I/O port access using Intel conf1 interface",
! 264: NULL, /* config */
! 265: conf1_detect,
! 266: conf12_init,
! 267: conf12_cleanup,
! 268: pci_generic_scan,
! 269: pci_generic_fill_info,
! 270: conf1_read,
! 271: conf1_write,
! 272: NULL, /* read_vpd */
! 273: NULL, /* init_dev */
! 274: NULL /* cleanup_dev */
! 275: };
! 276:
! 277: struct pci_methods pm_intel_conf2 = {
! 278: "intel-conf2",
! 279: "Raw I/O port access using Intel conf2 interface",
! 280: NULL, /* config */
! 281: conf2_detect,
! 282: conf12_init,
! 283: conf12_cleanup,
! 284: pci_generic_scan,
! 285: pci_generic_fill_info,
! 286: conf2_read,
! 287: conf2_write,
! 288: NULL, /* read_vpd */
! 289: NULL, /* init_dev */
! 290: NULL /* cleanup_dev */
! 291: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>