diff options
-rw-r--r-- | drivers/firmware/dcdbas.c | 110 |
1 files changed, 88 insertions, 22 deletions
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 4652512..3a4e5c5 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -530,30 +530,27 @@ static DCDBAS_DEV_ATTR_RW(host_control_action); static DCDBAS_DEV_ATTR_RW(host_control_smi_type); static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown); -static struct device_attribute *dcdbas_dev_attrs[] = { - &dev_attr_smi_data_buf_size, - &dev_attr_smi_data_buf_phys_addr, - &dev_attr_smi_request, - &dev_attr_host_control_action, - &dev_attr_host_control_smi_type, - &dev_attr_host_control_on_shutdown, +static struct attribute *dcdbas_dev_attrs[] = { + &dev_attr_smi_data_buf_size.attr, + &dev_attr_smi_data_buf_phys_addr.attr, + &dev_attr_smi_request.attr, + &dev_attr_host_control_action.attr, + &dev_attr_host_control_smi_type.attr, + &dev_attr_host_control_on_shutdown.attr, NULL }; -/** - * dcdbas_init: initialize driver - */ -static int __init dcdbas_init(void) +static struct attribute_group dcdbas_attr_group = { + .attrs = dcdbas_dev_attrs, +}; + +static int __devinit dcdbas_probe(struct platform_device *dev) { - int i; + int i, error; host_control_action = HC_ACTION_NONE; host_control_smi_type = HC_SMITYPE_NONE; - dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(dcdbas_pdev)) - return PTR_ERR(dcdbas_pdev); - /* * BIOS SMI calls require buffer addresses be in 32-bit address space. * This is done by setting the DMA mask below. @@ -561,19 +558,79 @@ static int __init dcdbas_init(void) dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK; dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask; + error = sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group); + if (error) + return error; + + for (i = 0; dcdbas_bin_attrs[i]; i++) { + error = sysfs_create_bin_file(&dev->dev.kobj, + dcdbas_bin_attrs[i]); + if (error) { + while (--i >= 0) + sysfs_remove_bin_file(&dev->dev.kobj, + dcdbas_bin_attrs[i]); + sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group); + return error; + } + } + register_reboot_notifier(&dcdbas_reboot_nb); + dev_info(&dev->dev, "%s (version %s)\n", + DRIVER_DESCRIPTION, DRIVER_VERSION); + + return 0; +} + +static int __devexit dcdbas_remove(struct platform_device *dev) +{ + int i; + + unregister_reboot_notifier(&dcdbas_reboot_nb); for (i = 0; dcdbas_bin_attrs[i]; i++) - sysfs_create_bin_file(&dcdbas_pdev->dev.kobj, - dcdbas_bin_attrs[i]); + sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]); + sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group); - for (i = 0; dcdbas_dev_attrs[i]; i++) - device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]); + return 0; +} - dev_info(&dcdbas_pdev->dev, "%s (version %s)\n", - DRIVER_DESCRIPTION, DRIVER_VERSION); +static struct platform_driver dcdbas_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = dcdbas_probe, + .remove = __devexit_p(dcdbas_remove), +}; + +/** + * dcdbas_init: initialize driver + */ +static int __init dcdbas_init(void) +{ + int error; + + error = platform_driver_register(&dcdbas_driver); + if (error) + return error; + + dcdbas_pdev = platform_device_alloc(DRIVER_NAME, -1); + if (!dcdbas_pdev) { + error = -ENOMEM; + goto err_unregister_driver; + } + + error = platform_device_add(dcdbas_pdev); + if (error) + goto err_free_device; return 0; + + err_free_device: + platform_device_put(dcdbas_pdev); + err_unregister_driver: + platform_driver_unregister(&dcdbas_driver); + return error; } /** @@ -588,6 +645,15 @@ static void __exit dcdbas_exit(void) unregister_reboot_notifier(&dcdbas_reboot_nb); smi_data_buf_free(); platform_device_unregister(dcdbas_pdev); + platform_driver_unregister(&dcdbas_driver); + + /* + * We have to free the buffer here instead of dcdbas_remove + * because only in module exit function we can be sure that + * all sysfs attributes belonging to this module have been + * released. + */ + smi_data_buf_free(); } module_init(dcdbas_init); |