Subversion Repositories HelenOS

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