diff options
-rw-r--r-- | drivers/misc/sony-laptop.c | 212 |
1 files changed, 112 insertions, 100 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index e67189a361a..2d05d5b7e12 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -54,6 +54,64 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " "the development of this driver"); +/*********** Platform Device ***********/ + +static atomic_t sony_pf_users = ATOMIC_INIT(0); +static struct platform_driver sony_pf_driver = { + .driver = { + .name = "sony-laptop", + .owner = THIS_MODULE, + } +}; +static struct platform_device *sony_pf_device; + +static int sony_pf_add(void) +{ + int ret = 0; + + /* don't run again if already initialized */ + if (atomic_add_return(1, &sony_pf_users) > 1) + return 0; + + ret = platform_driver_register(&sony_pf_driver); + if (ret) + goto out; + + sony_pf_device = platform_device_alloc("sony-laptop", -1); + if (!sony_pf_device) { + ret = -ENOMEM; + goto out_platform_registered; + } + + ret = platform_device_add(sony_pf_device); + if (ret) + goto out_platform_alloced; + + return 0; + + out_platform_alloced: + platform_device_put(sony_pf_device); + sony_pf_device = NULL; + out_platform_registered: + platform_driver_unregister(&sony_pf_driver); + out: + atomic_dec(&sony_pf_users); + return ret; +} + +static void sony_pf_remove(void) +{ + /* deregister only after the last user has gone */ + if (!atomic_dec_and_test(&sony_pf_users)) + return; + + platform_device_del(sony_pf_device); + platform_device_put(sony_pf_device); + platform_driver_unregister(&sony_pf_driver); +} + +/*********** SNC (SNY5001) Device ***********/ + static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, char *); static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, @@ -279,104 +337,6 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, return count; } -/* - * Platform device - */ -static struct platform_driver sncpf_driver = { - .driver = { - .name = "sony-laptop", - .owner = THIS_MODULE, - } -}; -static struct platform_device *sncpf_device; - -static int sony_nc_pf_add(void) -{ - acpi_handle handle; - struct sony_nc_value *item; - int ret = 0; - - ret = platform_driver_register(&sncpf_driver); - if (ret) - goto out; - - sncpf_device = platform_device_alloc("sony-laptop", -1); - if (!sncpf_device) { - ret = -ENOMEM; - goto out_platform_registered; - } - - ret = platform_device_add(sncpf_device); - if (ret) - goto out_platform_alloced; - - for (item = sony_nc_values; item->name; ++item) { - - if (!debug && item->debug) - continue; - - /* find the available acpiget as described in the DSDT */ - for (; item->acpiget && *item->acpiget; ++item->acpiget) { - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, - *item->acpiget, - &handle))) { - if (debug) - printk(LOG_PFX "Found %s getter: %s\n", - item->name, *item->acpiget); - item->devattr.attr.mode |= S_IRUGO; - break; - } - } - - /* find the available acpiset as described in the DSDT */ - for (; item->acpiset && *item->acpiset; ++item->acpiset) { - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, - *item->acpiset, - &handle))) { - if (debug) - printk(LOG_PFX "Found %s setter: %s\n", - item->name, *item->acpiset); - item->devattr.attr.mode |= S_IWUSR; - break; - } - } - - if (item->devattr.attr.mode != 0) { - ret = - device_create_file(&sncpf_device->dev, - &item->devattr); - if (ret) - goto out_sysfs; - } - } - - return 0; - - out_sysfs: - for (item = sony_nc_values; item->name; ++item) { - device_remove_file(&sncpf_device->dev, &item->devattr); - } - platform_device_del(sncpf_device); - out_platform_alloced: - platform_device_put(sncpf_device); - out_platform_registered: - platform_driver_unregister(&sncpf_driver); - out: - return ret; -} - -static void sony_nc_pf_remove(void) -{ - struct sony_nc_value *item; - - for (item = sony_nc_values; item->name; ++item) { - device_remove_file(&sncpf_device->dev, &item->devattr); - } - - platform_device_del(sncpf_device); - platform_device_put(sncpf_device); - platform_driver_unregister(&sncpf_driver); -} /* * Backlight device @@ -455,6 +415,7 @@ static int sony_nc_add(struct acpi_device *device) acpi_status status; int result = 0; acpi_handle handle; + struct sony_nc_value *item; sony_nc_acpi_device = device; @@ -497,13 +458,59 @@ static int sony_nc_add(struct acpi_device *device) } - if (sony_nc_pf_add()) + if (sony_pf_add()) goto outbacklight; + /* create sony_pf sysfs attributes related to the SNC device */ + for (item = sony_nc_values; item->name; ++item) { + + if (!debug && item->debug) + continue; + + /* find the available acpiget as described in the DSDT */ + for (; item->acpiget && *item->acpiget; ++item->acpiget) { + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, + *item->acpiget, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s getter: %s\n", + item->name, *item->acpiget); + item->devattr.attr.mode |= S_IRUGO; + break; + } + } + + /* find the available acpiset as described in the DSDT */ + for (; item->acpiset && *item->acpiset; ++item->acpiset) { + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, + *item->acpiset, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s setter: %s\n", + item->name, *item->acpiset); + item->devattr.attr.mode |= S_IWUSR; + break; + } + } + + if (item->devattr.attr.mode != 0) { + result = + device_create_file(&sony_pf_device->dev, + &item->devattr); + if (result) + goto out_sysfs; + } + } + printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully installed\n"); return 0; + out_sysfs: + for (item = sony_nc_values; item->name; ++item) { + device_remove_file(&sony_pf_device->dev, &item->devattr); + } + sony_pf_remove(); outbacklight: if (sony_backlight_device) backlight_device_unregister(sony_backlight_device); @@ -520,6 +527,7 @@ static int sony_nc_add(struct acpi_device *device) static int sony_nc_remove(struct acpi_device *device, int type) { acpi_status status; + struct sony_nc_value *item; if (sony_backlight_device) backlight_device_unregister(sony_backlight_device); @@ -532,7 +540,11 @@ static int sony_nc_remove(struct acpi_device *device, int type) if (ACPI_FAILURE(status)) printk(LOG_PFX "unable to remove notify handler\n"); - sony_nc_pf_remove(); + for (item = sony_nc_values; item->name; ++item) { + device_remove_file(&sony_pf_device->dev, &item->devattr); + } + + sony_pf_remove(); printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n"); |