Subversion Repositories HelenOS

Rev

Rev 1787 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  The PCI Library -- User Access
  3.  *
  4.  *  Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
  5.  *
  6.  *  May 8, 2006 - 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 <stdio.h>
  12. #include <stdlib.h>
  13. #include <stdarg.h>
  14. #include <string.h>
  15.  
  16. #include "internal.h"
  17.  
  18. static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
  19.     &pm_intel_conf1,
  20.     &pm_intel_conf2,
  21. };
  22.  
  23. struct pci_access *pci_alloc(void)
  24. {
  25.     struct pci_access *a = malloc(sizeof(struct pci_access));
  26.     int i;
  27.  
  28.     if (!a)
  29.         return NULL;
  30.        
  31.     bzero(a, sizeof(*a));
  32.     for (i = 0; i < PCI_ACCESS_MAX; i++)
  33.         if (pci_methods[i] && pci_methods[i]->config)
  34.             pci_methods[i]->config(a);
  35.     return a;
  36. }
  37.  
  38. void *pci_malloc(struct pci_access *a, int size)
  39. {
  40.     void *x = malloc(size);
  41.  
  42.     if (!x)
  43.         a->error("Out of memory (allocation of %d bytes failed)", size);
  44.     return x;
  45. }
  46.  
  47. void pci_mfree(void *x)
  48. {
  49.     if (x)
  50.         free(x);
  51. }
  52.  
  53. static void pci_generic_error(char *msg, ...)
  54. {
  55.     va_list args;
  56.  
  57.     va_start(args, msg);
  58.     puts("pcilib: ");
  59.     vprintf(msg, args);
  60.     putchar('\n');
  61.     exit(1);
  62. }
  63.  
  64. static void pci_generic_warn(char *msg, ...)
  65. {
  66.     va_list args;
  67.  
  68.     va_start(args, msg);
  69.     puts("pcilib: ");
  70.     vprintf(msg, args);
  71.     putchar('\n');
  72. }
  73.  
  74. static void pci_generic_debug(char *msg, ...)
  75. {
  76.     va_list args;
  77.  
  78.     va_start(args, msg);
  79.     vprintf(msg, args);
  80.     va_end(args);
  81. }
  82.  
  83. static void pci_null_debug(char *msg UNUSED, ...)
  84. {
  85. }
  86.  
  87. void pci_init(struct pci_access *a)
  88. {
  89.     if (!a->error)
  90.         a->error = pci_generic_error;
  91.     if (!a->warning)
  92.         a->warning = pci_generic_warn;
  93.     if (!a->debug)
  94.         a->debug = pci_generic_debug;
  95.     if (!a->debugging)
  96.         a->debug = pci_null_debug;
  97.  
  98.     if (a->method) {
  99.         if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
  100.             a->error("This access method is not supported.");
  101.         a->methods = pci_methods[a->method];
  102.     } else {
  103.         unsigned int i;
  104.         for (i = 0; i < PCI_ACCESS_MAX; i++)
  105.             if (pci_methods[i]) {
  106.                 a->debug("Trying method %d...", i);
  107.                 if (pci_methods[i]->detect(a)) {
  108.                     a->debug("...OK\n");
  109.                     a->methods = pci_methods[i];
  110.                     a->method = i;
  111.                     break;
  112.                 }
  113.                 a->debug("...No.\n");
  114.             }
  115.         if (!a->methods)
  116.             a->error("Cannot find any working access method.");
  117.     }
  118.     a->debug("Decided to use %s\n", a->methods->name);
  119.     a->methods->init(a);
  120. }
  121.  
  122. void pci_cleanup(struct pci_access *a)
  123. {
  124.     struct pci_dev *d, *e;
  125.  
  126.     for (d = a->devices; d; d = e) {
  127.         e = d->next;
  128.         pci_free_dev(d);
  129.     }
  130.     if (a->methods)
  131.         a->methods->cleanup(a);
  132.     pci_free_name_list(a);
  133.     pci_mfree(a);
  134. }
  135.  
  136. void pci_scan_bus(struct pci_access *a)
  137. {
  138.     a->methods->scan(a);
  139. }
  140.  
  141. struct pci_dev *pci_alloc_dev(struct pci_access *a)
  142. {
  143.     struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
  144.  
  145.     bzero(d, sizeof(*d));
  146.     d->access = a;
  147.     d->methods = a->methods;
  148.     d->hdrtype = -1;
  149.     if (d->methods->init_dev)
  150.         d->methods->init_dev(d);
  151.     return d;
  152. }
  153.  
  154. int pci_link_dev(struct pci_access *a, struct pci_dev *d)
  155. {
  156.     d->next = a->devices;
  157.     a->devices = d;
  158.  
  159.     return 1;
  160. }
  161.  
  162. struct pci_dev *pci_get_dev(struct pci_access *a, int domain, int bus,
  163.                 int dev, int func)
  164. {
  165.     struct pci_dev *d = pci_alloc_dev(a);
  166.  
  167.     d->domain = domain;
  168.     d->bus = bus;
  169.     d->dev = dev;
  170.     d->func = func;
  171.     return d;
  172. }
  173.  
  174. void pci_free_dev(struct pci_dev *d)
  175. {
  176.     if (d->methods->cleanup_dev)
  177.         d->methods->cleanup_dev(d);
  178.     pci_mfree(d);
  179. }
  180.  
  181. static inline void
  182. pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
  183. {
  184.     if (pos & (len - 1))
  185.         d->access->error("Unaligned read: pos=%02x, len=%d", pos,
  186.                  len);
  187.     if (pos + len <= d->cache_len)
  188.         memcpy(buf, d->cache + pos, len);
  189.     else if (!d->methods->read(d, pos, buf, len))
  190.         memset(buf, 0xff, len);
  191. }
  192.  
  193. byte pci_read_byte(struct pci_dev *d, int pos)
  194. {
  195.     byte buf;
  196.     pci_read_data(d, &buf, pos, 1);
  197.     return buf;
  198. }
  199.  
  200. word pci_read_word(struct pci_dev * d, int pos)
  201. {
  202.     word buf;
  203.     pci_read_data(d, &buf, pos, 2);
  204.     return le16_to_cpu(buf);
  205. }
  206.  
  207. u32 pci_read_long(struct pci_dev * d, int pos)
  208. {
  209.     u32 buf;
  210.     pci_read_data(d, &buf, pos, 4);
  211.     return le32_to_cpu(buf);
  212. }
  213.  
  214. int pci_read_block(struct pci_dev *d, int pos, byte * buf, int len)
  215. {
  216.     return d->methods->read(d, pos, buf, len);
  217. }
  218.  
  219. static inline int
  220. pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
  221. {
  222.     if (pos & (len - 1))
  223.         d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
  224.     if (pos + len <= d->cache_len)
  225.         memcpy(d->cache + pos, buf, len);
  226.     return d->methods->write(d, pos, buf, len);
  227. }
  228.  
  229. int pci_write_byte(struct pci_dev *d, int pos, byte data)
  230. {
  231.     return pci_write_data(d, &data, pos, 1);
  232. }
  233.  
  234. int pci_write_word(struct pci_dev *d, int pos, word data)
  235. {
  236.     word buf = cpu_to_le16(data);
  237.     return pci_write_data(d, &buf, pos, 2);
  238. }
  239.  
  240. int pci_write_long(struct pci_dev *d, int pos, u32 data)
  241. {
  242.     u32 buf = cpu_to_le32(data);
  243.     return pci_write_data(d, &buf, pos, 4);
  244. }
  245.  
  246. int pci_write_block(struct pci_dev *d, int pos, byte * buf, int len)
  247. {
  248.     if (pos < d->cache_len) {
  249.         int l = (pos + len >= d->cache_len) ? (d->cache_len - pos) : len;
  250.         memcpy(d->cache + pos, buf, l);
  251.     }
  252.     return d->methods->write(d, pos, buf, len);
  253. }
  254.  
  255. int pci_fill_info(struct pci_dev *d, int flags)
  256. {
  257.     if (flags & PCI_FILL_RESCAN) {
  258.         flags &= ~PCI_FILL_RESCAN;
  259.         d->known_fields = 0;
  260.     }
  261.     if (flags & ~d->known_fields)
  262.         d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
  263.     return d->known_fields;
  264. }
  265.  
  266. void pci_setup_cache(struct pci_dev *d, byte * cache, int len)
  267. {
  268.     d->cache = cache;
  269.     d->cache_len = len;
  270. }
  271.