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 | |||
