Subversion Repositories HelenOS-historic

Rev

Rev 1301 | Rev 1307 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  The PCI Library -- Direct Configuration access via i386 Ports
  3.  *
  4.  *  Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
  5.  *
  6.  *  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.  
  13. #include "internal.h"
  14.  
  15. static inline void outb(u8 b, u16 port)
  16. {
  17.     asm volatile ("outb %0, %1\n" :: "a" (b), "d" (port));
  18. }
  19.  
  20. static inline void outw(u16 w, u16 port)
  21. {
  22.     asm volatile ("outw %0, %1\n" :: "a" (w), "d" (port));
  23. }
  24.  
  25. static inline void outl(u32 l, u16 port)
  26. {
  27.     asm volatile ("outl %0, %1\n" :: "a" (l), "d" (port));
  28. }
  29.  
  30. static inline u8 inb(u16 port)
  31. {
  32.     u8 val;
  33.  
  34.     asm volatile ("inb %1, %0 \n" : "=a" (val) : "d"(port));
  35.     return val;
  36. }
  37.  
  38. static inline u16 inw(u16 port)
  39. {
  40.     u16 val;
  41.  
  42.     asm volatile ("inw %1, %0 \n" : "=a" (val) : "d"(port));
  43.     return val;
  44. }
  45.  
  46. static inline u32 inl(u16 port)
  47. {
  48.     u32 val;
  49.  
  50.     asm volatile ("inl %1, %0 \n" : "=a" (val) : "d"(port));
  51.     return val;
  52. }
  53.  
  54. static void conf12_init(struct pci_access *a)
  55. {
  56. }
  57.  
  58. static void conf12_cleanup(struct pci_access *a UNUSED)
  59. {
  60. }
  61.  
  62. /*
  63.  * Before we decide to use direct hardware access mechanisms, we try to do some
  64.  * trivial checks to ensure it at least _seems_ to be working -- we just test
  65.  * whether bus 00 contains a host bridge (this is similar to checking
  66.  * techniques used in XFree86, but ours should be more reliable since we
  67.  * attempt to make use of direct access hints provided by the PCI BIOS).
  68.  *
  69.  * This should be close to trivial, but it isn't, because there are buggy
  70.  * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
  71.  */
  72.  
  73. static int intel_sanity_check(struct pci_access *a, struct pci_methods *m)
  74. {
  75.     struct pci_dev d;
  76.  
  77.     a->debug("...sanity check");
  78.     d.bus = 0;
  79.     d.func = 0;
  80.     for (d.dev = 0; d.dev < 32; d.dev++) {
  81.         u16 class, vendor;
  82.         if (m->
  83.             read(&d, PCI_CLASS_DEVICE, (byte *) & class,
  84.              sizeof(class))
  85.             && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST)
  86.             || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA))
  87.             || m->read(&d, PCI_VENDOR_ID, (byte *) & vendor,
  88.                    sizeof(vendor))
  89.             && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL)
  90.             || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) {
  91.             a->debug("...outside the Asylum at 0/%02x/0",
  92.                  d.dev);
  93.             return 1;
  94.         }
  95.     }
  96.     a->debug("...insane");
  97.     return 0;
  98. }
  99.  
  100. /*
  101.  *  Configuration type 1
  102.  */
  103.  
  104. #define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
  105.  
  106. static int conf1_detect(struct pci_access *a)
  107. {
  108.     unsigned int tmp;
  109.     int res = 0;
  110.  
  111.     outb(0x01, 0xCFB);
  112.     tmp = inl(0xCF8);
  113.     outl(0x80000000, 0xCF8);
  114.     if (inl(0xCF8) == 0x80000000)
  115.         res = 1;
  116.     outl(tmp, 0xCF8);
  117.     if (res)
  118.         res = intel_sanity_check(a, &pm_intel_conf1);
  119.     return res;
  120. }
  121.  
  122. static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len)
  123. {
  124.     int addr = 0xcfc + (pos & 3);
  125.  
  126.     if (pos >= 256)
  127.         return 0;
  128.  
  129.     outl(0x80000000 | ((d->bus & 0xff) << 16) |
  130.          (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
  131.  
  132.     switch (len) {
  133.     case 1:
  134.         buf[0] = inb(addr);
  135.         break;
  136.     case 2:
  137.         ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
  138.         break;
  139.     case 4:
  140.         ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
  141.         break;
  142.     default:
  143.         return pci_generic_block_read(d, pos, buf, len);
  144.     }
  145.     return 1;
  146. }
  147.  
  148. static int 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) |
  156.          (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8);
  157.  
  158.     switch (len) {
  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 conf2_detect(struct pci_access *a)
  179. {
  180.     /* This is ugly and tends to produce false positives. Beware. */
  181.  
  182.     outb(0x00, 0xCFB);
  183.     outb(0x00, 0xCF8);
  184.     outb(0x00, 0xCFA);
  185.     if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
  186.         return intel_sanity_check(a, &pm_intel_conf2);
  187.     else
  188.         return 0;
  189. }
  190.  
  191. static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len)
  192. {
  193.     int addr = 0xc000 | (d->dev << 8) | pos;
  194.  
  195.     if (pos >= 256)
  196.         return 0;
  197.  
  198.     if (d->dev >= 16)
  199.         /* conf2 supports only 16 devices per bus */
  200.         return 0;
  201.     outb((d->func << 1) | 0xf0, 0xcf8);
  202.     outb(d->bus, 0xcfa);
  203.     switch (len) {
  204.     case 1:
  205.         buf[0] = inb(addr);
  206.         break;
  207.     case 2:
  208.         ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
  209.         break;
  210.     case 4:
  211.         ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
  212.         break;
  213.     default:
  214.         outb(0, 0xcf8);
  215.         return pci_generic_block_read(d, pos, buf, len);
  216.     }
  217.     outb(0, 0xcf8);
  218.     return 1;
  219. }
  220.  
  221. static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len)
  222. {
  223.     int addr = 0xc000 | (d->dev << 8) | pos;
  224.  
  225.     if (pos >= 256)
  226.         return 0;
  227.  
  228.     if (d->dev >= 16)
  229.         d->access->
  230.             error("conf2_write: only first 16 devices exist.");
  231.     outb((d->func << 1) | 0xf0, 0xcf8);
  232.     outb(d->bus, 0xcfa);
  233.     switch (len) {
  234.     case 1:
  235.         outb(buf[0], addr);
  236.         break;
  237.     case 2:
  238.         outw(le16_to_cpu(*(u16 *) buf), addr);
  239.         break;
  240.     case 4:
  241.         outl(le32_to_cpu(*(u32 *) buf), addr);
  242.         break;
  243.     default:
  244.         outb(0, 0xcf8);
  245.         return pci_generic_block_write(d, pos, buf, len);
  246.     }
  247.     outb(0, 0xcf8);
  248.     return 1;
  249. }
  250.  
  251. struct pci_methods pm_intel_conf1 = {
  252.     "Intel-conf1",
  253.     NULL,           /* config */
  254.     conf1_detect,
  255.     conf12_init,
  256.     conf12_cleanup,
  257.     pci_generic_scan,
  258.     pci_generic_fill_info,
  259.     conf1_read,
  260.     conf1_write,
  261.     NULL,           /* init_dev */
  262.     NULL            /* cleanup_dev */
  263. };
  264.  
  265. struct pci_methods pm_intel_conf2 = {
  266.     "Intel-conf2",
  267.     NULL,           /* config */
  268.     conf2_detect,
  269.     conf12_init,
  270.     conf12_cleanup,
  271.     pci_generic_scan,
  272.     pci_generic_fill_info,
  273.     conf2_read,
  274.     conf2_write,
  275.     NULL,           /* init_dev */
  276.     NULL            /* cleanup_dev */
  277. };
  278.