Loading drivers/platform/x86/asus-laptop.c +115 −120 Original line number Diff line number Diff line Loading @@ -193,29 +193,12 @@ ASUS_HANDLE(display_get, /* * Define a specific led structure to keep the main structure clean */ #define ASUS_DEFINE_LED(object) \ int object##_wk; \ struct work_struct object##_work; \ struct led_classdev object; #define led_to_asus(led_cdev, led) \ container_of(container_of(led_cdev, struct asus_laptop_leds, \ led), \ struct asus_laptop, leds) #define work_to_asus(work, led) \ container_of(container_of(work, struct asus_laptop_leds, \ led##_work), \ struct asus_laptop, leds) struct asus_laptop_leds { ASUS_DEFINE_LED(mled) ASUS_DEFINE_LED(tled) ASUS_DEFINE_LED(rled) ASUS_DEFINE_LED(pled) ASUS_DEFINE_LED(gled) ASUS_DEFINE_LED(kled) struct workqueue_struct *workqueue; struct asus_led { int wk; struct work_struct work; struct led_classdev led; struct asus_laptop *asus; const char *method; }; /* Loading @@ -233,7 +216,13 @@ struct asus_laptop { struct input_dev *inputdev; struct key_entry *keymap; struct asus_laptop_leds leds; struct asus_led mled; struct asus_led tled; struct asus_led rled; struct asus_led pled; struct asus_led gled; struct asus_led kled; struct workqueue_struct *led_workqueue; int wireless_status; bool have_rsts; Loading Loading @@ -353,7 +342,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method, } /* Generic LED function */ static int asus_led_set(struct asus_laptop *asus, char *method, static int asus_led_set(struct asus_laptop *asus, const char *method, int value) { if (!strcmp(method, METHOD_MLED)) Loading @@ -369,50 +358,29 @@ static int asus_led_set(struct asus_laptop *asus, char *method, /* * LEDs */ #define ASUS_LED(object, ledname, max) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value); \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev); \ static void object##_led_update(struct work_struct *ignored); ASUS_LED(mled, "mail", 1); ASUS_LED(tled, "touchpad", 1); ASUS_LED(rled, "record", 1); ASUS_LED(pled, "phone", 1); ASUS_LED(gled, "gaming", 1); ASUS_LED(kled, "kbd_backlight", 3); /* /sys/class/led handlers */ #define ASUS_LED_HANDLER(object, method) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value) \ { \ struct asus_laptop *asus = \ led_to_asus(led_cdev, object); \ \ asus->leds.object##_wk = (value > 0) ? 1 : 0; \ queue_work(asus->leds.workqueue, \ &asus->leds.object##_work); \ } \ static void object##_led_update(struct work_struct *work) \ { \ struct asus_laptop *asus = work_to_asus(work, object); \ \ int value = asus->leds.object##_wk; \ asus_led_set(asus, method, value); \ } \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev) \ { \ return led_cdev->brightness; \ } ASUS_LED_HANDLER(mled, METHOD_MLED); ASUS_LED_HANDLER(pled, METHOD_PLED); ASUS_LED_HANDLER(rled, METHOD_RLED); ASUS_LED_HANDLER(tled, METHOD_TLED); ASUS_LED_HANDLER(gled, METHOD_GLED); static void asus_led_cdev_set(struct led_classdev *led_cdev, enum led_brightness value) { struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; led->wk = !!value; queue_work(asus->led_workqueue, &led->work); } static void asus_led_cdev_update(struct work_struct *work) { struct asus_led *led = container_of(work, struct asus_led, work); struct asus_laptop *asus = led->asus; asus_led_set(asus, led->method, led->wk); } static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev) { return led_cdev->brightness; } /* * Keyboard backlight (also a LED) Loading Loading @@ -452,70 +420,76 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv) return 0; } static void kled_led_set(struct led_classdev *led_cdev, static void asus_kled_cdev_set(struct led_classdev *led_cdev, enum led_brightness value) { struct asus_laptop *asus = led_to_asus(led_cdev, kled); struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; asus->leds.kled_wk = value; queue_work(asus->leds.workqueue, &asus->leds.kled_work); led->wk = value; queue_work(asus->led_workqueue, &led->work); } static void kled_led_update(struct work_struct *work) static void asus_kled_cdev_update(struct work_struct *work) { struct asus_laptop *asus = work_to_asus(work, kled); struct asus_led *led = container_of(work, struct asus_led, work); struct asus_laptop *asus = led->asus; asus_kled_set(asus, asus->leds.kled_wk); asus_kled_set(asus, led->wk); } static enum led_brightness kled_led_get(struct led_classdev *led_cdev) static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev) { struct asus_laptop *asus = led_to_asus(led_cdev, kled); struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; return asus_kled_lvl(asus); } static void asus_led_exit(struct asus_laptop *asus) { if (asus->leds.mled.dev) led_classdev_unregister(&asus->leds.mled); if (asus->leds.tled.dev) led_classdev_unregister(&asus->leds.tled); if (asus->leds.pled.dev) led_classdev_unregister(&asus->leds.pled); if (asus->leds.rled.dev) led_classdev_unregister(&asus->leds.rled); if (asus->leds.gled.dev) led_classdev_unregister(&asus->leds.gled); if (asus->leds.kled.dev) led_classdev_unregister(&asus->leds.kled); if (asus->leds.workqueue) { destroy_workqueue(asus->leds.workqueue); asus->leds.workqueue = NULL; if (asus->mled.led.dev) led_classdev_unregister(&asus->mled.led); if (asus->tled.led.dev) led_classdev_unregister(&asus->tled.led); if (asus->pled.led.dev) led_classdev_unregister(&asus->pled.led); if (asus->rled.led.dev) led_classdev_unregister(&asus->rled.led); if (asus->gled.led.dev) led_classdev_unregister(&asus->gled.led); if (asus->kled.led.dev) led_classdev_unregister(&asus->kled.led); if (asus->led_workqueue) { destroy_workqueue(asus->led_workqueue); asus->led_workqueue = NULL; } } /* Ugly macro, need to fix that later */ #define ASUS_LED_REGISTER(asus, object, _name, max, method) \ do { \ struct led_classdev *ldev = &asus->leds.object; \ \ if (method && acpi_check_handle(asus->handle, method, NULL)) \ break ; \ \ INIT_WORK(&asus->leds.object##_work, object##_led_update); \ ldev->name = "asus::" _name; \ ldev->brightness_set = object##_led_set; \ ldev->brightness_get = object##_led_get; \ ldev->max_brightness = max; \ rv = led_classdev_register(&asus->platform_device->dev, ldev); \ if (rv) \ goto error; \ } while (0) static int asus_led_register(struct asus_laptop *asus, struct asus_led *led, const char *name, const char *method) { struct led_classdev *led_cdev = &led->led; if (!method || acpi_check_handle(asus->handle, method, NULL)) return 0; /* Led not present */ led->asus = asus; led->method = method; INIT_WORK(&led->work, asus_led_cdev_update); led_cdev->name = name; led_cdev->brightness_set = asus_led_cdev_set; led_cdev->brightness_get = asus_led_cdev_get; led_cdev->max_brightness = 1; return led_classdev_register(&asus->platform_device->dev, led_cdev); } static int asus_led_init(struct asus_laptop *asus) { int rv; int r; /* * Functions that actually update the LED's are called from a Loading @@ -523,22 +497,43 @@ static int asus_led_init(struct asus_laptop *asus) * subsystem asks, we avoid messing with the Asus ACPI stuff during a * potentially bad time, such as a timer interrupt. */ asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->leds.workqueue) asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->led_workqueue) return -ENOMEM; ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED); ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED); ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED); ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED); ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED); r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); if (r) goto error; r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED); if (r) goto error; r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED); if (r) goto error; r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED); if (r) goto error; r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED); if (r) goto error; if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) && !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, NULL); !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) { struct asus_led *led = &asus->kled; struct led_classdev *cdev = &led->led; led->asus = asus; INIT_WORK(&led->work, asus_kled_cdev_update); cdev->name = "asus::kbd_backlight"; cdev->brightness_set = asus_kled_cdev_set; cdev->brightness_get = asus_kled_cdev_get; cdev->max_brightness = 3; r = led_classdev_register(&asus->platform_device->dev, cdev); } error: if (rv) if (r) asus_led_exit(asus); return rv; return r; } /* Loading Loading
drivers/platform/x86/asus-laptop.c +115 −120 Original line number Diff line number Diff line Loading @@ -193,29 +193,12 @@ ASUS_HANDLE(display_get, /* * Define a specific led structure to keep the main structure clean */ #define ASUS_DEFINE_LED(object) \ int object##_wk; \ struct work_struct object##_work; \ struct led_classdev object; #define led_to_asus(led_cdev, led) \ container_of(container_of(led_cdev, struct asus_laptop_leds, \ led), \ struct asus_laptop, leds) #define work_to_asus(work, led) \ container_of(container_of(work, struct asus_laptop_leds, \ led##_work), \ struct asus_laptop, leds) struct asus_laptop_leds { ASUS_DEFINE_LED(mled) ASUS_DEFINE_LED(tled) ASUS_DEFINE_LED(rled) ASUS_DEFINE_LED(pled) ASUS_DEFINE_LED(gled) ASUS_DEFINE_LED(kled) struct workqueue_struct *workqueue; struct asus_led { int wk; struct work_struct work; struct led_classdev led; struct asus_laptop *asus; const char *method; }; /* Loading @@ -233,7 +216,13 @@ struct asus_laptop { struct input_dev *inputdev; struct key_entry *keymap; struct asus_laptop_leds leds; struct asus_led mled; struct asus_led tled; struct asus_led rled; struct asus_led pled; struct asus_led gled; struct asus_led kled; struct workqueue_struct *led_workqueue; int wireless_status; bool have_rsts; Loading Loading @@ -353,7 +342,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method, } /* Generic LED function */ static int asus_led_set(struct asus_laptop *asus, char *method, static int asus_led_set(struct asus_laptop *asus, const char *method, int value) { if (!strcmp(method, METHOD_MLED)) Loading @@ -369,50 +358,29 @@ static int asus_led_set(struct asus_laptop *asus, char *method, /* * LEDs */ #define ASUS_LED(object, ledname, max) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value); \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev); \ static void object##_led_update(struct work_struct *ignored); ASUS_LED(mled, "mail", 1); ASUS_LED(tled, "touchpad", 1); ASUS_LED(rled, "record", 1); ASUS_LED(pled, "phone", 1); ASUS_LED(gled, "gaming", 1); ASUS_LED(kled, "kbd_backlight", 3); /* /sys/class/led handlers */ #define ASUS_LED_HANDLER(object, method) \ static void object##_led_set(struct led_classdev *led_cdev, \ enum led_brightness value) \ { \ struct asus_laptop *asus = \ led_to_asus(led_cdev, object); \ \ asus->leds.object##_wk = (value > 0) ? 1 : 0; \ queue_work(asus->leds.workqueue, \ &asus->leds.object##_work); \ } \ static void object##_led_update(struct work_struct *work) \ { \ struct asus_laptop *asus = work_to_asus(work, object); \ \ int value = asus->leds.object##_wk; \ asus_led_set(asus, method, value); \ } \ static enum led_brightness object##_led_get( \ struct led_classdev *led_cdev) \ { \ return led_cdev->brightness; \ } ASUS_LED_HANDLER(mled, METHOD_MLED); ASUS_LED_HANDLER(pled, METHOD_PLED); ASUS_LED_HANDLER(rled, METHOD_RLED); ASUS_LED_HANDLER(tled, METHOD_TLED); ASUS_LED_HANDLER(gled, METHOD_GLED); static void asus_led_cdev_set(struct led_classdev *led_cdev, enum led_brightness value) { struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; led->wk = !!value; queue_work(asus->led_workqueue, &led->work); } static void asus_led_cdev_update(struct work_struct *work) { struct asus_led *led = container_of(work, struct asus_led, work); struct asus_laptop *asus = led->asus; asus_led_set(asus, led->method, led->wk); } static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev) { return led_cdev->brightness; } /* * Keyboard backlight (also a LED) Loading Loading @@ -452,70 +420,76 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv) return 0; } static void kled_led_set(struct led_classdev *led_cdev, static void asus_kled_cdev_set(struct led_classdev *led_cdev, enum led_brightness value) { struct asus_laptop *asus = led_to_asus(led_cdev, kled); struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; asus->leds.kled_wk = value; queue_work(asus->leds.workqueue, &asus->leds.kled_work); led->wk = value; queue_work(asus->led_workqueue, &led->work); } static void kled_led_update(struct work_struct *work) static void asus_kled_cdev_update(struct work_struct *work) { struct asus_laptop *asus = work_to_asus(work, kled); struct asus_led *led = container_of(work, struct asus_led, work); struct asus_laptop *asus = led->asus; asus_kled_set(asus, asus->leds.kled_wk); asus_kled_set(asus, led->wk); } static enum led_brightness kled_led_get(struct led_classdev *led_cdev) static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev) { struct asus_laptop *asus = led_to_asus(led_cdev, kled); struct asus_led *led = container_of(led_cdev, struct asus_led, led); struct asus_laptop *asus = led->asus; return asus_kled_lvl(asus); } static void asus_led_exit(struct asus_laptop *asus) { if (asus->leds.mled.dev) led_classdev_unregister(&asus->leds.mled); if (asus->leds.tled.dev) led_classdev_unregister(&asus->leds.tled); if (asus->leds.pled.dev) led_classdev_unregister(&asus->leds.pled); if (asus->leds.rled.dev) led_classdev_unregister(&asus->leds.rled); if (asus->leds.gled.dev) led_classdev_unregister(&asus->leds.gled); if (asus->leds.kled.dev) led_classdev_unregister(&asus->leds.kled); if (asus->leds.workqueue) { destroy_workqueue(asus->leds.workqueue); asus->leds.workqueue = NULL; if (asus->mled.led.dev) led_classdev_unregister(&asus->mled.led); if (asus->tled.led.dev) led_classdev_unregister(&asus->tled.led); if (asus->pled.led.dev) led_classdev_unregister(&asus->pled.led); if (asus->rled.led.dev) led_classdev_unregister(&asus->rled.led); if (asus->gled.led.dev) led_classdev_unregister(&asus->gled.led); if (asus->kled.led.dev) led_classdev_unregister(&asus->kled.led); if (asus->led_workqueue) { destroy_workqueue(asus->led_workqueue); asus->led_workqueue = NULL; } } /* Ugly macro, need to fix that later */ #define ASUS_LED_REGISTER(asus, object, _name, max, method) \ do { \ struct led_classdev *ldev = &asus->leds.object; \ \ if (method && acpi_check_handle(asus->handle, method, NULL)) \ break ; \ \ INIT_WORK(&asus->leds.object##_work, object##_led_update); \ ldev->name = "asus::" _name; \ ldev->brightness_set = object##_led_set; \ ldev->brightness_get = object##_led_get; \ ldev->max_brightness = max; \ rv = led_classdev_register(&asus->platform_device->dev, ldev); \ if (rv) \ goto error; \ } while (0) static int asus_led_register(struct asus_laptop *asus, struct asus_led *led, const char *name, const char *method) { struct led_classdev *led_cdev = &led->led; if (!method || acpi_check_handle(asus->handle, method, NULL)) return 0; /* Led not present */ led->asus = asus; led->method = method; INIT_WORK(&led->work, asus_led_cdev_update); led_cdev->name = name; led_cdev->brightness_set = asus_led_cdev_set; led_cdev->brightness_get = asus_led_cdev_get; led_cdev->max_brightness = 1; return led_classdev_register(&asus->platform_device->dev, led_cdev); } static int asus_led_init(struct asus_laptop *asus) { int rv; int r; /* * Functions that actually update the LED's are called from a Loading @@ -523,22 +497,43 @@ static int asus_led_init(struct asus_laptop *asus) * subsystem asks, we avoid messing with the Asus ACPI stuff during a * potentially bad time, such as a timer interrupt. */ asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->leds.workqueue) asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); if (!asus->led_workqueue) return -ENOMEM; ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED); ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED); ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED); ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED); ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED); r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); if (r) goto error; r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED); if (r) goto error; r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED); if (r) goto error; r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED); if (r) goto error; r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED); if (r) goto error; if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) && !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, NULL); !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) { struct asus_led *led = &asus->kled; struct led_classdev *cdev = &led->led; led->asus = asus; INIT_WORK(&led->work, asus_kled_cdev_update); cdev->name = "asus::kbd_backlight"; cdev->brightness_set = asus_kled_cdev_set; cdev->brightness_get = asus_kled_cdev_get; cdev->max_brightness = 3; r = led_classdev_register(&asus->platform_device->dev, cdev); } error: if (rv) if (r) asus_led_exit(asus); return rv; return r; } /* Loading