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>