aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@holoscopio.com>2010-04-27 12:15:00 -0400
committerMatthew Garrett <mjg@redhat.com>2010-05-17 12:06:01 -0400
commitd5c051f1080e0eec55f3fc42c37d941681941628 (patch)
tree2851e28345f99f7f45a62932b1b8274caaa3a342
parente40152ee1e1c7a63f4777791863215e3faa37a86 (diff)
classmate-laptop: Add RFKILL support.
The RFKILL device shares the same ACPI device used for backlight. So, it required a new struct sharing both a backlight_device and a rfkill device. Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
-rw-r--r--drivers/platform/x86/classmate-laptop.c170
1 files changed, 148 insertions, 22 deletions
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 7f9e5ddc9498..3bf399fe2bbc 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -24,6 +24,7 @@
24#include <acpi/acpi_drivers.h> 24#include <acpi/acpi_drivers.h>
25#include <linux/backlight.h> 25#include <linux/backlight.h>
26#include <linux/input.h> 26#include <linux/input.h>
27#include <linux/rfkill.h>
27 28
28MODULE_LICENSE("GPL"); 29MODULE_LICENSE("GPL");
29 30
@@ -37,7 +38,7 @@ struct cmpc_accel {
37 38
38#define CMPC_ACCEL_HID "ACCE0000" 39#define CMPC_ACCEL_HID "ACCE0000"
39#define CMPC_TABLET_HID "TBLT0000" 40#define CMPC_TABLET_HID "TBLT0000"
40#define CMPC_BL_HID "IPML200" 41#define CMPC_IPML_HID "IPML200"
41#define CMPC_KEYS_HID "FnBT0000" 42#define CMPC_KEYS_HID "FnBT0000"
42 43
43/* 44/*
@@ -461,43 +462,168 @@ static const struct backlight_ops cmpc_bl_ops = {
461 .update_status = cmpc_bl_update_status 462 .update_status = cmpc_bl_update_status
462}; 463};
463 464
464static int cmpc_bl_add(struct acpi_device *acpi) 465/*
466 * RFKILL code.
467 */
468
469static acpi_status cmpc_get_rfkill_wlan(acpi_handle handle,
470 unsigned long long *value)
465{ 471{
466 struct backlight_properties props; 472 union acpi_object param;
473 struct acpi_object_list input;
474 unsigned long long output;
475 acpi_status status;
476
477 param.type = ACPI_TYPE_INTEGER;
478 param.integer.value = 0xC1;
479 input.count = 1;
480 input.pointer = &param;
481 status = acpi_evaluate_integer(handle, "GRDI", &input, &output);
482 if (ACPI_SUCCESS(status))
483 *value = output;
484 return status;
485}
486
487static acpi_status cmpc_set_rfkill_wlan(acpi_handle handle,
488 unsigned long long value)
489{
490 union acpi_object param[2];
491 struct acpi_object_list input;
492 acpi_status status;
493 unsigned long long output;
494
495 param[0].type = ACPI_TYPE_INTEGER;
496 param[0].integer.value = 0xC1;
497 param[1].type = ACPI_TYPE_INTEGER;
498 param[1].integer.value = value;
499 input.count = 2;
500 input.pointer = param;
501 status = acpi_evaluate_integer(handle, "GWRI", &input, &output);
502 return status;
503}
504
505static void cmpc_rfkill_query(struct rfkill *rfkill, void *data)
506{
507 acpi_status status;
508 acpi_handle handle;
509 unsigned long long state;
510 bool blocked;
511
512 handle = data;
513 status = cmpc_get_rfkill_wlan(handle, &state);
514 if (ACPI_SUCCESS(status)) {
515 blocked = state & 1 ? false : true;
516 rfkill_set_sw_state(rfkill, blocked);
517 }
518}
519
520static int cmpc_rfkill_block(void *data, bool blocked)
521{
522 acpi_status status;
523 acpi_handle handle;
524 unsigned long long state;
525
526 handle = data;
527 status = cmpc_get_rfkill_wlan(handle, &state);
528 if (ACPI_FAILURE(status))
529 return -ENODEV;
530 if (blocked)
531 state &= ~1;
532 else
533 state |= 1;
534 status = cmpc_set_rfkill_wlan(handle, state);
535 if (ACPI_FAILURE(status))
536 return -ENODEV;
537 return 0;
538}
539
540static const struct rfkill_ops cmpc_rfkill_ops = {
541 .query = cmpc_rfkill_query,
542 .set_block = cmpc_rfkill_block,
543};
544
545/*
546 * Common backlight and rfkill code.
547 */
548
549struct ipml200_dev {
467 struct backlight_device *bd; 550 struct backlight_device *bd;
551 struct rfkill *rf;
552};
553
554static int cmpc_ipml_add(struct acpi_device *acpi)
555{
556 int retval;
557 struct ipml200_dev *ipml;
558 struct backlight_properties props;
559
560 ipml = kmalloc(sizeof(*ipml), GFP_KERNEL);
561 if (ipml == NULL)
562 return -ENOMEM;
468 563
469 memset(&props, 0, sizeof(struct backlight_properties)); 564 memset(&props, 0, sizeof(struct backlight_properties));
470 props.max_brightness = 7; 565 props.max_brightness = 7;
471 bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle, 566 ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev,
472 &cmpc_bl_ops, &props); 567 acpi->handle, &cmpc_bl_ops,
473 if (IS_ERR(bd)) 568 &props);
474 return PTR_ERR(bd); 569 if (IS_ERR(ipml->bd)) {
475 dev_set_drvdata(&acpi->dev, bd); 570 retval = PTR_ERR(ipml->bd);
571 goto out_bd;
572 }
573
574 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN,
575 &cmpc_rfkill_ops, acpi->handle);
576 /* rfkill_alloc may fail if RFKILL is disabled. We should still work
577 * anyway. */
578 if (!IS_ERR(ipml->rf)) {
579 retval = rfkill_register(ipml->rf);
580 if (retval) {
581 rfkill_destroy(ipml->rf);
582 ipml->rf = NULL;
583 }
584 } else {
585 ipml->rf = NULL;
586 }
587
588 dev_set_drvdata(&acpi->dev, ipml);
476 return 0; 589 return 0;
590
591out_bd:
592 kfree(ipml);
593 return retval;
477} 594}
478 595
479static int cmpc_bl_remove(struct acpi_device *acpi, int type) 596static int cmpc_ipml_remove(struct acpi_device *acpi, int type)
480{ 597{
481 struct backlight_device *bd; 598 struct ipml200_dev *ipml;
599
600 ipml = dev_get_drvdata(&acpi->dev);
601
602 backlight_device_unregister(ipml->bd);
603
604 if (ipml->rf) {
605 rfkill_unregister(ipml->rf);
606 rfkill_destroy(ipml->rf);
607 }
608
609 kfree(ipml);
482 610
483 bd = dev_get_drvdata(&acpi->dev);
484 backlight_device_unregister(bd);
485 return 0; 611 return 0;
486} 612}
487 613
488static const struct acpi_device_id cmpc_bl_device_ids[] = { 614static const struct acpi_device_id cmpc_ipml_device_ids[] = {
489 {CMPC_BL_HID, 0}, 615 {CMPC_IPML_HID, 0},
490 {"", 0} 616 {"", 0}
491}; 617};
492 618
493static struct acpi_driver cmpc_bl_acpi_driver = { 619static struct acpi_driver cmpc_ipml_acpi_driver = {
494 .owner = THIS_MODULE, 620 .owner = THIS_MODULE,
495 .name = "cmpc", 621 .name = "cmpc",
496 .class = "cmpc", 622 .class = "cmpc",
497 .ids = cmpc_bl_device_ids, 623 .ids = cmpc_ipml_device_ids,
498 .ops = { 624 .ops = {
499 .add = cmpc_bl_add, 625 .add = cmpc_ipml_add,
500 .remove = cmpc_bl_remove 626 .remove = cmpc_ipml_remove
501 } 627 }
502}; 628};
503 629
@@ -580,7 +706,7 @@ static int cmpc_init(void)
580 if (r) 706 if (r)
581 goto failed_keys; 707 goto failed_keys;
582 708
583 r = acpi_bus_register_driver(&cmpc_bl_acpi_driver); 709 r = acpi_bus_register_driver(&cmpc_ipml_acpi_driver);
584 if (r) 710 if (r)
585 goto failed_bl; 711 goto failed_bl;
586 712
@@ -598,7 +724,7 @@ failed_accel:
598 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); 724 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
599 725
600failed_tablet: 726failed_tablet:
601 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver); 727 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
602 728
603failed_bl: 729failed_bl:
604 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); 730 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
@@ -611,7 +737,7 @@ static void cmpc_exit(void)
611{ 737{
612 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver); 738 acpi_bus_unregister_driver(&cmpc_accel_acpi_driver);
613 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver); 739 acpi_bus_unregister_driver(&cmpc_tablet_acpi_driver);
614 acpi_bus_unregister_driver(&cmpc_bl_acpi_driver); 740 acpi_bus_unregister_driver(&cmpc_ipml_acpi_driver);
615 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver); 741 acpi_bus_unregister_driver(&cmpc_keys_acpi_driver);
616} 742}
617 743
@@ -621,7 +747,7 @@ module_exit(cmpc_exit);
621static const struct acpi_device_id cmpc_device_ids[] = { 747static const struct acpi_device_id cmpc_device_ids[] = {
622 {CMPC_ACCEL_HID, 0}, 748 {CMPC_ACCEL_HID, 0},
623 {CMPC_TABLET_HID, 0}, 749 {CMPC_TABLET_HID, 0},
624 {CMPC_BL_HID, 0}, 750 {CMPC_IPML_HID, 0},
625 {CMPC_KEYS_HID, 0}, 751 {CMPC_KEYS_HID, 0},
626 {"", 0} 752 {"", 0}
627}; 753};