Subversion Repositories HelenOS

Rev

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