aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-driver.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-09-03 02:26:36 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-09-09 16:43:58 -0400
commit9dba910e9de2c4aa15ec1286f10052c107ef48ca (patch)
tree4870eccc95e406ae8d490136f5d65953203418c8 /drivers/pci/pci-driver.c
parent825c423a35a80a8fd66398a3f9bde7f0b0187a76 (diff)
PCI: separate out pci_add_dynid()
Separate out pci_add_dynid() from store_new_id() and export it so that in-kernel code can add PCI IDs dynamically. As the function will be available regardless of HOTPLUG, put it and pull pci_free_dynids() outside of CONFIG_HOTPLUG. This will be used by pci-stub to initialize initial IDs via module param. While at it, remove bogus get_driver() failure check. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Reviewed-by: Grant Grundler <grundler@parisc-linux.org> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pci-driver.c')
-rw-r--r--drivers/pci/pci-driver.c119
1 files changed, 74 insertions, 45 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index f99bc7f089f1..c66dc4341fa0 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -19,37 +19,98 @@
19#include <linux/cpu.h> 19#include <linux/cpu.h>
20#include "pci.h" 20#include "pci.h"
21 21
22/*
23 * Dynamic device IDs are disabled for !CONFIG_HOTPLUG
24 */
25
26struct pci_dynid { 22struct pci_dynid {
27 struct list_head node; 23 struct list_head node;
28 struct pci_device_id id; 24 struct pci_device_id id;
29}; 25};
30 26
31#ifdef CONFIG_HOTPLUG 27/**
28 * pci_add_dynid - add a new PCI device ID to this driver and re-probe devices
29 * @drv: target pci driver
30 * @vendor: PCI vendor ID
31 * @device: PCI device ID
32 * @subvendor: PCI subvendor ID
33 * @subdevice: PCI subdevice ID
34 * @class: PCI class
35 * @class_mask: PCI class mask
36 * @driver_data: private driver data
37 *
38 * Adds a new dynamic pci device ID to this driver and causes the
39 * driver to probe for all devices again. @drv must have been
40 * registered prior to calling this function.
41 *
42 * CONTEXT:
43 * Does GFP_KERNEL allocation.
44 *
45 * RETURNS:
46 * 0 on success, -errno on failure.
47 */
48int pci_add_dynid(struct pci_driver *drv,
49 unsigned int vendor, unsigned int device,
50 unsigned int subvendor, unsigned int subdevice,
51 unsigned int class, unsigned int class_mask,
52 unsigned long driver_data)
53{
54 struct pci_dynid *dynid;
55 int retval;
56
57 dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
58 if (!dynid)
59 return -ENOMEM;
60
61 dynid->id.vendor = vendor;
62 dynid->id.device = device;
63 dynid->id.subvendor = subvendor;
64 dynid->id.subdevice = subdevice;
65 dynid->id.class = class;
66 dynid->id.class_mask = class_mask;
67 dynid->id.driver_data = driver_data;
32 68
69 spin_lock(&drv->dynids.lock);
70 list_add_tail(&dynid->node, &drv->dynids.list);
71 spin_unlock(&drv->dynids.lock);
72
73 get_driver(&drv->driver);
74 retval = driver_attach(&drv->driver);
75 put_driver(&drv->driver);
76
77 return retval;
78}
79
80static void pci_free_dynids(struct pci_driver *drv)
81{
82 struct pci_dynid *dynid, *n;
83
84 spin_lock(&drv->dynids.lock);
85 list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
86 list_del(&dynid->node);
87 kfree(dynid);
88 }
89 spin_unlock(&drv->dynids.lock);
90}
91
92/*
93 * Dynamic device ID manipulation via sysfs is disabled for !CONFIG_HOTPLUG
94 */
95#ifdef CONFIG_HOTPLUG
33/** 96/**
34 * store_new_id - add a new PCI device ID to this driver and re-probe devices 97 * store_new_id - sysfs frontend to pci_add_dynid()
35 * @driver: target device driver 98 * @driver: target device driver
36 * @buf: buffer for scanning device ID data 99 * @buf: buffer for scanning device ID data
37 * @count: input size 100 * @count: input size
38 * 101 *
39 * Adds a new dynamic pci device ID to this driver, 102 * Allow PCI IDs to be added to an existing driver via sysfs.
40 * and causes the driver to probe for all devices again.
41 */ 103 */
42static ssize_t 104static ssize_t
43store_new_id(struct device_driver *driver, const char *buf, size_t count) 105store_new_id(struct device_driver *driver, const char *buf, size_t count)
44{ 106{
45 struct pci_dynid *dynid;
46 struct pci_driver *pdrv = to_pci_driver(driver); 107 struct pci_driver *pdrv = to_pci_driver(driver);
47 const struct pci_device_id *ids = pdrv->id_table; 108 const struct pci_device_id *ids = pdrv->id_table;
48 __u32 vendor, device, subvendor=PCI_ANY_ID, 109 __u32 vendor, device, subvendor=PCI_ANY_ID,
49 subdevice=PCI_ANY_ID, class=0, class_mask=0; 110 subdevice=PCI_ANY_ID, class=0, class_mask=0;
50 unsigned long driver_data=0; 111 unsigned long driver_data=0;
51 int fields=0; 112 int fields=0;
52 int retval=0; 113 int retval;
53 114
54 fields = sscanf(buf, "%x %x %x %x %x %x %lx", 115 fields = sscanf(buf, "%x %x %x %x %x %x %lx",
55 &vendor, &device, &subvendor, &subdevice, 116 &vendor, &device, &subvendor, &subdevice,
@@ -72,27 +133,8 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
72 return retval; 133 return retval;
73 } 134 }
74 135
75 dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); 136 retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice,
76 if (!dynid) 137 class, class_mask, driver_data);
77 return -ENOMEM;
78
79 dynid->id.vendor = vendor;
80 dynid->id.device = device;
81 dynid->id.subvendor = subvendor;
82 dynid->id.subdevice = subdevice;
83 dynid->id.class = class;
84 dynid->id.class_mask = class_mask;
85 dynid->id.driver_data = driver_data;
86
87 spin_lock(&pdrv->dynids.lock);
88 list_add_tail(&dynid->node, &pdrv->dynids.list);
89 spin_unlock(&pdrv->dynids.lock);
90
91 if (get_driver(&pdrv->driver)) {
92 retval = driver_attach(&pdrv->driver);
93 put_driver(&pdrv->driver);
94 }
95
96 if (retval) 138 if (retval)
97 return retval; 139 return retval;
98 return count; 140 return count;
@@ -145,19 +187,6 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
145} 187}
146static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); 188static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
147 189
148static void
149pci_free_dynids(struct pci_driver *drv)
150{
151 struct pci_dynid *dynid, *n;
152
153 spin_lock(&drv->dynids.lock);
154 list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
155 list_del(&dynid->node);
156 kfree(dynid);
157 }
158 spin_unlock(&drv->dynids.lock);
159}
160
161static int 190static int
162pci_create_newid_file(struct pci_driver *drv) 191pci_create_newid_file(struct pci_driver *drv)
163{ 192{
@@ -186,7 +215,6 @@ static void pci_remove_removeid_file(struct pci_driver *drv)
186 driver_remove_file(&drv->driver, &driver_attr_remove_id); 215 driver_remove_file(&drv->driver, &driver_attr_remove_id);
187} 216}
188#else /* !CONFIG_HOTPLUG */ 217#else /* !CONFIG_HOTPLUG */
189static inline void pci_free_dynids(struct pci_driver *drv) {}
190static inline int pci_create_newid_file(struct pci_driver *drv) 218static inline int pci_create_newid_file(struct pci_driver *drv)
191{ 219{
192 return 0; 220 return 0;
@@ -1106,6 +1134,7 @@ static int __init pci_driver_init(void)
1106 1134
1107postcore_initcall(pci_driver_init); 1135postcore_initcall(pci_driver_init);
1108 1136
1137EXPORT_SYMBOL_GPL(pci_add_dynid);
1109EXPORT_SYMBOL(pci_match_id); 1138EXPORT_SYMBOL(pci_match_id);
1110EXPORT_SYMBOL(__pci_register_driver); 1139EXPORT_SYMBOL(__pci_register_driver);
1111EXPORT_SYMBOL(pci_unregister_driver); 1140EXPORT_SYMBOL(pci_unregister_driver);