aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRussell King <rmk+lkml@arm.linux.org.uk>2006-11-29 16:18:04 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-20 13:54:41 -0500
commit7461b60afa62b26943e97861d87b9f9a32d7fd9c (patch)
tree4872be72d50f56ef1a9d17f132bb19b74301f691 /drivers/pci
parentf238085415c56618e042252894f2fcc971add645 (diff)
PCI: use /sys/bus/pci/drivers/<driver>/new_id first
Unfortunately, the .../new_id feature does not work with the 8250_pci driver. The reason for this comes down to the way .../new_id is implemented. When PCI tries to match a driver to a device, it checks the modules static device ID tables _before_ checking the dynamic new_id tables. When a driver is capable of matching by ID, and falls back to matching by class (as 8250_pci does), this makes it absolutely impossible to specify a board by ID, and as such the correct driver_data value to use with it. Let's say you have a serial board with vendor 0x1234 and device 0x5678. It's class is set to PCI_CLASS_COMMUNICATION_SERIAL. On boot, this card is matched to the 8250_pci driver, which tries to probe it because it matched using the class entry. The driver finds that it is unable to automatically detect the correct settings to use, so it returns -ENODEV. You know that the information the driver needs is to match this card using a device_data value of '7'. So you echo 1234 5678 0 0 0 0 7 into new_id. The kernel attempts to re-bind 8250_pci to this device. However, because it scans the PCI driver tables, it _again_ matches the class entry which has the wrong device_data. It fails. End of story. You can't support the card without rebuilding the kernel (or writing a specific PCI probe module to support it.) So, can we make new_id override the driver-internal PCI ID tables? IOW, like this: From: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-driver.c10
1 files changed, 3 insertions, 7 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e5ae3a0c13bb..de5b9011d038 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -162,14 +162,9 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
162const struct pci_device_id *pci_match_device(struct pci_driver *drv, 162const struct pci_device_id *pci_match_device(struct pci_driver *drv,
163 struct pci_dev *dev) 163 struct pci_dev *dev)
164{ 164{
165 const struct pci_device_id *id;
166 struct pci_dynid *dynid; 165 struct pci_dynid *dynid;
167 166
168 id = pci_match_id(drv->id_table, dev); 167 /* Look at the dynamic ids first, before the static ones */
169 if (id)
170 return id;
171
172 /* static ids didn't match, lets look at the dynamic ones */
173 spin_lock(&drv->dynids.lock); 168 spin_lock(&drv->dynids.lock);
174 list_for_each_entry(dynid, &drv->dynids.list, node) { 169 list_for_each_entry(dynid, &drv->dynids.list, node) {
175 if (pci_match_one_device(&dynid->id, dev)) { 170 if (pci_match_one_device(&dynid->id, dev)) {
@@ -178,7 +173,8 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv,
178 } 173 }
179 } 174 }
180 spin_unlock(&drv->dynids.lock); 175 spin_unlock(&drv->dynids.lock);
181 return NULL; 176
177 return pci_match_id(drv->id_table, dev);
182} 178}
183 179
184static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, 180static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,