diff options
author | Len Brown <len.brown@intel.com> | 2009-04-05 01:40:06 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-04-05 01:40:06 -0400 |
commit | 12648810506eaa063dc23b66514fbb4796f34312 (patch) | |
tree | 4cd16290c9e1350d946a92ca8d5624cdd683b739 | |
parent | 7329e9356e5b46e11a1781dff2dc64c2e3284884 (diff) | |
parent | 03ae61dd5701092aabb60a8cae9929dbf8dc25c6 (diff) |
Merge branch 'video' into release
Conflicts:
drivers/acpi/video.c
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/video.c | 279 | ||||
-rw-r--r-- | drivers/acpi/video_detect.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_opregion.c | 65 | ||||
-rw-r--r-- | include/acpi/video.h | 11 |
7 files changed, 306 insertions, 63 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5259d502add6..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 = { |
@@ -376,7 +390,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned | |||
376 | unsigned long long level; | 390 | unsigned long long level; |
377 | int offset; | 391 | int offset; |
378 | 392 | ||
379 | acpi_video_device_lcd_get_level_current(video, &level); | 393 | if (acpi_video_device_lcd_get_level_current(video, &level)) |
394 | return -EINVAL; | ||
380 | for (offset = 2; offset < video->brightness->count; offset++) | 395 | for (offset = 2; offset < video->brightness->count; offset++) |
381 | if (level == video->brightness->levels[offset]) { | 396 | if (level == video->brightness->levels[offset]) { |
382 | *state = video->brightness->count - offset - 1; | 397 | *state = video->brightness->count - offset - 1; |
@@ -483,34 +498,68 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, | |||
483 | static int | 498 | static int |
484 | 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) |
485 | { | 500 | { |
486 | int status = AE_OK; | 501 | int status; |
487 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 502 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
488 | struct acpi_object_list args = { 1, &arg0 }; | 503 | struct acpi_object_list args = { 1, &arg0 }; |
489 | int state; | 504 | int state; |
490 | 505 | ||
491 | |||
492 | arg0.integer.value = level; | 506 | arg0.integer.value = level; |
493 | 507 | ||
494 | if (device->cap._BCM) | 508 | status = acpi_evaluate_object(device->dev->handle, "_BCM", |
495 | status = acpi_evaluate_object(device->dev->handle, "_BCM", | 509 | &args, NULL); |
496 | &args, NULL); | 510 | if (ACPI_FAILURE(status)) { |
511 | ACPI_ERROR((AE_INFO, "Evaluating _BCM failed")); | ||
512 | return -EIO; | ||
513 | } | ||
514 | |||
497 | device->brightness->curr = level; | 515 | device->brightness->curr = level; |
498 | for (state = 2; state < device->brightness->count; state++) | 516 | for (state = 2; state < device->brightness->count; state++) |
499 | if (level == device->brightness->levels[state]) | 517 | if (level == device->brightness->levels[state]) { |
500 | device->backlight->props.brightness = state - 2; | 518 | if (device->backlight) |
519 | device->backlight->props.brightness = state - 2; | ||
520 | return 0; | ||
521 | } | ||
501 | 522 | ||
502 | return status; | 523 | ACPI_ERROR((AE_INFO, "Current brightness invalid")); |
524 | return -EINVAL; | ||
503 | } | 525 | } |
504 | 526 | ||
505 | static int | 527 | static int |
506 | 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, |
507 | unsigned long long *level) | 529 | unsigned long long *level) |
508 | { | 530 | { |
509 | if (device->cap._BQC) | 531 | acpi_status status = AE_OK; |
510 | return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, | 532 | |
511 | 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 | |||
512 | *level = device->brightness->curr; | 561 | *level = device->brightness->curr; |
513 | return AE_OK; | 562 | return 0; |
514 | } | 563 | } |
515 | 564 | ||
516 | static int | 565 | static int |
@@ -659,9 +708,11 @@ static int | |||
659 | acpi_video_init_brightness(struct acpi_video_device *device) | 708 | acpi_video_init_brightness(struct acpi_video_device *device) |
660 | { | 709 | { |
661 | union acpi_object *obj = NULL; | 710 | union acpi_object *obj = NULL; |
662 | 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; | ||
663 | union acpi_object *o; | 713 | union acpi_object *o; |
664 | struct acpi_video_device_brightness *br = NULL; | 714 | struct acpi_video_device_brightness *br = NULL; |
715 | int result = -EINVAL; | ||
665 | 716 | ||
666 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { | 717 | if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
667 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " | 718 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " |
@@ -675,13 +726,16 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
675 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 726 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
676 | if (!br) { | 727 | if (!br) { |
677 | printk(KERN_ERR "can't allocate memory\n"); | 728 | printk(KERN_ERR "can't allocate memory\n"); |
729 | result = -ENOMEM; | ||
678 | goto out; | 730 | goto out; |
679 | } | 731 | } |
680 | 732 | ||
681 | br->levels = kmalloc(obj->package.count * sizeof *(br->levels), | 733 | br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), |
682 | GFP_KERNEL); | 734 | GFP_KERNEL); |
683 | if (!br->levels) | 735 | if (!br->levels) { |
736 | result = -ENOMEM; | ||
684 | goto out_free; | 737 | goto out_free; |
738 | } | ||
685 | 739 | ||
686 | for (i = 0; i < obj->package.count; i++) { | 740 | for (i = 0; i < obj->package.count; i++) { |
687 | o = (union acpi_object *)&obj->package.elements[i]; | 741 | o = (union acpi_object *)&obj->package.elements[i]; |
@@ -696,18 +750,86 @@ acpi_video_init_brightness(struct acpi_video_device *device) | |||
696 | count++; | 750 | count++; |
697 | } | 751 | } |
698 | 752 | ||
699 | /* don't sort the first two brightness levels */ | 753 | /* |
700 | sort(&br->levels[2], count - 2, sizeof(br->levels[2]), | 754 | * some buggy BIOS don't export the levels |
701 | acpi_video_cmp_level, NULL); | 755 | * when machine is on AC/Battery in _BCL package. |
702 | 756 | * In this case, the first two elements in _BCL packages | |
703 | if (count < 2) | 757 | * are also supported brightness levels that OS should take care of. |
704 | 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")); | ||
705 | 781 | ||
706 | br->count = count; | 782 | br->count = count; |
707 | device->brightness = br; | 783 | device->brightness = br; |
708 | 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)); | ||
709 | kfree(obj); | 831 | kfree(obj); |
710 | return max_level; | 832 | return result; |
711 | 833 | ||
712 | out_free_levels: | 834 | out_free_levels: |
713 | kfree(br->levels); | 835 | kfree(br->levels); |
@@ -716,7 +838,7 @@ out_free: | |||
716 | out: | 838 | out: |
717 | device->brightness = NULL; | 839 | device->brightness = NULL; |
718 | kfree(obj); | 840 | kfree(obj); |
719 | return 0; | 841 | return result; |
720 | } | 842 | } |
721 | 843 | ||
722 | /* | 844 | /* |
@@ -733,7 +855,6 @@ out: | |||
733 | 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) |
734 | { | 856 | { |
735 | acpi_handle h_dummy1; | 857 | acpi_handle h_dummy1; |
736 | u32 max_level = 0; | ||
737 | 858 | ||
738 | 859 | ||
739 | memset(&device->cap, 0, sizeof(device->cap)); | 860 | memset(&device->cap, 0, sizeof(device->cap)); |
@@ -749,6 +870,12 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
749 | } | 870 | } |
750 | 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))) |
751 | 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 | |||
752 | 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))) { |
753 | device->cap._DDC = 1; | 880 | device->cap._DDC = 1; |
754 | } | 881 | } |
@@ -762,13 +889,14 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
762 | device->cap._DSS = 1; | 889 | device->cap._DSS = 1; |
763 | } | 890 | } |
764 | 891 | ||
765 | if (acpi_video_backlight_support()) | 892 | if (acpi_video_backlight_support()) { |
766 | max_level = acpi_video_init_brightness(device); | ||
767 | |||
768 | if (device->cap._BCL && device->cap._BCM && max_level > 0) { | ||
769 | int result; | 893 | int result; |
770 | static int count = 0; | 894 | static int count = 0; |
771 | char *name; | 895 | char *name; |
896 | |||
897 | result = acpi_video_init_brightness(device); | ||
898 | if (result) | ||
899 | return; | ||
772 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | 900 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); |
773 | if (!name) | 901 | if (!name) |
774 | return; | 902 | return; |
@@ -777,18 +905,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
777 | device->backlight = backlight_device_register(name, | 905 | device->backlight = backlight_device_register(name, |
778 | NULL, device, &acpi_backlight_ops); | 906 | NULL, device, &acpi_backlight_ops); |
779 | device->backlight->props.max_brightness = device->brightness->count-3; | 907 | device->backlight->props.max_brightness = device->brightness->count-3; |
780 | /* | ||
781 | * If there exists the _BQC object, the _BQC object will be | ||
782 | * called to get the current backlight brightness. Otherwise | ||
783 | * the brightness will be set to the maximum. | ||
784 | */ | ||
785 | if (device->cap._BQC) | ||
786 | device->backlight->props.brightness = | ||
787 | acpi_video_get_brightness(device->backlight); | ||
788 | else | ||
789 | device->backlight->props.brightness = | ||
790 | device->backlight->props.max_brightness; | ||
791 | backlight_update_status(device->backlight); | ||
792 | kfree(name); | 908 | kfree(name); |
793 | 909 | ||
794 | device->cdev = thermal_cooling_device_register("LCD", | 910 | device->cdev = thermal_cooling_device_register("LCD", |
@@ -1065,13 +1181,12 @@ acpi_video_device_write_brightness(struct file *file, | |||
1065 | /* validate through the list of available levels */ | 1181 | /* validate through the list of available levels */ |
1066 | for (i = 2; i < dev->brightness->count; i++) | 1182 | for (i = 2; i < dev->brightness->count; i++) |
1067 | if (level == dev->brightness->levels[i]) { | 1183 | if (level == dev->brightness->levels[i]) { |
1068 | if (ACPI_SUCCESS | 1184 | if (!acpi_video_device_lcd_set_level(dev, level)) |
1069 | (acpi_video_device_lcd_set_level(dev, level))) | 1185 | return count; |
1070 | dev->brightness->curr = level; | ||
1071 | break; | 1186 | break; |
1072 | } | 1187 | } |
1073 | 1188 | ||
1074 | return count; | 1189 | return -EINVAL; |
1075 | } | 1190 | } |
1076 | 1191 | ||
1077 | 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) |
@@ -1753,15 +1868,29 @@ acpi_video_get_next_level(struct acpi_video_device *device, | |||
1753 | } | 1868 | } |
1754 | } | 1869 | } |
1755 | 1870 | ||
1756 | static void | 1871 | static int |
1757 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) | 1872 | acpi_video_switch_brightness(struct acpi_video_device *device, int event) |
1758 | { | 1873 | { |
1759 | unsigned long long level_current, level_next; | 1874 | unsigned long long level_current, level_next; |
1875 | int result = -EINVAL; | ||
1876 | |||
1760 | if (!device->brightness) | 1877 | if (!device->brightness) |
1761 | return; | 1878 | goto out; |
1762 | 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 | |||
1763 | level_next = acpi_video_get_next_level(device, level_current, event); | 1885 | level_next = acpi_video_get_next_level(device, level_current, event); |
1764 | 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; | ||
1765 | } | 1894 | } |
1766 | 1895 | ||
1767 | static int | 1896 | static int |
@@ -2128,7 +2257,27 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) | |||
2128 | return 0; | 2257 | return 0; |
2129 | } | 2258 | } |
2130 | 2259 | ||
2131 | 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) | ||
2132 | { | 2281 | { |
2133 | int result = 0; | 2282 | int result = 0; |
2134 | 2283 | ||
@@ -2145,6 +2294,22 @@ static int __init acpi_video_init(void) | |||
2145 | 2294 | ||
2146 | return 0; | 2295 | return 0; |
2147 | } | 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 | } | ||
2148 | 2313 | ||
2149 | static void __exit acpi_video_exit(void) | 2314 | static void __exit acpi_video_exit(void) |
2150 | { | 2315 | { |
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 50e3d2dbf3af..09737275e25f 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c | |||
@@ -55,6 +55,9 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, | |||
55 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " | 55 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " |
56 | "support\n")); | 56 | "support\n")); |
57 | *cap |= ACPI_VIDEO_BACKLIGHT; | 57 | *cap |= ACPI_VIDEO_BACKLIGHT; |
58 | if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy))) | ||
59 | printk(KERN_WARNING FW_BUG PREFIX "ACPI brightness " | ||
60 | "control misses _BQC function\n"); | ||
58 | /* We have backlight support, no need to scan further */ | 61 | /* We have backlight support, no need to scan further */ |
59 | return AE_CTRL_TERMINATE; | 62 | return AE_CTRL_TERMINATE; |
60 | } | 63 | } |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 6d21b9e48b89..638686904e06 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1144,8 +1144,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1144 | if (!IS_I945G(dev) && !IS_I945GM(dev)) | 1144 | if (!IS_I945G(dev) && !IS_I945GM(dev)) |
1145 | pci_enable_msi(dev->pdev); | 1145 | pci_enable_msi(dev->pdev); |
1146 | 1146 | ||
1147 | intel_opregion_init(dev); | ||
1148 | |||
1149 | spin_lock_init(&dev_priv->user_irq_lock); | 1147 | spin_lock_init(&dev_priv->user_irq_lock); |
1150 | dev_priv->user_irq_refcount = 0; | 1148 | dev_priv->user_irq_refcount = 0; |
1151 | 1149 | ||
@@ -1164,6 +1162,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1164 | } | 1162 | } |
1165 | } | 1163 | } |
1166 | 1164 | ||
1165 | /* Must be done after probing outputs */ | ||
1166 | intel_opregion_init(dev, 0); | ||
1167 | |||
1167 | return 0; | 1168 | return 0; |
1168 | 1169 | ||
1169 | out_iomapfree: | 1170 | out_iomapfree: |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b293ef0bae71..209592fdb7e7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -99,7 +99,7 @@ static int i915_resume(struct drm_device *dev) | |||
99 | 99 | ||
100 | i915_restore_state(dev); | 100 | i915_restore_state(dev); |
101 | 101 | ||
102 | intel_opregion_init(dev); | 102 | intel_opregion_init(dev, 1); |
103 | 103 | ||
104 | /* KMS EnterVT equivalent */ | 104 | /* KMS EnterVT equivalent */ |
105 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 105 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d6cc9861e0a1..b9a92c250b91 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -659,12 +659,12 @@ extern int i915_restore_state(struct drm_device *dev); | |||
659 | 659 | ||
660 | #ifdef CONFIG_ACPI | 660 | #ifdef CONFIG_ACPI |
661 | /* i915_opregion.c */ | 661 | /* i915_opregion.c */ |
662 | extern int intel_opregion_init(struct drm_device *dev); | 662 | extern int intel_opregion_init(struct drm_device *dev, int resume); |
663 | extern void intel_opregion_free(struct drm_device *dev); | 663 | extern void intel_opregion_free(struct drm_device *dev); |
664 | extern void opregion_asle_intr(struct drm_device *dev); | 664 | extern void opregion_asle_intr(struct drm_device *dev); |
665 | extern void opregion_enable_asle(struct drm_device *dev); | 665 | extern void opregion_enable_asle(struct drm_device *dev); |
666 | #else | 666 | #else |
667 | static inline int intel_opregion_init(struct drm_device *dev) { return 0; } | 667 | static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; } |
668 | static inline void intel_opregion_free(struct drm_device *dev) { return; } | 668 | static inline void intel_opregion_free(struct drm_device *dev) { return; } |
669 | static inline void opregion_asle_intr(struct drm_device *dev) { return; } | 669 | static inline void opregion_asle_intr(struct drm_device *dev) { return; } |
670 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } | 670 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } |
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index ff012835a386..69427722d20e 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
29 | #include <acpi/video.h> | ||
29 | 30 | ||
30 | #include "drmP.h" | 31 | #include "drmP.h" |
31 | #include "i915_drm.h" | 32 | #include "i915_drm.h" |
@@ -136,6 +137,12 @@ struct opregion_asle { | |||
136 | 137 | ||
137 | #define ASLE_CBLV_VALID (1<<31) | 138 | #define ASLE_CBLV_VALID (1<<31) |
138 | 139 | ||
140 | #define ACPI_OTHER_OUTPUT (0<<8) | ||
141 | #define ACPI_VGA_OUTPUT (1<<8) | ||
142 | #define ACPI_TV_OUTPUT (2<<8) | ||
143 | #define ACPI_DIGITAL_OUTPUT (3<<8) | ||
144 | #define ACPI_LVDS_OUTPUT (4<<8) | ||
145 | |||
139 | static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) | 146 | static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) |
140 | { | 147 | { |
141 | struct drm_i915_private *dev_priv = dev->dev_private; | 148 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -282,7 +289,58 @@ static struct notifier_block intel_opregion_notifier = { | |||
282 | .notifier_call = intel_opregion_video_event, | 289 | .notifier_call = intel_opregion_video_event, |
283 | }; | 290 | }; |
284 | 291 | ||
285 | int intel_opregion_init(struct drm_device *dev) | 292 | /* |
293 | * Initialise the DIDL field in opregion. This passes a list of devices to | ||
294 | * the firmware. Values are defined by section B.4.2 of the ACPI specification | ||
295 | * (version 3) | ||
296 | */ | ||
297 | |||
298 | static void intel_didl_outputs(struct drm_device *dev) | ||
299 | { | ||
300 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
301 | struct intel_opregion *opregion = &dev_priv->opregion; | ||
302 | struct drm_connector *connector; | ||
303 | int i = 0; | ||
304 | |||
305 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
306 | int output_type = ACPI_OTHER_OUTPUT; | ||
307 | if (i >= 8) { | ||
308 | dev_printk (KERN_ERR, &dev->pdev->dev, | ||
309 | "More than 8 outputs detected\n"); | ||
310 | return; | ||
311 | } | ||
312 | switch (connector->connector_type) { | ||
313 | case DRM_MODE_CONNECTOR_VGA: | ||
314 | case DRM_MODE_CONNECTOR_DVIA: | ||
315 | output_type = ACPI_VGA_OUTPUT; | ||
316 | break; | ||
317 | case DRM_MODE_CONNECTOR_Composite: | ||
318 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
319 | case DRM_MODE_CONNECTOR_Component: | ||
320 | case DRM_MODE_CONNECTOR_9PinDIN: | ||
321 | output_type = ACPI_TV_OUTPUT; | ||
322 | break; | ||
323 | case DRM_MODE_CONNECTOR_DVII: | ||
324 | case DRM_MODE_CONNECTOR_DVID: | ||
325 | case DRM_MODE_CONNECTOR_DisplayPort: | ||
326 | case DRM_MODE_CONNECTOR_HDMIA: | ||
327 | case DRM_MODE_CONNECTOR_HDMIB: | ||
328 | output_type = ACPI_DIGITAL_OUTPUT; | ||
329 | break; | ||
330 | case DRM_MODE_CONNECTOR_LVDS: | ||
331 | output_type = ACPI_LVDS_OUTPUT; | ||
332 | break; | ||
333 | } | ||
334 | opregion->acpi->didl[i] |= (1<<31) | output_type | i; | ||
335 | i++; | ||
336 | } | ||
337 | |||
338 | /* If fewer than 8 outputs, the list must be null terminated */ | ||
339 | if (i < 8) | ||
340 | opregion->acpi->didl[i] = 0; | ||
341 | } | ||
342 | |||
343 | int intel_opregion_init(struct drm_device *dev, int resume) | ||
286 | { | 344 | { |
287 | struct drm_i915_private *dev_priv = dev->dev_private; | 345 | struct drm_i915_private *dev_priv = dev->dev_private; |
288 | struct intel_opregion *opregion = &dev_priv->opregion; | 346 | struct intel_opregion *opregion = &dev_priv->opregion; |
@@ -312,6 +370,11 @@ int intel_opregion_init(struct drm_device *dev) | |||
312 | if (mboxes & MBOX_ACPI) { | 370 | if (mboxes & MBOX_ACPI) { |
313 | DRM_DEBUG("Public ACPI methods supported\n"); | 371 | DRM_DEBUG("Public ACPI methods supported\n"); |
314 | opregion->acpi = base + OPREGION_ACPI_OFFSET; | 372 | opregion->acpi = base + OPREGION_ACPI_OFFSET; |
373 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
374 | intel_didl_outputs(dev); | ||
375 | if (!resume) | ||
376 | acpi_video_register(); | ||
377 | } | ||
315 | } else { | 378 | } else { |
316 | DRM_DEBUG("Public ACPI methods not supported\n"); | 379 | DRM_DEBUG("Public ACPI methods not supported\n"); |
317 | err = -ENOTSUPP; | 380 | err = -ENOTSUPP; |
diff --git a/include/acpi/video.h b/include/acpi/video.h new file mode 100644 index 000000000000..f0275bb79ce4 --- /dev/null +++ b/include/acpi/video.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef __ACPI_VIDEO_H | ||
2 | #define __ACPI_VIDEO_H | ||
3 | |||
4 | #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE) | ||
5 | extern int acpi_video_register(void); | ||
6 | #else | ||
7 | static inline int acpi_video_register(void) { return 0; } | ||
8 | #endif | ||
9 | |||
10 | #endif | ||
11 | |||