diff options
| author | Corentin Chary <corentincj@iksaif.net> | 2010-01-26 15:01:34 -0500 |
|---|---|---|
| committer | Corentin Chary <corentincj@iksaif.net> | 2010-02-28 13:35:13 -0500 |
| commit | aee0afb8cb52178164accfec9cfc58bc27b597b3 (patch) | |
| tree | d6775772d0f85a31f4ded53c1ea2587d748692c6 /drivers | |
| parent | 18e1311ee71a67497a33521be61ddf6562fa22c0 (diff) | |
asus-laptop: clean led code
Remove all "templates" and add a generic struct asus_led instead.
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/platform/x86/asus-laptop.c | 235 |
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) \ | 196 | struct 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 | |||
| 211 | struct 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 */ |
| 356 | static int asus_led_set(struct asus_laptop *asus, char *method, | 345 | static 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 | |||
| 379 | ASUS_LED(mled, "mail", 1); | ||
| 380 | ASUS_LED(tled, "touchpad", 1); | ||
| 381 | ASUS_LED(rled, "record", 1); | ||
| 382 | ASUS_LED(pled, "phone", 1); | ||
| 383 | ASUS_LED(gled, "gaming", 1); | ||
| 384 | ASUS_LED(kled, "kbd_backlight", 3); | ||
| 385 | |||
| 386 | /* /sys/class/led handlers */ | 361 | /* /sys/class/led handlers */ |
| 387 | #define ASUS_LED_HANDLER(object, method) \ | 362 | static 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 | } \ | 372 | static 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 | ||
| 411 | ASUS_LED_HANDLER(mled, METHOD_MLED); | 377 | asus_led_set(asus, led->method, led->wk); |
| 412 | ASUS_LED_HANDLER(pled, METHOD_PLED); | 378 | } |
| 413 | ASUS_LED_HANDLER(rled, METHOD_RLED); | 379 | |
| 414 | ASUS_LED_HANDLER(tled, METHOD_TLED); | 380 | static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev) |
| 415 | ASUS_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 | ||
| 455 | static void kled_led_set(struct led_classdev *led_cdev, | 423 | static 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 | ||
| 464 | static void kled_led_update(struct work_struct *work) | 433 | static 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 | ||
| 471 | static enum led_brightness kled_led_get(struct led_classdev *led_cdev) | 441 | static 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 | ||
| 478 | static void asus_led_exit(struct asus_laptop *asus) | 449 | static 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) \ | 470 | static 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 | ||
| 516 | static int asus_led_init(struct asus_laptop *asus) | 490 | static 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 | } | ||
| 538 | error: | 533 | error: |
| 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 | /* |
