|
@@ -17,19 +17,41 @@
|
|
|
#include <linux/pci_ids.h>
|
|
|
#include <linux/leds.h>
|
|
|
|
|
|
-#define ASUS_WIRELESS_LED_STATUS 0x2
|
|
|
-#define ASUS_WIRELESS_LED_OFF 0x4
|
|
|
-#define ASUS_WIRELESS_LED_ON 0x5
|
|
|
+struct hswc_params {
|
|
|
+ u8 on;
|
|
|
+ u8 off;
|
|
|
+ u8 status;
|
|
|
+};
|
|
|
|
|
|
struct asus_wireless_data {
|
|
|
struct input_dev *idev;
|
|
|
struct acpi_device *adev;
|
|
|
+ const struct hswc_params *hswc_params;
|
|
|
struct workqueue_struct *wq;
|
|
|
struct work_struct led_work;
|
|
|
struct led_classdev led;
|
|
|
int led_state;
|
|
|
};
|
|
|
|
|
|
+static const struct hswc_params atk4001_id_params = {
|
|
|
+ .on = 0x0,
|
|
|
+ .off = 0x1,
|
|
|
+ .status = 0x2,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct hswc_params atk4002_id_params = {
|
|
|
+ .on = 0x5,
|
|
|
+ .off = 0x4,
|
|
|
+ .status = 0x2,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct acpi_device_id device_ids[] = {
|
|
|
+ {"ATK4001", (kernel_ulong_t)&atk4001_id_params},
|
|
|
+ {"ATK4002", (kernel_ulong_t)&atk4002_id_params},
|
|
|
+ {"", 0},
|
|
|
+};
|
|
|
+MODULE_DEVICE_TABLE(acpi, device_ids);
|
|
|
+
|
|
|
static u64 asus_wireless_method(acpi_handle handle, const char *method,
|
|
|
int param)
|
|
|
{
|
|
@@ -61,8 +83,8 @@ static enum led_brightness led_state_get(struct led_classdev *led)
|
|
|
|
|
|
data = container_of(led, struct asus_wireless_data, led);
|
|
|
s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
|
|
|
- ASUS_WIRELESS_LED_STATUS);
|
|
|
- if (s == ASUS_WIRELESS_LED_ON)
|
|
|
+ data->hswc_params->status);
|
|
|
+ if (s == data->hswc_params->on)
|
|
|
return LED_FULL;
|
|
|
return LED_OFF;
|
|
|
}
|
|
@@ -82,8 +104,8 @@ static void led_state_set(struct led_classdev *led,
|
|
|
struct asus_wireless_data *data;
|
|
|
|
|
|
data = container_of(led, struct asus_wireless_data, led);
|
|
|
- data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF :
|
|
|
- ASUS_WIRELESS_LED_ON;
|
|
|
+ data->led_state = value == LED_OFF ? data->hswc_params->off :
|
|
|
+ data->hswc_params->on;
|
|
|
queue_work(data->wq, &data->led_work);
|
|
|
}
|
|
|
|
|
@@ -104,12 +126,14 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event)
|
|
|
static int asus_wireless_add(struct acpi_device *adev)
|
|
|
{
|
|
|
struct asus_wireless_data *data;
|
|
|
+ const struct acpi_device_id *id;
|
|
|
int err;
|
|
|
|
|
|
data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
|
|
|
if (!data)
|
|
|
return -ENOMEM;
|
|
|
adev->driver_data = data;
|
|
|
+ data->adev = adev;
|
|
|
|
|
|
data->idev = devm_input_allocate_device(&adev->dev);
|
|
|
if (!data->idev)
|
|
@@ -124,7 +148,16 @@ static int asus_wireless_add(struct acpi_device *adev)
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
- data->adev = adev;
|
|
|
+ for (id = device_ids; id->id[0]; id++) {
|
|
|
+ if (!strcmp((char *) id->id, acpi_device_hid(adev))) {
|
|
|
+ data->hswc_params =
|
|
|
+ (const struct hswc_params *)id->driver_data;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!data->hswc_params)
|
|
|
+ return 0;
|
|
|
+
|
|
|
data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
|
|
|
if (!data->wq)
|
|
|
return -ENOMEM;
|
|
@@ -137,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev)
|
|
|
err = devm_led_classdev_register(&adev->dev, &data->led);
|
|
|
if (err)
|
|
|
destroy_workqueue(data->wq);
|
|
|
+
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -149,13 +183,6 @@ static int asus_wireless_remove(struct acpi_device *adev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static const struct acpi_device_id device_ids[] = {
|
|
|
- {"ATK4001", 0},
|
|
|
- {"ATK4002", 0},
|
|
|
- {"", 0},
|
|
|
-};
|
|
|
-MODULE_DEVICE_TABLE(acpi, device_ids);
|
|
|
-
|
|
|
static struct acpi_driver asus_wireless_driver = {
|
|
|
.name = "Asus Wireless Radio Control Driver",
|
|
|
.class = "hotkey",
|