2 * Asus Wireless Radio Control Driver
4 * Copyright (C) 2015-2016 Endless Mobile, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/types.h>
15 #include <linux/acpi.h>
16 #include <linux/input.h>
17 #include <linux/pci_ids.h>
18 #include <linux/leds.h>
20 #define ASUS_WIRELESS_LED_STATUS 0x2
21 #define ASUS_WIRELESS_LED_OFF 0x4
22 #define ASUS_WIRELESS_LED_ON 0x5
24 struct asus_wireless_data
{
25 struct input_dev
*idev
;
26 struct acpi_device
*adev
;
27 struct workqueue_struct
*wq
;
28 struct work_struct led_work
;
29 struct led_classdev led
;
33 static u64
asus_wireless_method(acpi_handle handle
, const char *method
,
36 struct acpi_object_list p
;
37 union acpi_object obj
;
41 acpi_handle_debug(handle
, "Evaluating method %s, parameter %#x\n",
43 obj
.type
= ACPI_TYPE_INTEGER
;
44 obj
.integer
.value
= param
;
48 s
= acpi_evaluate_integer(handle
, (acpi_string
) method
, &p
, &ret
);
50 acpi_handle_err(handle
,
51 "Failed to eval method %s, param %#x (%d)\n",
53 acpi_handle_debug(handle
, "%s returned %#x\n", method
, (uint
) ret
);
57 static enum led_brightness
led_state_get(struct led_classdev
*led
)
59 struct asus_wireless_data
*data
;
62 data
= container_of(led
, struct asus_wireless_data
, led
);
63 s
= asus_wireless_method(acpi_device_handle(data
->adev
), "HSWC",
64 ASUS_WIRELESS_LED_STATUS
);
65 if (s
== ASUS_WIRELESS_LED_ON
)
70 static void led_state_update(struct work_struct
*work
)
72 struct asus_wireless_data
*data
;
74 data
= container_of(work
, struct asus_wireless_data
, led_work
);
75 asus_wireless_method(acpi_device_handle(data
->adev
), "HSWC",
79 static void led_state_set(struct led_classdev
*led
,
80 enum led_brightness value
)
82 struct asus_wireless_data
*data
;
84 data
= container_of(led
, struct asus_wireless_data
, led
);
85 data
->led_state
= value
== LED_OFF
? ASUS_WIRELESS_LED_OFF
:
87 queue_work(data
->wq
, &data
->led_work
);
90 static void asus_wireless_notify(struct acpi_device
*adev
, u32 event
)
92 struct asus_wireless_data
*data
= acpi_driver_data(adev
);
94 dev_dbg(&adev
->dev
, "event=%#x\n", event
);
96 dev_notice(&adev
->dev
, "Unknown ASHS event: %#x\n", event
);
99 input_report_key(data
->idev
, KEY_RFKILL
, 1);
100 input_report_key(data
->idev
, KEY_RFKILL
, 0);
101 input_sync(data
->idev
);
104 static int asus_wireless_add(struct acpi_device
*adev
)
106 struct asus_wireless_data
*data
;
109 data
= devm_kzalloc(&adev
->dev
, sizeof(*data
), GFP_KERNEL
);
112 adev
->driver_data
= data
;
114 data
->idev
= devm_input_allocate_device(&adev
->dev
);
117 data
->idev
->name
= "Asus Wireless Radio Control";
118 data
->idev
->phys
= "asus-wireless/input0";
119 data
->idev
->id
.bustype
= BUS_HOST
;
120 data
->idev
->id
.vendor
= PCI_VENDOR_ID_ASUSTEK
;
121 set_bit(EV_KEY
, data
->idev
->evbit
);
122 set_bit(KEY_RFKILL
, data
->idev
->keybit
);
123 err
= input_register_device(data
->idev
);
128 data
->wq
= create_singlethread_workqueue("asus_wireless_workqueue");
131 INIT_WORK(&data
->led_work
, led_state_update
);
132 data
->led
.name
= "asus-wireless::airplane";
133 data
->led
.brightness_set
= led_state_set
;
134 data
->led
.brightness_get
= led_state_get
;
135 data
->led
.flags
= LED_CORE_SUSPENDRESUME
;
136 data
->led
.max_brightness
= 1;
137 err
= devm_led_classdev_register(&adev
->dev
, &data
->led
);
139 destroy_workqueue(data
->wq
);
143 static int asus_wireless_remove(struct acpi_device
*adev
)
145 struct asus_wireless_data
*data
= acpi_driver_data(adev
);
148 destroy_workqueue(data
->wq
);
152 static const struct acpi_device_id device_ids
[] = {
157 MODULE_DEVICE_TABLE(acpi
, device_ids
);
159 static struct acpi_driver asus_wireless_driver
= {
160 .name
= "Asus Wireless Radio Control Driver",
164 .add
= asus_wireless_add
,
165 .remove
= asus_wireless_remove
,
166 .notify
= asus_wireless_notify
,
169 module_acpi_driver(asus_wireless_driver
);
171 MODULE_DESCRIPTION("Asus Wireless Radio Control Driver");
172 MODULE_AUTHOR("João Paulo Rechi Vita <jprvita@gmail.com>");
173 MODULE_LICENSE("GPL");