File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pciutils / lib / i386-ports.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:18:43 2012 UTC (13 years, 1 month ago) by misho
Branches: pciutils, MAIN
CVS tags: v3_1_9, HEAD
pciutils

    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>