* Registration of PCI drivers and handling of hot-pluggable devices.
*/
+/* multithreaded probe logic */
+static int pci_multithread_probe =
+#ifdef CONFIG_PCI_MULTITHREAD_PROBE
+ 1;
+#else
+ 0;
+#endif
+__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644);
+
+
/*
* Dynamic device IDs are disabled for !CONFIG_HOTPLUG
*/
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
+ int retval = 0;
fields = sscanf(buf, "%x %x %x %x %x %x %lux",
&vendor, &device, &subvendor, &subdevice,
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
- driver_attach(&pdrv->driver);
+ retval = driver_attach(&pdrv->driver);
put_driver(&pdrv->driver);
}
+ if (retval)
+ return retval;
return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
/**
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
- * @ids: array of PCI device id structures to search in
- * @dev: the PCI device structure to match against
* @drv: the PCI driver to match against
+ * @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices. Returns the matching
return i;
}
+static int pci_device_suspend_late(struct device * dev, pm_message_t state)
+{
+ struct pci_dev * pci_dev = to_pci_dev(dev);
+ struct pci_driver * drv = pci_dev->driver;
+ int i = 0;
+
+ if (drv && drv->suspend_late) {
+ i = drv->suspend_late(pci_dev, state);
+ suspend_report_result(drv->suspend_late, i);
+ }
+ return i;
+}
/*
* Default resume method for devices that have no driver provided resume,
* or not even a driver at all.
*/
-static void pci_default_resume(struct pci_dev *pci_dev)
+static int pci_default_resume(struct pci_dev *pci_dev)
{
- int retval;
+ int retval = 0;
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
+
+ return retval;
}
static int pci_device_resume(struct device * dev)
{
+ int error;
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
if (drv && drv->resume)
- drv->resume(pci_dev);
+ error = drv->resume(pci_dev);
else
- pci_default_resume(pci_dev);
- return 0;
+ error = pci_default_resume(pci_dev);
+ return error;
+}
+
+static int pci_device_resume_early(struct device * dev)
+{
+ int error = 0;
+ struct pci_dev * pci_dev = to_pci_dev(dev);
+ struct pci_driver * drv = pci_dev->driver;
+
+ if (drv && drv->resume_early)
+ error = drv->resume_early(pci_dev);
+ return error;
}
static void pci_device_shutdown(struct device *dev)
drv->driver.owner = owner;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
+ if (pci_multithread_probe)
+ drv->driver.multithread_probe = pci_multithread_probe;
+ else
+ drv->driver.multithread_probe = drv->multithread_probe;
+
spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);
.probe = pci_device_probe,
.remove = pci_device_remove,
.suspend = pci_device_suspend,
- .shutdown = pci_device_shutdown,
+ .suspend_late = pci_device_suspend_late,
+ .resume_early = pci_device_resume_early,
.resume = pci_device_resume,
+ .shutdown = pci_device_shutdown,
.dev_attrs = pci_dev_attrs,
};