aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/asus-laptop.c235
1 files changed, 115 insertions, 120 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index e1df92a22de9..ae5302646c4e 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -193,29 +193,12 @@ ASUS_HANDLE(display_get,
193/* 193/*
194 * Define a specific led structure to keep the main structure clean 194 * Define a specific led structure to keep the main structure clean
195 */ 195 */
196#define ASUS_DEFINE_LED(object) \ 196struct asus_led {
197 int object##_wk; \ 197 int wk;
198 struct work_struct object##_work; \ 198 struct work_struct work;
199 struct led_classdev object; 199 struct led_classdev led;
200 200 struct asus_laptop *asus;
201 201 const char *method;
202#define led_to_asus(led_cdev, led) \
203 container_of(container_of(led_cdev, struct asus_laptop_leds, \
204 led), \
205 struct asus_laptop, leds)
206#define work_to_asus(work, led) \
207 container_of(container_of(work, struct asus_laptop_leds, \
208 led##_work), \
209 struct asus_laptop, leds)
210
211struct asus_laptop_leds {
212 ASUS_DEFINE_LED(mled)
213 ASUS_DEFINE_LED(tled)
214 ASUS_DEFINE_LED(rled)
215 ASUS_DEFINE_LED(pled)
216 ASUS_DEFINE_LED(gled)
217 ASUS_DEFINE_LED(kled)
218 struct workqueue_struct *workqueue;
219}; 202};
220 203
221/* 204/*
@@ -233,7 +216,13 @@ struct asus_laptop {
233 struct input_dev *inputdev; 216 struct input_dev *inputdev;
234 struct key_entry *keymap; 217 struct key_entry *keymap;
235 218
236 struct asus_laptop_leds leds; 219 struct asus_led mled;
220 struct asus_led tled;
221 struct asus_led rled;
222 struct asus_led pled;
223 struct asus_led gled;
224 struct asus_led kled;
225 struct workqueue_struct *led_workqueue;
237 226
238 int wireless_status; 227 int wireless_status;
239 bool have_rsts; 228 bool have_rsts;
@@ -353,7 +342,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
353} 342}
354 343
355/* Generic LED function */ 344/* Generic LED function */
356static int asus_led_set(struct asus_laptop *asus, char *method, 345static int asus_led_set(struct asus_laptop *asus, const char *method,
357 int value) 346 int value)
358{ 347{
359 if (!strcmp(method, METHOD_MLED)) 348 if (!strcmp(method, METHOD_MLED))
@@ -369,50 +358,29 @@ static int asus_led_set(struct asus_laptop *asus, char *method,
369/* 358/*
370 * LEDs 359 * LEDs
371 */ 360 */
372#define ASUS_LED(object, ledname, max) \
373 static void object##_led_set(struct led_classdev *led_cdev, \
374 enum led_brightness value); \
375 static enum led_brightness object##_led_get( \
376 struct led_classdev *led_cdev); \
377 static void object##_led_update(struct work_struct *ignored);
378
379ASUS_LED(mled, "mail", 1);
380ASUS_LED(tled, "touchpad", 1);
381ASUS_LED(rled, "record", 1);
382ASUS_LED(pled, "phone", 1);
383ASUS_LED(gled, "gaming", 1);
384ASUS_LED(kled, "kbd_backlight", 3);
385
386/* /sys/class/led handlers */ 361/* /sys/class/led handlers */
387#define ASUS_LED_HANDLER(object, method) \ 362static void asus_led_cdev_set(struct led_classdev *led_cdev,
388 static void object##_led_set(struct led_classdev *led_cdev, \ 363 enum led_brightness value)
389 enum led_brightness value) \ 364{
390 { \ 365 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
391 struct asus_laptop *asus = \ 366 struct asus_laptop *asus = led->asus;
392 led_to_asus(led_cdev, object); \ 367
393 \ 368 led->wk = !!value;
394 asus->leds.object##_wk = (value > 0) ? 1 : 0; \ 369 queue_work(asus->led_workqueue, &led->work);
395 queue_work(asus->leds.workqueue, \ 370}
396 &asus->leds.object##_work); \ 371
397 } \ 372static void asus_led_cdev_update(struct work_struct *work)
398 static void object##_led_update(struct work_struct *work) \ 373{
399 { \ 374 struct asus_led *led = container_of(work, struct asus_led, work);
400 struct asus_laptop *asus = work_to_asus(work, object); \ 375 struct asus_laptop *asus = led->asus;
401 \
402 int value = asus->leds.object##_wk; \
403 asus_led_set(asus, method, value); \
404 } \
405 static enum led_brightness object##_led_get( \
406 struct led_classdev *led_cdev) \
407 { \
408 return led_cdev->brightness; \
409 }
410 376
411ASUS_LED_HANDLER(mled, METHOD_MLED); 377 asus_led_set(asus, led->method, led->wk);
412ASUS_LED_HANDLER(pled, METHOD_PLED); 378}
413ASUS_LED_HANDLER(rled, METHOD_RLED); 379
414ASUS_LED_HANDLER(tled, METHOD_TLED); 380static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev)
415ASUS_LED_HANDLER(gled, METHOD_GLED); 381{
382 return led_cdev->brightness;
383}
416 384
417/* 385/*
418 * Keyboard backlight (also a LED) 386 * Keyboard backlight (also a LED)
@@ -452,70 +420,76 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv)
452 return 0; 420 return 0;
453} 421}
454 422
455static void kled_led_set(struct led_classdev *led_cdev, 423static void asus_kled_cdev_set(struct led_classdev *led_cdev,
456 enum led_brightness value) 424 enum led_brightness value)
457{ 425{
458 struct asus_laptop *asus = led_to_asus(led_cdev, kled); 426 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
427 struct asus_laptop *asus = led->asus;
459 428
460 asus->leds.kled_wk = value; 429 led->wk = value;
461 queue_work(asus->leds.workqueue, &asus->leds.kled_work); 430 queue_work(asus->led_workqueue, &led->work);
462} 431}
463 432
464static void kled_led_update(struct work_struct *work) 433static void asus_kled_cdev_update(struct work_struct *work)
465{ 434{
466 struct asus_laptop *asus = work_to_asus(work, kled); 435 struct asus_led *led = container_of(work, struct asus_led, work);
436 struct asus_laptop *asus = led->asus;
467 437
468 asus_kled_set(asus, asus->leds.kled_wk); 438 asus_kled_set(asus, led->wk);
469} 439}
470 440
471static enum led_brightness kled_led_get(struct led_classdev *led_cdev) 441static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
472{ 442{
473 struct asus_laptop *asus = led_to_asus(led_cdev, kled); 443 struct asus_led *led = container_of(led_cdev, struct asus_led, led);
444 struct asus_laptop *asus = led->asus;
474 445
475 return asus_kled_lvl(asus); 446 return asus_kled_lvl(asus);
476} 447}
477 448
478static void asus_led_exit(struct asus_laptop *asus) 449static void asus_led_exit(struct asus_laptop *asus)
479{ 450{
480 if (asus->leds.mled.dev) 451 if (asus->mled.led.dev)
481 led_classdev_unregister(&asus->leds.mled); 452 led_classdev_unregister(&asus->mled.led);
482 if (asus->leds.tled.dev) 453 if (asus->tled.led.dev)
483 led_classdev_unregister(&asus->leds.tled); 454 led_classdev_unregister(&asus->tled.led);
484 if (asus->leds.pled.dev) 455 if (asus->pled.led.dev)
485 led_classdev_unregister(&asus->leds.pled); 456 led_classdev_unregister(&asus->pled.led);
486 if (asus->leds.rled.dev) 457 if (asus->rled.led.dev)
487 led_classdev_unregister(&asus->leds.rled); 458 led_classdev_unregister(&asus->rled.led);
488 if (asus->leds.gled.dev) 459 if (asus->gled.led.dev)
489 led_classdev_unregister(&asus->leds.gled); 460 led_classdev_unregister(&asus->gled.led);
490 if (asus->leds.kled.dev) 461 if (asus->kled.led.dev)
491 led_classdev_unregister(&asus->leds.kled); 462 led_classdev_unregister(&asus->kled.led);
492 if (asus->leds.workqueue) { 463 if (asus->led_workqueue) {
493 destroy_workqueue(asus->leds.workqueue); 464 destroy_workqueue(asus->led_workqueue);
494 asus->leds.workqueue = NULL; 465 asus->led_workqueue = NULL;
495 } 466 }
496} 467}
497 468
498/* Ugly macro, need to fix that later */ 469/* Ugly macro, need to fix that later */
499#define ASUS_LED_REGISTER(asus, object, _name, max, method) \ 470static int asus_led_register(struct asus_laptop *asus,
500 do { \ 471 struct asus_led *led,
501 struct led_classdev *ldev = &asus->leds.object; \ 472 const char *name, const char *method)
502 \ 473{
503 if (method && acpi_check_handle(asus->handle, method, NULL)) \ 474 struct led_classdev *led_cdev = &led->led;
504 break ; \ 475
505 \ 476 if (!method || acpi_check_handle(asus->handle, method, NULL))
506 INIT_WORK(&asus->leds.object##_work, object##_led_update); \ 477 return 0; /* Led not present */
507 ldev->name = "asus::" _name; \ 478
508 ldev->brightness_set = object##_led_set; \ 479 led->asus = asus;
509 ldev->brightness_get = object##_led_get; \ 480 led->method = method;
510 ldev->max_brightness = max; \ 481
511 rv = led_classdev_register(&asus->platform_device->dev, ldev); \ 482 INIT_WORK(&led->work, asus_led_cdev_update);
512 if (rv) \ 483 led_cdev->name = name;
513 goto error; \ 484 led_cdev->brightness_set = asus_led_cdev_set;
514 } while (0) 485 led_cdev->brightness_get = asus_led_cdev_get;
486 led_cdev->max_brightness = 1;
487 return led_classdev_register(&asus->platform_device->dev, led_cdev);
488}
515 489
516static int asus_led_init(struct asus_laptop *asus) 490static int asus_led_init(struct asus_laptop *asus)
517{ 491{
518 int rv; 492 int r;
519 493
520 /* 494 /*
521 * Functions that actually update the LED's are called from a 495 * Functions that actually update the LED's are called from a
@@ -523,22 +497,43 @@ static int asus_led_init(struct asus_laptop *asus)
523 * subsystem asks, we avoid messing with the Asus ACPI stuff during a 497 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
524 * potentially bad time, such as a timer interrupt. 498 * potentially bad time, such as a timer interrupt.
525 */ 499 */
526 asus->leds.workqueue = create_singlethread_workqueue("led_workqueue"); 500 asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
527 if (!asus->leds.workqueue) 501 if (!asus->led_workqueue)
528 return -ENOMEM; 502 return -ENOMEM;
529 503
530 ASUS_LED_REGISTER(asus, mled, "mail", 1, METHOD_MLED); 504 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
531 ASUS_LED_REGISTER(asus, tled, "touchpad", 1, METHOD_TLED); 505 if (r)
532 ASUS_LED_REGISTER(asus, rled, "record", 1, METHOD_RLED); 506 goto error;
533 ASUS_LED_REGISTER(asus, pled, "phone", 1, METHOD_PLED); 507 r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
534 ASUS_LED_REGISTER(asus, gled, "gaming", 1, METHOD_GLED); 508 if (r)
509 goto error;
510 r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED);
511 if (r)
512 goto error;
513 r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED);
514 if (r)
515 goto error;
516 r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED);
517 if (r)
518 goto error;
535 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) && 519 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
536 !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) 520 !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
537 ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3, NULL); 521 struct asus_led *led = &asus->kled;
522 struct led_classdev *cdev = &led->led;
523
524 led->asus = asus;
525
526 INIT_WORK(&led->work, asus_kled_cdev_update);
527 cdev->name = "asus::kbd_backlight";
528 cdev->brightness_set = asus_kled_cdev_set;
529 cdev->brightness_get = asus_kled_cdev_get;
530 cdev->max_brightness = 3;
531 r = led_classdev_register(&asus->platform_device->dev, cdev);
532 }
538error: 533error:
539 if (rv) 534 if (r)
540 asus_led_exit(asus); 535 asus_led_exit(asus);
541 return rv; 536 return r;
542} 537}
543 538
544/* 539/*