diff options
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r-- | drivers/acpi/video.c | 301 |
1 files changed, 235 insertions, 66 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index bb5ed059114a..100c8eeaa5dd 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/thermal.h> | 37 | #include <linux/thermal.h> |
38 | #include <linux/video_output.h> | 38 | #include <linux/video_output.h> |
39 | #include <linux/sort.h> | 39 | #include <linux/sort.h> |
40 | #include <linux/pci.h> | ||
41 | #include <linux/pci_ids.h> | ||
40 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
41 | 43 | ||
42 | #include <acpi/acpi_bus.h> | 44 | #include <acpi/acpi_bus.h> |
@@ -162,16 +164,26 @@ struct acpi_video_device_cap { | |||
162 | u8 _BCL:1; /*Query list of brightness control levels supported */ | 164 | u8 _BCL:1; /*Query list of brightness control levels supported */ |
163 | u8 _BCM:1; /*Set the brightness level */ | 165 | u8 _BCM:1; /*Set the brightness level */ |
164 | u8 _BQC:1; /* Get current brightness level */ | 166 | u8 _BQC:1; /* Get current brightness level */ |
167 | u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */ | ||
165 | u8 _DDC:1; /*Return the EDID for this device */ | 168 | u8 _DDC:1; /*Return the EDID for this device */ |
166 | u8 _DCS:1; /*Return status of output device */ | 169 | u8 _DCS:1; /*Return status of output device */ |
167 | u8 _DGS:1; /*Query graphics state */ | 170 | u8 _DGS:1; /*Query graphics state */ |
168 | u8 _DSS:1; /*Device state set */ | 171 | u8 _DSS:1; /*Device state set */ |
169 | }; | 172 | }; |
170 | 173 | ||
174 | struct acpi_video_brightness_flags { | ||
175 | u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */ | ||
176 | u8 _BCL_reversed:1; /* _BCL package is in a reversed order*/ | ||
177 | u8 _BCL_use_index:1; /* levels in _BCL are index values */ | ||
178 | u8 _BCM_use_index:1; /* input of _BCM is an index value */ | ||
179 | u8 _BQC_use_index:1; /* _BQC returns an index value */ | ||
180 | }; | ||
181 | |||
171 | struct acpi_video_device_brightness { | 182 | struct acpi_video_device_brightness { |
172 | int curr; | 183 | int curr; |
173 | int count; | 184 | int count; |
174 | int *levels; | 185 | int *levels; |
186 | struct acpi_video_brightness_flags flags; | ||
175 | }; | 187 | }; |
176 | 188 | ||
177 | struct acpi_video_device { | 189 | struct acpi_video_device { |
@@ -294,7 +306,7 @@ static int acpi_video_device_lcd_get_level_current( | |||
294 | unsigned long long *level); | 306 | unsigned long long *level); |
295 | static int acpi_video_get_next_level(struct acpi_video_device *device, | 307 | static int acpi_video_get_next_level(struct acpi_video_device *device, |
296 | u32 level_current, u32 event); | 308 | u32 level_current, u32 event); |
297 | static void acpi_video_switch_brightness(struct acpi_video_device *device, | 309 | static int acpi_video_switch_brightness(struct acpi_video_device *device, |
298 | int event); | 310 | int event); |
299 | static int acpi_video_device_get_state(struct acpi_video_device *device, | 311 | static int acpi_video_device_get_state(struct acpi_video_device *device, |
300 | unsigned long long *state); | 312 | unsigned long long *state); |
@@ -308,7 +320,9 @@ static int acpi_video_get_brightness(struct backlight_device *bd) | |||
308 | int i; | 320 | int i; |
309 | struct acpi_video_device *vd = | 321 | struct acpi_video_device *vd = |
310 | (struct acpi_video_device *)bl_get_data(bd); | 322 | (struct acpi_video_device *)bl_get_data(bd); |
311 | acpi_video_device_lcd_get_level_current(vd, &cur_level); | 323 | |
324 | if (acpi_video_device_lcd_get_level_current(vd, &cur_level)) | ||
325 | return -EINVAL; | ||
312 | for (i = 2; i < vd->brightness->count; i++) { | 326 | for (i = 2; i < vd->brightness->count; i++) { |
313 | if (vd->brightness->levels[i] == cur_level) | 327 | if (vd->brightness->levels[i] == cur_level) |
314 | /* The first two entries are special - see page 575 | 328 | /* The first two entries are special - see page 575 |
@@ -320,12 +334,12 @@ static int acpi_video_get_brightness(struct backlight_device *bd) | |||
320 | 334 | ||
321 | static int acpi_video_set_brightness(struct backlight_device *bd) | 335 | static int acpi_video_set_brightness(struct backlight_device *bd) |
322 | { | 336 | { |
323 | int request_level = bd->props.brightness+2; | 337 | int request_level = bd->props.brightness + 2; |
324 | struct acpi_video_device *vd = | 338 | struct acpi_video_device *vd = |
325 | (struct acpi_video_device *)bl_get_data(bd); | 339 | (struct acpi_video_device *)bl_get_data(bd); |
326 | acpi_video_device_lcd_set_level(vd, | 340 | |
327 | vd->brightness->levels[request_level]); | 341 | return acpi_video_device_lcd_set_level(vd, |
328 | return 0; | 342 | vd->brightness->levels[request_level]); |
329 | } | 343 | } |
330 | 344 | ||
331 | static struct backlight_ops acpi_backlight_ops = { | 345 | static struct backlight_ops acpi_backlight_ops = { |
@@ -358,32 +372,37 @@ static struct output_properties acpi_output_properties = { | |||
358 | 372 | ||
359 | 373 | ||
360 | /* thermal cooling device callbacks */ | 374 | /* thermal cooling device callbacks */ |
361 | static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf) | 375 | static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned |
376 | long *state) | ||
362 | { | 377 | { |
363 | struct acpi_device *device = cdev->devdata; | 378 | struct acpi_device *device = cdev->devdata; |
364 | struct acpi_video_device *video = acpi_driver_data(device); | 379 | struct acpi_video_device *video = acpi_driver_data(device); |
365 | 380 | ||
366 | return sprintf(buf, "%d\n", video->brightness->count - 3); | 381 | *state = video->brightness->count - 3; |
382 | return 0; | ||
367 | } | 383 | } |
368 | 384 | ||
369 | static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf) | 385 | static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned |
386 | long *state) | ||
370 | { | 387 | { |
371 | struct acpi_device *device = cdev->devdata; | 388 | struct acpi_device *device = cdev->devdata; |
372 | struct acpi_video_device *video = acpi_driver_data(device); | 389 | struct acpi_video_device *video = acpi_driver_data(device); |
373 | unsigned long long level; | 390 | unsigned long long level; |
374 | int state; | 391 | int offset; |
375 | 392 | ||
376 | acpi_video_device_lcd_get_level_current(video, &level); | 393 | if (acpi_video_device_lcd_get_level_current(video, &level)) |
377 | for (state = 2; state < video->brightness->count; state++) | 394 | return -EINVAL; |
378 | if (level == video->brightness->levels[state]) | 395 | for (offset = 2; offset < video->brightness->count; offset++) |
379 | return sprintf(buf, "%d\n", | 396 | if (level == video->brightness->levels[offset]) { |
380 | video->brightness->count - state - 1); | 397 | *state = video->brightness->count - offset - 1; |
398 | return 0; | ||
399 | } | ||
381 | 400 | ||
382 | return -EINVAL; | 401 | return -EINVAL; |
383 | } | 402 | } |
384 | 403 | ||
385 | static int | 404 | static int |
386 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) | 405 | video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) |
387 | { | 406 | { |
388 | struct acpi_device *device = cdev->devdata; | 407 | struct acpi_device *device = cdev->devdata; |
389 | struct acpi_video_device *video = acpi_driver_data(device); | 408 | struct acpi_video_device *video = acpi_driver_data(device); |
@@ -479,34 +498,68 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, | |||
479 | static int | 498 | static int |
480 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) | 499 | acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) |
481 | { | 500 | { |
482 | int status = AE_OK; | 501 | int status; |
483 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 502 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
484 | struct acpi_object_list args = { 1, &arg0 }; | 503 | struct acpi_object_list args = { 1, &arg0 }; |
485 | int state; | 504 | int state; |
486 | 505 | ||
487 | |||
488 | arg0.integer.value = level; | 506 | arg0.integer.value = level; |
489 | 507 | ||
490 | if (device->cap._BCM) | 508 | status = acpi_evaluate_object(device->dev->handle, "_BCM", |
491 | status = acpi_evaluate_object(device->dev->handle, "_BCM", | 509 | &args, NULL); |
492 | &args, NULL); | 510 | if (ACPI_FAILURE(status)) { |
511 | ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); | ||
512 | return -EIO; | ||
513 | } | ||
514 | |||
493 | device->brightness->curr = level; | 515 | device->brightness->curr = level; |
494 | for (state = 2; state < device->brightness->count; state++) | 516 | for (state = 2; state < device->brightness->count; state++) |
495 | if (level == device->brightness->levels[state]) | 517 | if (level == device->brightness->levels[state]) { |
496 | device->backlight->props.brightness = state - 2; | 518 | if (device->backlight) |
519 | device->backlight->props.brightness = state - 2; | ||
520 | return 0; | ||
521 | } | ||
497 | 522 | ||
498 | return status; | 523 | ACPI_ERROR((AE_INFO, "Current brightness invalid")); |
524 | return -EINVAL; | ||
499 | } | 525 | } |
500 | 526 | ||
501 | static int | 527 | static int |
502 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, | 528 | acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, |
503 | unsigned long long *level) | 529 | unsigned long long *level) |
504 | { | 530 | { |
505 | if (device->cap._BQC) | 531 | acpi_status status = AE_OK; |
506 | return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, | 532 | |
507 | level); | 533 | if (device->cap._BQC || device->cap._BCQ) { |
534 | char *buf = device->cap._BQC ? "_BQC" : "_BCQ"; | ||
535 | |||
536 | status = acpi_evaluate_integer(device->dev->handle, buf, | ||
537 | NULL, level); | ||
538 | if (ACPI_SUCCESS(status)) { | ||
539 | if (device->brightness->flags._BQC_use_index) { | ||
540 | if (device->brightness->flags._BCL_reversed) | ||
541 | *level = device->brightness->count | ||
542 | - 3 - (*level); | ||
543 | *level = device->brightness->levels[*level + 2]; | ||
544 | |||
545 | } | ||
546 | device->brightness->curr = *level; | ||
547 | return 0; | ||
548 | } else { | ||
549 | /* Fixme: | ||
550 | * should we return an error or ignore this failure? | ||
551 | * dev->brightness->curr is a cached value which stores | ||
552 | * the correct current backlight level in most cases. | ||
553 | * ACPI video backlight still works w/ buggy _BQC. | ||
554 | * http://bugzilla.kernel.org/show_bug.cgi?id=12233 | ||
555 | */ | ||
556 | ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf)); | ||
557 | device->cap._BQC = device->cap._BCQ = 0; | ||
558 | } | ||
559 | } | ||
560 | |||
508 | *level = device->brightness->curr; | 561 | *level = device->brightness->curr; |
509 | return AE_OK; | 562 | return 0; |
510 | } | 563 | } |
511 | 564 | ||
512 | static int | 565 | static int |
@@ -655,9 +708,11 @@ static int | |||
655 | acpi_video_init_brightness(struct acpi_video_device *device) | 708 | acpi_video_init_brightness(struct acpi_video_device *device) |
656 | { | 709 | { |
657 | union acpi_object *obj = NULL; | 710 | union acpi_object *obj = NULL; |
658 | int i, max_level = 0, count = 0; | 711 | int i, max_level = 0, count = 0, level_ac_battery = 0; |
712 | unsigned long long level, level_old; | ||
659 | union acpi_object *o; | 713 | union acpi_object *o; |
660 | struct acpi_video_device_brightness *br = NULL; | 714 | struct acpi_video_device_brightness *br = NULL; |
715 | int result = -EINVAL; | ||
661 | 716 | ||
662 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { | 717 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
663 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " | 718 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " |
@@ -671,13 +726,16 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
671 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 726 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
672 | if (!br) { | 727 | if (!br) { |
673 | printk(KERN_ERR "can't allocate memory\n"); | 728 | printk(KERN_ERR "can't allocate memory\n"); |
729 | result = -ENOMEM; | ||
674 | goto out; | 730 | goto out; |
675 | } | 731 | } |
676 | 732 | ||
677 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), | 733 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), |
678 | GFP_KERNEL); | 734 | GFP_KERNEL); |
679 | if (!br->levels) | 735 | if (!br->levels) { |
736 | result = -ENOMEM; | ||
680 | goto out_free; | 737 | goto out_free; |
738 | } | ||
681 | 739 | ||
682 | for (i = 0; i < obj->package.count; i++) { | 740 | for (i = 0; i < obj->package.count; i++) { |
683 | o = (union acpi_object *)&obj->package.elements[i]; | 741 | o = (union acpi_object *)&obj->package.elements[i]; |
@@ -692,18 +750,86 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
692 | count++; | 750 | count++; |
693 | } | 751 | } |
694 | 752 | ||
695 | /* don't sort the first two brightness levels */ | 753 | /* |
696 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | 754 | * some buggy BIOS don't export the levels |
697 | acpi_video_cmp_level, NULL); | 755 | * when machine is on AC/Battery in _BCL package. |
698 | 756 | * In this case, the first two elements in _BCL packages | |
699 | if (count < 2) | 757 | * are also supported brightness levels that OS should take care of. |
700 | goto out_free_levels; | 758 | */ |
759 | for (i = 2; i < count; i++) | ||
760 | if (br->levels[i] == br->levels[0] || | ||
761 | br->levels[i] == br->levels[1]) | ||
762 | level_ac_battery++; | ||
763 | |||
764 | if (level_ac_battery < 2) { | ||
765 | level_ac_battery = 2 - level_ac_battery; | ||
766 | br->flags._BCL_no_ac_battery_levels = 1; | ||
767 | for (i = (count - 1 + level_ac_battery); i >= 2; i--) | ||
768 | br->levels[i] = br->levels[i - level_ac_battery]; | ||
769 | count += level_ac_battery; | ||
770 | } else if (level_ac_battery > 2) | ||
771 | ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package\n")); | ||
772 | |||
773 | /* Check if the _BCL package is in a reversed order */ | ||
774 | if (max_level == br->levels[2]) { | ||
775 | br->flags._BCL_reversed = 1; | ||
776 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | ||
777 | acpi_video_cmp_level, NULL); | ||
778 | } else if (max_level != br->levels[count - 1]) | ||
779 | ACPI_ERROR((AE_INFO, | ||
780 | "Found unordered _BCL package\n")); | ||
701 | 781 | ||
702 | br->count = count; | 782 | br->count = count; |
703 | device->brightness = br; | 783 | device->brightness = br; |
704 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count)); | 784 | |
785 | /* Check the input/output of _BQC/_BCL/_BCM */ | ||
786 | if ((max_level < 100) && (max_level <= (count - 2))) | ||
787 | br->flags._BCL_use_index = 1; | ||
788 | |||
789 | /* | ||
790 | * _BCM is always consistent with _BCL, | ||
791 | * at least for all the laptops we have ever seen. | ||
792 | */ | ||
793 | br->flags._BCM_use_index = br->flags._BCL_use_index; | ||
794 | |||
795 | /* _BQC uses INDEX while _BCL uses VALUE in some laptops */ | ||
796 | br->curr = max_level; | ||
797 | result = acpi_video_device_lcd_get_level_current(device, &level_old); | ||
798 | if (result) | ||
799 | goto out_free_levels; | ||
800 | |||
801 | result = acpi_video_device_lcd_set_level(device, br->curr); | ||
802 | if (result) | ||
803 | goto out_free_levels; | ||
804 | |||
805 | result = acpi_video_device_lcd_get_level_current(device, &level); | ||
806 | if (result) | ||
807 | goto out_free_levels; | ||
808 | |||
809 | if ((level != level_old) && !br->flags._BCM_use_index) { | ||
810 | /* Note: | ||
811 | * This piece of code does not work correctly if the current | ||
812 | * brightness levels is 0. | ||
813 | * But I guess boxes that boot with such a dark screen are rare | ||
814 | * and no more code is needed to cover this specifial case. | ||
815 | */ | ||
816 | |||
817 | if (level_ac_battery != 2) { | ||
818 | /* | ||
819 | * For now, we don't support the _BCL like this: | ||
820 | * 16, 15, 0, 1, 2, 3, ..., 14, 15, 16 | ||
821 | * because we may mess up the index returned by _BQC. | ||
822 | * Plus: we have not got a box like this. | ||
823 | */ | ||
824 | ACPI_ERROR((AE_INFO, "_BCL not supported\n")); | ||
825 | } | ||
826 | br->flags._BQC_use_index = 1; | ||
827 | } | ||
828 | |||
829 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
830 | "found %d brightness levels\n", count - 2)); | ||
705 | kfree(obj); | 831 | kfree(obj); |
706 | return max_level; | 832 | return result; |
707 | 833 | ||
708 | out_free_levels: | 834 | out_free_levels: |
709 | kfree(br->levels); | 835 | kfree(br->levels); |
@@ -712,7 +838,7 @@ out_free: | |||
712 | out: | 838 | out: |
713 | device->brightness = NULL; | 839 | device->brightness = NULL; |
714 | kfree(obj); | 840 | kfree(obj); |
715 | return 0; | 841 | return result; |
716 | } | 842 | } |
717 | 843 | ||
718 | /* | 844 | /* |
@@ -729,7 +855,6 @@ out: | |||
729 | static void acpi_video_device_find_cap(struct acpi_video_device *device) | 855 | static void acpi_video_device_find_cap(struct acpi_video_device *device) |
730 | { | 856 | { |
731 | acpi_handle h_dummy1; | 857 | acpi_handle h_dummy1; |
732 | u32 max_level = 0; | ||
733 | 858 | ||
734 | 859 | ||
735 | memset(&device->cap, 0, sizeof(device->cap)); | 860 | memset(&device->cap, 0, sizeof(device->cap)); |
@@ -745,6 +870,12 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
745 | } | 870 | } |
746 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) | 871 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) |
747 | device->cap._BQC = 1; | 872 | device->cap._BQC = 1; |
873 | else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ", | ||
874 | &h_dummy1))) { | ||
875 | printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n"); | ||
876 | device->cap._BCQ = 1; | ||
877 | } | ||
878 | |||
748 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { | 879 | if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { |
749 | device->cap._DDC = 1; | 880 | device->cap._DDC = 1; |
750 | } | 881 | } |
@@ -758,13 +889,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
758 | device->cap._DSS = 1; | 889 | device->cap._DSS = 1; |
759 | } | 890 | } |
760 | 891 | ||
761 | if (acpi_video_backlight_support()) | 892 | if (acpi_video_backlight_support()) { |
762 | max_level = acpi_video_init_brightness(device); | ||
763 | |||
764 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { | ||
765 | int result; | 893 | int result; |
766 | static int count = 0; | 894 | static int count = 0; |
767 | char *name; | 895 | char *name; |
896 | |||
897 | result = acpi_video_init_brightness(device); | ||
898 | if (result) | ||
899 | return; | ||
768 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 900 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
769 | if (!name) | 901 | if (!name) |
770 | return; | 902 | return; |
@@ -773,18 +905,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
773 | device->backlight = backlight_device_register(name, | 905 | device->backlight = backlight_device_register(name, |
774 | NULL, device, &acpi_backlight_ops); | 906 | NULL, device, &acpi_backlight_ops); |
775 | device->backlight->props.max_brightness = device->brightness->count-3; | 907 | device->backlight->props.max_brightness = device->brightness->count-3; |
776 | /* | ||
777 | * If there exists the _BQC object, the _BQC object will be | ||
778 | * called to get the current backlight brightness. Otherwise | ||
779 | * the brightness will be set to the maximum. | ||
780 | */ | ||
781 | if (device->cap._BQC) | ||
782 | device->backlight->props.brightness = | ||
783 | acpi_video_get_brightness(device->backlight); | ||
784 | else | ||
785 | device->backlight->props.brightness = | ||
786 | device->backlight->props.max_brightness; | ||
787 | backlight_update_status(device->backlight); | ||
788 | kfree(name); | 908 | kfree(name); |
789 | 909 | ||
790 | device->cdev = thermal_cooling_device_register("LCD", | 910 | device->cdev = thermal_cooling_device_register("LCD", |
@@ -1061,13 +1181,12 @@ acpi_video_device_write_brightness(struct file *file, | |||
1061 | /* validate through the list of available levels */ | 1181 | /* validate through the list of available levels */ |
1062 | for (i = 2; i < dev->brightness->count; i++) | 1182 | for (i = 2; i < dev->brightness->count; i++) |
1063 | if (level == dev->brightness->levels[i]) { | 1183 | if (level == dev->brightness->levels[i]) { |
1064 | if (ACPI_SUCCESS | 1184 | if (!acpi_video_device_lcd_set_level(dev, level)) |
1065 | (acpi_video_device_lcd_set_level(dev, level))) | 1185 | return count; |
1066 | dev->brightness->curr = level; | ||
1067 | break; | 1186 | break; |
1068 | } | 1187 | } |
1069 | 1188 | ||
1070 | return count; | 1189 | return -EINVAL; |
1071 | } | 1190 | } |
1072 | 1191 | ||
1073 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) | 1192 | static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset) |
@@ -1749,15 +1868,29 @@ acpi_video_get_next_level(struct acpi_video_device *device, | |||
1749 | } | 1868 | } |
1750 | } | 1869 | } |
1751 | 1870 | ||
1752 | static void | 1871 | static int |
1753 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) | 1872 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) |
1754 | { | 1873 | { |
1755 | unsigned long long level_current, level_next; | 1874 | unsigned long long level_current, level_next; |
1875 | int result = -EINVAL; | ||
1876 | |||
1756 | if (!device->brightness) | 1877 | if (!device->brightness) |
1757 | return; | 1878 | goto out; |
1758 | acpi_video_device_lcd_get_level_current(device, &level_current); | 1879 | |
1880 | result = acpi_video_device_lcd_get_level_current(device, | ||
1881 | &level_current); | ||
1882 | if (result) | ||
1883 | goto out; | ||
1884 | |||
1759 | level_next = acpi_video_get_next_level(device, level_current, event); | 1885 | level_next = acpi_video_get_next_level(device, level_current, event); |
1760 | acpi_video_device_lcd_set_level(device, level_next); | 1886 | |
1887 | result = acpi_video_device_lcd_set_level(device, level_next); | ||
1888 | |||
1889 | out: | ||
1890 | if (result) | ||
1891 | printk(KERN_ERR PREFIX "Failed to switch the brightness\n"); | ||
1892 | |||
1893 | return result; | ||
1761 | } | 1894 | } |
1762 | 1895 | ||
1763 | static int | 1896 | static int |
@@ -2124,7 +2257,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2124 | return 0; | 2257 | return 0; |
2125 | } | 2258 | } |
2126 | 2259 | ||
2127 | static int __init acpi_video_init(void) | 2260 | static int __init intel_opregion_present(void) |
2261 | { | ||
2262 | #if defined(CONFIG_DRM_I915) || defined(CONFIG_DRM_I915_MODULE) | ||
2263 | struct pci_dev *dev = NULL; | ||
2264 | u32 address; | ||
2265 | |||
2266 | for_each_pci_dev(dev) { | ||
2267 | if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) | ||
2268 | continue; | ||
2269 | if (dev->vendor != PCI_VENDOR_ID_INTEL) | ||
2270 | continue; | ||
2271 | pci_read_config_dword(dev, 0xfc, &address); | ||
2272 | if (!address) | ||
2273 | continue; | ||
2274 | return 1; | ||
2275 | } | ||
2276 | #endif | ||
2277 | return 0; | ||
2278 | } | ||
2279 | |||
2280 | int acpi_video_register(void) | ||
2128 | { | 2281 | { |
2129 | int result = 0; | 2282 | int result = 0; |
2130 | 2283 | ||
@@ -2141,6 +2294,22 @@ static int __init acpi_video_init(void) | |||
2141 | 2294 | ||
2142 | return 0; | 2295 | return 0; |
2143 | } | 2296 | } |
2297 | EXPORT_SYMBOL(acpi_video_register); | ||
2298 | |||
2299 | /* | ||
2300 | * This is kind of nasty. Hardware using Intel chipsets may require | ||
2301 | * the video opregion code to be run first in order to initialise | ||
2302 | * state before any ACPI video calls are made. To handle this we defer | ||
2303 | * registration of the video class until the opregion code has run. | ||
2304 | */ | ||
2305 | |||
2306 | static int __init acpi_video_init(void) | ||
2307 | { | ||
2308 | if (intel_opregion_present()) | ||
2309 | return 0; | ||
2310 | |||
2311 | return acpi_video_register(); | ||
2312 | } | ||
2144 | 2313 | ||
2145 | static void __exit acpi_video_exit(void) | 2314 | static void __exit acpi_video_exit(void) |
2146 | { | 2315 | { |