mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-15 09:55:36 +00:00
asus-laptop: clean led code
Remove all "templates" and add a generic struct asus_led instead. Signed-off-by: Corentin Chary <corentincj@iksaif.net>
This commit is contained in:
parent
18e1311ee7
commit
aee0afb8cb
@ -193,29 +193,12 @@ ASUS_HANDLE(display_get,
|
|||||||
/*
|
/*
|
||||||
* Define a specific led structure to keep the main structure clean
|
* Define a specific led structure to keep the main structure clean
|
||||||
*/
|
*/
|
||||||
#define ASUS_DEFINE_LED(object) \
|
struct asus_led {
|
||||||
int object##_wk; \
|
int wk;
|
||||||
struct work_struct object##_work; \
|
struct work_struct work;
|
||||||
struct led_classdev object;
|
struct led_classdev led;
|
||||||
|
struct asus_laptop *asus;
|
||||||
|
const char *method;
|
||||||
#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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -233,7 +216,13 @@ struct asus_laptop {
|
|||||||
struct input_dev *inputdev;
|
struct input_dev *inputdev;
|
||||||
struct key_entry *keymap;
|
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;
|
int wireless_status;
|
||||||
bool have_rsts;
|
bool have_rsts;
|
||||||
@ -353,7 +342,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Generic LED function */
|
/* 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)
|
int value)
|
||||||
{
|
{
|
||||||
if (!strcmp(method, METHOD_MLED))
|
if (!strcmp(method, METHOD_MLED))
|
||||||
@ -369,50 +358,29 @@ static int asus_led_set(struct asus_laptop *asus, char *method,
|
|||||||
/*
|
/*
|
||||||
* LEDs
|
* 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 */
|
/* /sys/class/led handlers */
|
||||||
#define ASUS_LED_HANDLER(object, method) \
|
static void asus_led_cdev_set(struct led_classdev *led_cdev,
|
||||||
static void object##_led_set(struct led_classdev *led_cdev, \
|
enum led_brightness value)
|
||||||
enum led_brightness value) \
|
{
|
||||||
{ \
|
struct asus_led *led = container_of(led_cdev, struct asus_led, led);
|
||||||
struct asus_laptop *asus = \
|
struct asus_laptop *asus = led->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);
|
led->wk = !!value;
|
||||||
ASUS_LED_HANDLER(pled, METHOD_PLED);
|
queue_work(asus->led_workqueue, &led->work);
|
||||||
ASUS_LED_HANDLER(rled, METHOD_RLED);
|
}
|
||||||
ASUS_LED_HANDLER(tled, METHOD_TLED);
|
|
||||||
ASUS_LED_HANDLER(gled, METHOD_GLED);
|
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)
|
* Keyboard backlight (also a LED)
|
||||||
@ -452,70 +420,76 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv)
|
|||||||
return 0;
|
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)
|
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;
|
led->wk = value;
|
||||||
queue_work(asus->leds.workqueue, &asus->leds.kled_work);
|
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);
|
return asus_kled_lvl(asus);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asus_led_exit(struct asus_laptop *asus)
|
static void asus_led_exit(struct asus_laptop *asus)
|
||||||
{
|
{
|
||||||
if (asus->leds.mled.dev)
|
if (asus->mled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.mled);
|
led_classdev_unregister(&asus->mled.led);
|
||||||
if (asus->leds.tled.dev)
|
if (asus->tled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.tled);
|
led_classdev_unregister(&asus->tled.led);
|
||||||
if (asus->leds.pled.dev)
|
if (asus->pled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.pled);
|
led_classdev_unregister(&asus->pled.led);
|
||||||
if (asus->leds.rled.dev)
|
if (asus->rled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.rled);
|
led_classdev_unregister(&asus->rled.led);
|
||||||
if (asus->leds.gled.dev)
|
if (asus->gled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.gled);
|
led_classdev_unregister(&asus->gled.led);
|
||||||
if (asus->leds.kled.dev)
|
if (asus->kled.led.dev)
|
||||||
led_classdev_unregister(&asus->leds.kled);
|
led_classdev_unregister(&asus->kled.led);
|
||||||
if (asus->leds.workqueue) {
|
if (asus->led_workqueue) {
|
||||||
destroy_workqueue(asus->leds.workqueue);
|
destroy_workqueue(asus->led_workqueue);
|
||||||
asus->leds.workqueue = NULL;
|
asus->led_workqueue = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ugly macro, need to fix that later */
|
/* Ugly macro, need to fix that later */
|
||||||
#define ASUS_LED_REGISTER(asus, object, _name, max, method) \
|
static int asus_led_register(struct asus_laptop *asus,
|
||||||
do { \
|
struct asus_led *led,
|
||||||
struct led_classdev *ldev = &asus->leds.object; \
|
const char *name, const char *method)
|
||||||
\
|
{
|
||||||
if (method && acpi_check_handle(asus->handle, method, NULL)) \
|
struct led_classdev *led_cdev = &led->led;
|
||||||
break ; \
|
|
||||||
\
|
if (!method || acpi_check_handle(asus->handle, method, NULL))
|
||||||
INIT_WORK(&asus->leds.object##_work, object##_led_update); \
|
return 0; /* Led not present */
|
||||||
ldev->name = "asus::" _name; \
|
|
||||||
ldev->brightness_set = object##_led_set; \
|
led->asus = asus;
|
||||||
ldev->brightness_get = object##_led_get; \
|
led->method = method;
|
||||||
ldev->max_brightness = max; \
|
|
||||||
rv = led_classdev_register(&asus->platform_device->dev, ldev); \
|
INIT_WORK(&led->work, asus_led_cdev_update);
|
||||||
if (rv) \
|
led_cdev->name = name;
|
||||||
goto error; \
|
led_cdev->brightness_set = asus_led_cdev_set;
|
||||||
} while (0)
|
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)
|
static int asus_led_init(struct asus_laptop *asus)
|
||||||
{
|
{
|
||||||
int rv;
|
int r;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions that actually update the LED's are called from a
|
* Functions that actually update the LED's are called from a
|
||||||
@ -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
|
* subsystem asks, we avoid messing with the Asus ACPI stuff during a
|
||||||
* potentially bad time, such as a timer interrupt.
|
* potentially bad time, such as a timer interrupt.
|
||||||
*/
|
*/
|
||||||
asus->leds.workqueue = create_singlethread_workqueue("led_workqueue");
|
asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
|
||||||
if (!asus->leds.workqueue)
|
if (!asus->led_workqueue)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED);
|
r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
|
||||||
ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED);
|
if (r)
|
||||||
ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED);
|
goto error;
|
||||||
ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED);
|
r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
|
||||||
ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED);
|
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) &&
|
if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
|
||||||
!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL))
|
!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
|
||||||
ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, 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:
|
error:
|
||||||
if (rv)
|
if (r)
|
||||||
asus_led_exit(asus);
|
asus_led_exit(asus);
|
||||||
return rv;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user