/** * rescan the pci bus on insert * Jan Dittmer * * heavily based on a similar module from * Vladimir Kondratiev, vladimir.kondratiev@intel.com */ #include #include #include #include /** * Rescan slot. * First, determine whether card in the slot has changed. It is * done by compare of old and actual devices for function 0. * If change detected, old device(s) removed, other functions * scanned if it is multi-function dev, new devices inserted. * * @param temp Device template. Should be set: bus and devfn. * @return Device for function 0 */ void pci_rescan_slot(struct pci_dev *temp) { struct pci_bus *bus = temp->bus; struct pci_dev* old_dev = pci_find_slot(bus->number,temp->devfn); struct pci_dev *dev = NULL; int func = 0; int new_multi = 0; /* new multifunction device */ u8 hdr_type; /* function 0 */ if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { temp->hdr_type = hdr_type & 0x7f; new_multi=hdr_type & 0x80; if (!old_dev) { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { printk("Found new device on %s function %x:%x %x\n", bus->name, temp->devfn >> 3, temp->devfn & 7, hdr_type); pci_bus_add_device(dev); } } if (new_multi) { /* continue scanning for other functions */ /* printk("Scanning subfunctions\n"); */ for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) { // printk("%x\n", func); if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) continue; temp->hdr_type = hdr_type & 0x7f; old_dev = pci_find_slot(bus->number, temp->devfn); if (!old_dev) { dev = pci_scan_single_device(bus, temp->devfn); if (dev) { printk("Found new device on %s function %x:%x %x\n", bus->name, temp->devfn >> 3, temp->devfn & 7, hdr_type); printk("Prettyname %s\n", dev->pretty_name); // from drivers/pci/bus.c, pci_bus_add_devices pci_bus_add_device(dev); } } } } } } /** * Rescan PCI bus. * Assumed, some slots may have changed its content. * Find old information about each slot and the new one. * If they match, do nothing. Otherwise, * remove/insert proper devices. * * @param bus */ static void pci_rescan_bus(const struct pci_bus *bus) { unsigned int devfn; struct pci_dev dev0; memset(&dev0, 0, sizeof(dev0)); dev0.bus = (struct pci_bus*)bus; dev0.sysdata = bus->sysdata; for (devfn = 0; devfn < 0x100; devfn += 8) { dev0.devfn = devfn; pci_rescan_slot(&dev0); } } static void pci_rescan_buses(const struct list_head *list) { const struct list_head *l; list_for_each(l,list) { const struct pci_bus *b = pci_bus_b(l); /* printk("Scanning Bus %d:%d:%d, %s\n", b->number, b->primary, b->secondary, b->name); */ pci_rescan_bus(b); pci_rescan_buses(&b->children); } } static int pci_rescan_init(void) { pci_rescan_buses(&pci_root_buses); return -ENODEV; } static void pci_rescan_exit(void) {} module_init(pci_rescan_init); module_exit(pci_rescan_exit); MODULE_DESCRIPTION("Do PCI bus rescan"); MODULE_AUTHOR("jdi");