diff options
Diffstat (limited to 'drivers/misc/sony-laptop.c')
-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 e67189a361a2..2d05d5b7e125 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -54,6 +54,64 @@ module_param(debug, int, 0); | |||
54 | MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " | 54 | MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " |
55 | "the development of this driver"); | 55 | "the development of this driver"); |
56 | 56 | ||
57 | /*********** Platform Device ***********/ | ||
58 | |||
59 | static atomic_t sony_pf_users = ATOMIC_INIT(0); | ||
60 | static struct platform_driver sony_pf_driver = { | ||
61 | .driver = { | ||
62 | .name = "sony-laptop", | ||
63 | .owner = THIS_MODULE, | ||
64 | } | ||
65 | }; | ||
66 | static struct platform_device *sony_pf_device; | ||
67 | |||
68 | static int sony_pf_add(void) | ||
69 | { | ||
70 | int ret = 0; | ||
71 | |||
72 | /* don't run again if already initialized */ | ||
73 | if (atomic_add_return(1, &sony_pf_users) > 1) | ||
74 | return 0; | ||
75 | |||
76 | ret = platform_driver_register(&sony_pf_driver); | ||
77 | if (ret) | ||
78 | goto out; | ||
79 | |||
80 | sony_pf_device = platform_device_alloc("sony-laptop", -1); | ||
81 | if (!sony_pf_device) { | ||
82 | ret = -ENOMEM; | ||
83 | goto out_platform_registered; | ||
84 | } | ||
85 | |||
86 | ret = platform_device_add(sony_pf_device); | ||
87 | if (ret) | ||
88 | goto out_platform_alloced; | ||
89 | |||
90 | return 0; | ||
91 | |||
92 | out_platform_alloced: | ||
93 | platform_device_put(sony_pf_device); | ||
94 | sony_pf_device = NULL; | ||
95 | out_platform_registered: | ||
96 | platform_driver_unregister(&sony_pf_driver); | ||
97 | out: | ||
98 | atomic_dec(&sony_pf_users); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static void sony_pf_remove(void) | ||
103 | { | ||
104 | /* deregister only after the last user has gone */ | ||
105 | if (!atomic_dec_and_test(&sony_pf_users)) | ||
106 | return; | ||
107 | |||
108 | platform_device_del(sony_pf_device); | ||
109 | platform_device_put(sony_pf_device); | ||
110 | platform_driver_unregister(&sony_pf_driver); | ||
111 | } | ||
112 | |||
113 | /*********** SNC (SNY5001) Device ***********/ | ||
114 | |||
57 | static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, | 115 | static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, |
58 | char *); | 116 | char *); |
59 | static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, | 117 | 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, | |||
279 | return count; | 337 | return count; |
280 | } | 338 | } |
281 | 339 | ||
282 | /* | ||
283 | * Platform device | ||
284 | */ | ||
285 | static struct platform_driver sncpf_driver = { | ||
286 | .driver = { | ||
287 | .name = "sony-laptop", | ||
288 | .owner = THIS_MODULE, | ||
289 | } | ||
290 | }; | ||
291 | static struct platform_device *sncpf_device; | ||
292 | |||
293 | static int sony_nc_pf_add(void) | ||
294 | { | ||
295 | acpi_handle handle; | ||
296 | struct sony_nc_value *item; | ||
297 | int ret = 0; | ||
298 | |||
299 | ret = platform_driver_register(&sncpf_driver); | ||
300 | if (ret) | ||
301 | goto out; | ||
302 | |||
303 | sncpf_device = platform_device_alloc("sony-laptop", -1); | ||
304 | if (!sncpf_device) { | ||
305 | ret = -ENOMEM; | ||
306 | goto out_platform_registered; | ||
307 | } | ||
308 | |||
309 | ret = platform_device_add(sncpf_device); | ||
310 | if (ret) | ||
311 | goto out_platform_alloced; | ||
312 | |||
313 | for (item = sony_nc_values; item->name; ++item) { | ||
314 | |||
315 | if (!debug && item->debug) | ||
316 | continue; | ||
317 | |||
318 | /* find the available acpiget as described in the DSDT */ | ||
319 | for (; item->acpiget && *item->acpiget; ++item->acpiget) { | ||
320 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | ||
321 | *item->acpiget, | ||
322 | &handle))) { | ||
323 | if (debug) | ||
324 | printk(LOG_PFX "Found %s getter: %s\n", | ||
325 | item->name, *item->acpiget); | ||
326 | item->devattr.attr.mode |= S_IRUGO; | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /* find the available acpiset as described in the DSDT */ | ||
332 | for (; item->acpiset && *item->acpiset; ++item->acpiset) { | ||
333 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | ||
334 | *item->acpiset, | ||
335 | &handle))) { | ||
336 | if (debug) | ||
337 | printk(LOG_PFX "Found %s setter: %s\n", | ||
338 | item->name, *item->acpiset); | ||
339 | item->devattr.attr.mode |= S_IWUSR; | ||
340 | break; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | if (item->devattr.attr.mode != 0) { | ||
345 | ret = | ||
346 | device_create_file(&sncpf_device->dev, | ||
347 | &item->devattr); | ||
348 | if (ret) | ||
349 | goto out_sysfs; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | |||
355 | out_sysfs: | ||
356 | for (item = sony_nc_values; item->name; ++item) { | ||
357 | device_remove_file(&sncpf_device->dev, &item->devattr); | ||
358 | } | ||
359 | platform_device_del(sncpf_device); | ||
360 | out_platform_alloced: | ||
361 | platform_device_put(sncpf_device); | ||
362 | out_platform_registered: | ||
363 | platform_driver_unregister(&sncpf_driver); | ||
364 | out: | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | static void sony_nc_pf_remove(void) | ||
369 | { | ||
370 | struct sony_nc_value *item; | ||
371 | |||
372 | for (item = sony_nc_values; item->name; ++item) { | ||
373 | device_remove_file(&sncpf_device->dev, &item->devattr); | ||
374 | } | ||
375 | |||
376 | platform_device_del(sncpf_device); | ||
377 | platform_device_put(sncpf_device); | ||
378 | platform_driver_unregister(&sncpf_driver); | ||
379 | } | ||
380 | 340 | ||
381 | /* | 341 | /* |
382 | * Backlight device | 342 | * Backlight device |
@@ -455,6 +415,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
455 | acpi_status status; | 415 | acpi_status status; |
456 | int result = 0; | 416 | int result = 0; |
457 | acpi_handle handle; | 417 | acpi_handle handle; |
418 | struct sony_nc_value *item; | ||
458 | 419 | ||
459 | sony_nc_acpi_device = device; | 420 | sony_nc_acpi_device = device; |
460 | 421 | ||
@@ -497,13 +458,59 @@ static int sony_nc_add(struct acpi_device *device) | |||
497 | 458 | ||
498 | } | 459 | } |
499 | 460 | ||
500 | if (sony_nc_pf_add()) | 461 | if (sony_pf_add()) |
501 | goto outbacklight; | 462 | goto outbacklight; |
502 | 463 | ||
464 | /* create sony_pf sysfs attributes related to the SNC device */ | ||
465 | for (item = sony_nc_values; item->name; ++item) { | ||
466 | |||
467 | if (!debug && item->debug) | ||
468 | continue; | ||
469 | |||
470 | /* find the available acpiget as described in the DSDT */ | ||
471 | for (; item->acpiget && *item->acpiget; ++item->acpiget) { | ||
472 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | ||
473 | *item->acpiget, | ||
474 | &handle))) { | ||
475 | if (debug) | ||
476 | printk(LOG_PFX "Found %s getter: %s\n", | ||
477 | item->name, *item->acpiget); | ||
478 | item->devattr.attr.mode |= S_IRUGO; | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* find the available acpiset as described in the DSDT */ | ||
484 | for (; item->acpiset && *item->acpiset; ++item->acpiset) { | ||
485 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, | ||
486 | *item->acpiset, | ||
487 | &handle))) { | ||
488 | if (debug) | ||
489 | printk(LOG_PFX "Found %s setter: %s\n", | ||
490 | item->name, *item->acpiset); | ||
491 | item->devattr.attr.mode |= S_IWUSR; | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | if (item->devattr.attr.mode != 0) { | ||
497 | result = | ||
498 | device_create_file(&sony_pf_device->dev, | ||
499 | &item->devattr); | ||
500 | if (result) | ||
501 | goto out_sysfs; | ||
502 | } | ||
503 | } | ||
504 | |||
503 | printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully installed\n"); | 505 | printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully installed\n"); |
504 | 506 | ||
505 | return 0; | 507 | return 0; |
506 | 508 | ||
509 | out_sysfs: | ||
510 | for (item = sony_nc_values; item->name; ++item) { | ||
511 | device_remove_file(&sony_pf_device->dev, &item->devattr); | ||
512 | } | ||
513 | sony_pf_remove(); | ||
507 | outbacklight: | 514 | outbacklight: |
508 | if (sony_backlight_device) | 515 | if (sony_backlight_device) |
509 | backlight_device_unregister(sony_backlight_device); | 516 | backlight_device_unregister(sony_backlight_device); |
@@ -520,6 +527,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
520 | static int sony_nc_remove(struct acpi_device *device, int type) | 527 | static int sony_nc_remove(struct acpi_device *device, int type) |
521 | { | 528 | { |
522 | acpi_status status; | 529 | acpi_status status; |
530 | struct sony_nc_value *item; | ||
523 | 531 | ||
524 | if (sony_backlight_device) | 532 | if (sony_backlight_device) |
525 | backlight_device_unregister(sony_backlight_device); | 533 | backlight_device_unregister(sony_backlight_device); |
@@ -532,7 +540,11 @@ static int sony_nc_remove(struct acpi_device *device, int type) | |||
532 | if (ACPI_FAILURE(status)) | 540 | if (ACPI_FAILURE(status)) |
533 | printk(LOG_PFX "unable to remove notify handler\n"); | 541 | printk(LOG_PFX "unable to remove notify handler\n"); |
534 | 542 | ||
535 | sony_nc_pf_remove(); | 543 | for (item = sony_nc_values; item->name; ++item) { |
544 | device_remove_file(&sony_pf_device->dev, &item->devattr); | ||
545 | } | ||
546 | |||
547 | sony_pf_remove(); | ||
536 | 548 | ||
537 | printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n"); | 549 | printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n"); |
538 | 550 | ||