at v2.6.12-rc3 163 lines 3.9 kB view raw
1#include <linux/kernel.h> 2#include <linux/pci.h> 3#include <linux/module.h> 4#include "pci.h" 5 6int pci_hotplug (struct device *dev, char **envp, int num_envp, 7 char *buffer, int buffer_size) 8{ 9 struct pci_dev *pdev; 10 char *scratch; 11 int i = 0; 12 int length = 0; 13 14 if (!dev) 15 return -ENODEV; 16 17 pdev = to_pci_dev(dev); 18 if (!pdev) 19 return -ENODEV; 20 21 scratch = buffer; 22 23 /* stuff we want to pass to /sbin/hotplug */ 24 envp[i++] = scratch; 25 length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X", 26 pdev->class); 27 if ((buffer_size - length <= 0) || (i >= num_envp)) 28 return -ENOMEM; 29 ++length; 30 scratch += length; 31 32 envp[i++] = scratch; 33 length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X", 34 pdev->vendor, pdev->device); 35 if ((buffer_size - length <= 0) || (i >= num_envp)) 36 return -ENOMEM; 37 ++length; 38 scratch += length; 39 40 envp[i++] = scratch; 41 length += scnprintf (scratch, buffer_size - length, 42 "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, 43 pdev->subsystem_device); 44 if ((buffer_size - length <= 0) || (i >= num_envp)) 45 return -ENOMEM; 46 ++length; 47 scratch += length; 48 49 envp[i++] = scratch; 50 length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s", 51 pci_name(pdev)); 52 if ((buffer_size - length <= 0) || (i >= num_envp)) 53 return -ENOMEM; 54 55 envp[i] = NULL; 56 57 return 0; 58} 59 60static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) 61{ 62 struct list_head *ln; 63 struct pci_dev *dev; 64 struct pci_dev_wrapped wrapped_dev; 65 int result = 0; 66 67 pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus), 68 wrapped_bus->bus->number); 69 70 if (fn->pre_visit_pci_bus) { 71 result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent); 72 if (result) 73 return result; 74 } 75 76 ln = wrapped_bus->bus->devices.next; 77 while (ln != &wrapped_bus->bus->devices) { 78 dev = pci_dev_b(ln); 79 ln = ln->next; 80 81 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); 82 wrapped_dev.dev = dev; 83 84 result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus); 85 if (result) 86 return result; 87 } 88 89 if (fn->post_visit_pci_bus) 90 result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent); 91 92 return result; 93} 94 95static int pci_visit_bridge (struct pci_visit * fn, 96 struct pci_dev_wrapped *wrapped_dev, 97 struct pci_bus_wrapped *wrapped_parent) 98{ 99 struct pci_bus *bus; 100 struct pci_bus_wrapped wrapped_bus; 101 int result = 0; 102 103 pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev)); 104 105 if (fn->visit_pci_dev) { 106 result = fn->visit_pci_dev(wrapped_dev, wrapped_parent); 107 if (result) 108 return result; 109 } 110 111 bus = wrapped_dev->dev->subordinate; 112 if (bus) { 113 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); 114 wrapped_bus.bus = bus; 115 116 result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev); 117 } 118 return result; 119} 120 121/** 122 * pci_visit_dev - scans the pci buses. 123 * Every bus and every function is presented to a custom 124 * function that can act upon it. 125 */ 126int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, 127 struct pci_bus_wrapped *wrapped_parent) 128{ 129 struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL; 130 int result = 0; 131 132 if (!dev) 133 return 0; 134 135 if (fn->pre_visit_pci_dev) { 136 result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent); 137 if (result) 138 return result; 139 } 140 141 switch (dev->class >> 8) { 142 case PCI_CLASS_BRIDGE_PCI: 143 result = pci_visit_bridge(fn, wrapped_dev, 144 wrapped_parent); 145 if (result) 146 return result; 147 break; 148 default: 149 pr_debug("PCI: Scanning device %s\n", pci_name(dev)); 150 if (fn->visit_pci_dev) { 151 result = fn->visit_pci_dev (wrapped_dev, 152 wrapped_parent); 153 if (result) 154 return result; 155 } 156 } 157 158 if (fn->post_visit_pci_dev) 159 result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent); 160 161 return result; 162} 163EXPORT_SYMBOL(pci_visit_dev);