Subject: [PATCH] [acpi driver model] Implement core driver methods - Implement all of the core Linux driver methods, making them pass down the calls to the corresponding ACPI driver calls. - Implement acpi_device_start() and acpi_device_stop() for the manually firing up and quiescing a device. Make sure those are called from the ->probe() and ->remove() methods. Signed-off-by: Patrick Mochel --- drivers/acpi/drivers/core/driver.c | 162 ++++++++++++++++++++++++++++++++++++ 1 files changed, 162 insertions(+), 0 deletions(-) applies-to: 74b019f29b10dbecf8b738c60159cdcb824252d7 eb3c4d38917a4370024cd84b7e059f24f9565e4e diff --git a/drivers/acpi/drivers/core/driver.c b/drivers/acpi/drivers/core/driver.c index 6e37faa..cb12d01 100644 --- a/drivers/acpi/drivers/core/driver.c +++ b/drivers/acpi/drivers/core/driver.c @@ -18,6 +18,159 @@ /** + * acpi_device_start - Fire up an ACPI device. + * @ad: The ACPI device + * + * This runs the ->d_start() method in the device's + * driver, if it is there. This method should be run + * only after the driver has been successfully added + * to the device (and before it has been removed). + * + * This is called from acpi_device_add() below, though + * it may also be called in the event of a device being + * inserted or removed. + * + * Note that this function takes a 'struct acpi_dev' as + * a parameter, since it is not a pass-down method from + * the Linux core struct device_driver. This may change + * in the future (when/if a ->start() method is added). + * For now, it is only called locally. + */ + +static int acpi_device_start(struct acpi_dev * ad) +{ + struct acpi_device_driver * adrv = to_acpi_driver(ad->dev.driver); + int ret = 0; + + if (adrv && adrv->d_start) + ret = adrv->d_start(ad); + return ret; +} + + +/** + * acpi_device_stop - Quiesce a device and driver. + * @ad: The ACPI device. + * + * This method calls the ->d_stop() method in the device's + * driver, if it exists. This method should be run only + * while the device is bound to a driver. + * + * This is called from acpi_device_remove() below, though + * it may also be called when a device is inserted or + * removed. + * + * Note that this function takes a 'struct acpi_dev' as + * a parameter, since it is not a pass-down method from + * the Linux core struct device_driver. This may change + * in the future (when/if a ->start() method is added). + * For now, it is only called locally. + */ + +static int acpi_device_stop(struct acpi_dev * ad) +{ + struct acpi_device_driver * adrv = to_acpi_driver(ad->dev.driver); + int ret = 0; + + if (adrv && adrv->d_stop) + ret = adrv->d_stop(ad); + return ret; +} + + +static int acpi_device_add(struct device * dev) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_device_driver * adrv = to_acpi_driver(dev->driver); + int ret = 0; + + dbg("Probing: Device [%s] Driver [%s]", + ad->dev.bus_id, adrv->d_drv.name); + + if (adrv->d_add) { + ret = adrv->d_add(ad); + + if (ret) + goto Done; + } + + /* + * Start the device + */ + ret = acpi_device_start(ad); + if (!ret) + goto Done; + + /* + * Something bad happened.. + * tear down the device and return the error. + */ + if (adrv->d_remove) + adrv->d_remove(ad); + + Done: + dbg("Probing Done: Device [%s] Driver [%s], Return [%d]", + ad->dev.bus_id, adrv->d_drv.name, ret); + return ret; +} + + + +static int acpi_device_remove(struct device * dev) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_device_driver * adrv = to_acpi_driver(dev->driver); + + dbg("Removing: Device [%s] Driver [%s]", + ad->dev.bus_id, adrv->d_drv.name); + + /* + * Stop the device, ignore the error + */ + acpi_device_stop(ad); + + return adrv->d_remove ? adrv->d_remove(ad) : 0; +} + + +static void acpi_device_shutdown(struct device * dev) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_device_driver * adrv = to_acpi_driver(dev->driver); + + dbg("Shutting down: Device [%s] Driver [%s]", + ad->dev.bus_id, adrv->d_drv.name); + + if (adrv->d_shutdown) + adrv->d_shutdown(ad); +} + + +static int acpi_device_suspend(struct device * dev, pm_message_t state) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_device_driver * adrv = to_acpi_driver(dev->driver); + + dbg("Suspending: Device [%s] Driver [%s]", + ad->dev.bus_id, adrv->d_drv.name); + + return adrv->d_suspend ? adrv->d_suspend(ad, ACPI_STATE_D3) : 0; +} + + +static int acpi_device_resume(struct device * dev) +{ + struct acpi_dev * ad = to_acpi_dev(dev); + struct acpi_device_driver * adrv = to_acpi_driver(dev->driver); + + dbg("Resuming: Device [%s] Driver [%s]", + ad->dev.bus_id, adrv->d_drv.name); + + return adrv->d_resume ? adrv->d_resume(ad) : 0; +} + + +/** * acpi_driver_register - Register an ACPI driver * @drv: The ACPI driver to register * @@ -31,7 +184,16 @@ int acpi_driver_register(struct acpi_dev dbg("Registering driver %s", drv->d_drv.name); + /* + * Fill in the necessary fields for the core. + */ drv->d_drv.bus = &acpi_bus; + drv->d_drv.probe = acpi_device_add; + drv->d_drv.remove = acpi_device_remove; + drv->d_drv.shutdown = acpi_device_shutdown; + drv->d_drv.suspend = acpi_device_suspend; + drv->d_drv.resume = acpi_device_resume; + /* * Register driver with core --- 0.99.9.GIT