Subversion Repositories HelenOS

Rev

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

  1. #include <futex.h>
  2. #include <assert.h>
  3.  
  4. #include "pci.h"
  5. #include "pci_bus.h"
  6. #include "pci_regs.h"
  7. #include "pci_conf.h"
  8.  
  9. LIST_INITIALIZE(devices_list);
  10. LIST_INITIALIZE(buses_list);
  11. LIST_INITIALIZE(drivers_list);
  12.  
  13. static atomic_t pci_bus_futex = FUTEX_INITIALIZER;
  14.  
  15. static int pci_match(pci_drv_t *drv, pci_dev_t *dev);
  16. static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev);
  17. static void pci_lookup_driver(pci_dev_t *dev);
  18. static void pci_lookup_devices(pci_drv_t *drv);
  19.  
  20.  
  21. // TODO: think about locking
  22. void pci_bus_scan(pci_bus_t *bus)
  23. {
  24.     pci_dev_t *dev = pci_alloc_dev();
  25.     pci_bus_t *child_bus = NULL;
  26.     int dnum, fnum;
  27.     bool multi;
  28.     uint8_t header_type;
  29.    
  30.     printf("PCI: scanning bus number %d\n", bus->num);
  31.    
  32.     for (dnum = 0; dnum < 4/*256*/; dnum++) {
  33.         multi = true;
  34.         for (fnum = 0; multi && fnum < 8; fnum++) {
  35.             pci_init_dev(dev, bus, dnum, fnum);
  36.             dev->vendor_id = pci_conf_read_16(dev, PCI_VENDOR_ID);
  37.             dev->device_id = pci_conf_read_16(dev, PCI_DEVICE_ID);
  38.             if (dev->vendor_id == 0xFFFF) {
  39.                 continue;  // device is not present, go on scanning the bus
  40.             }
  41.             header_type = pci_conf_read_8(dev, PCI_HEADER_TYPE);
  42.             if (fnum == 0) {
  43.                  multi = header_type >> 7;  // is the device multifunction?
  44.             }
  45.             header_type = header_type & 0x7F; // clear the multifunction bit
  46.            
  47.             printf("PCI: adding new device %d : %d", dnum, fnum);
  48.             printf(" - vendor = %x, device = %x.\n", dev->vendor_id, dev->device_id);
  49.             pci_device_register(dev);
  50.             dev = pci_alloc_dev();  // alloc new aux. dev. structure
  51.            
  52.             if (header_type == PCI_HEADER_TYPE_BRIDGE || header_type == PCI_HEADER_TYPE_CARDBUS ) {
  53.                 if (dnum != 0 && fnum != 0) {
  54.                     child_bus = pci_alloc_bus();
  55.                     pci_init_bus(child_bus, bus, pci_conf_read_8(dev, PCI_BRIDGE_SEC_BUS_NUM));
  56.                     pci_bus_register(child_bus);
  57.                     pci_bus_scan(child_bus);   
  58.                 }  
  59.             }
  60.         }
  61.     }
  62.    
  63.     if (dev->vendor_id == 0xFFFF) {
  64.         pci_free_dev(dev);  // free the auxiliary device structure
  65.     }  
  66. }
  67.  
  68. /*
  69.  * Usage: pci_bus_futex must be down.
  70.  */
  71. static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev)
  72. {
  73.     assert(dev->driver == NULL);
  74.    
  75.     if (drv->ops->add_device(dev)) {
  76.         dev->driver = drv;
  77.         return 1;
  78.     }
  79.    
  80.     return 0;
  81. }
  82.  
  83. /*
  84.  * Usage: pci_bus_futex must be down.
  85.  */
  86. static void pci_lookup_driver(pci_dev_t *dev)
  87. {
  88.     link_t *item = drivers_list.next;
  89.     pci_drv_t *drv = NULL;
  90.    
  91.     while (item != &drivers_list) {
  92.         drv = list_get_instance(item, pci_drv_t, link);
  93.         if (pci_match(drv, dev) && pci_pass_dev(drv, dev)) {
  94.             break;
  95.         }
  96.         item = item->next;
  97.     }
  98. }
  99.  
  100. /*
  101.  * Usage: pci_bus_futex must be down.
  102.  */
  103. static void pci_lookup_devices(pci_drv_t *drv)
  104. {
  105.     link_t *item = devices_list.next;
  106.     pci_dev_t *dev = NULL;
  107.    
  108.     while (item != &devices_list) {
  109.         dev = list_get_instance(item, pci_dev_t, link);
  110.         if (dev->driver == NULL && pci_match(drv, dev)) {
  111.             pci_pass_dev(drv, dev);
  112.         }
  113.         item = item->next;
  114.     }
  115. }
  116.  
  117. static int pci_match(pci_drv_t *drv, pci_dev_t *dev)
  118. {
  119.     return drv->vendor_id == dev->vendor_id && drv->device_id == dev->vendor_id;
  120. }
  121.  
  122. void pci_bus_register(pci_bus_t *bus)
  123. {
  124.     futex_down(&pci_bus_futex);
  125.    
  126.     // add the device to the list of pci devices
  127.     list_append(&(bus->link), &buses_list);
  128.    
  129.     futex_up(&pci_bus_futex);
  130. }
  131.  
  132. void pci_device_register(pci_dev_t *dev)
  133. {
  134.     futex_down(&pci_bus_futex);
  135.    
  136.     // add the device to the list of pci devices
  137.     list_append(&(dev->link), &devices_list);
  138.    
  139.     // try to find suitable driver for the device and pass the device to it
  140.     pci_lookup_driver(dev);
  141.    
  142.     futex_up(&pci_bus_futex);  
  143. }
  144.  
  145. void pci_driver_register(pci_drv_t *drv)
  146. {
  147.     futex_down(&pci_bus_futex);
  148.     list_append(&(drv->link), &drivers_list);
  149.    
  150.     // try to find compatible devices
  151.     pci_lookup_devices(drv);
  152.    
  153.     futex_up(&pci_bus_futex);
  154. }
  155.  
  156.