diff options
author | Mattia Dongili <malattia@linux.it> | 2011-05-09 10:20:29 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-05-09 10:28:47 -0400 |
commit | 62d2f23e8bce3e7da4db53928e810fc8a474ce70 (patch) | |
tree | 5f463c8a917131bd38e51bc585aec253e3ba0862 | |
parent | 6192fa7109fb33591fa1078c8c1981e39da02d2d (diff) |
[PATCH] sony-laptop: limit brightness range to DSDT provided ones
The new style brightness control provides an operating range of 9 values
(seems consistent over a large number of models sharing the same
brightness control methods).
Read and use the minimum and maximum values to limit the backlight
interface between those boundaries.
Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 127 |
1 files changed, 103 insertions, 24 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 9d80ae4e6be6..6fe8cd6e23b5 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -934,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, | |||
934 | /* | 934 | /* |
935 | * Backlight device | 935 | * Backlight device |
936 | */ | 936 | */ |
937 | struct sony_backlight_props { | ||
938 | struct backlight_device *dev; | ||
939 | int handle; | ||
940 | u8 offset; | ||
941 | u8 maxlvl; | ||
942 | }; | ||
943 | struct sony_backlight_props sony_bl_props; | ||
944 | |||
937 | static int sony_backlight_update_status(struct backlight_device *bd) | 945 | static int sony_backlight_update_status(struct backlight_device *bd) |
938 | { | 946 | { |
939 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", | 947 | return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", |
@@ -954,19 +962,23 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) | |||
954 | { | 962 | { |
955 | int result; | 963 | int result; |
956 | int *handle = (int *)bl_get_data(bd); | 964 | int *handle = (int *)bl_get_data(bd); |
965 | struct sony_backlight_props *sdev = | ||
966 | (struct sony_backlight_props *)bl_get_data(bd); | ||
957 | 967 | ||
958 | sony_call_snc_handle(*handle, 0x0200, &result); | 968 | sony_call_snc_handle(sdev->handle, 0x0200, &result); |
959 | 969 | ||
960 | return result & 0xff; | 970 | return (result & 0xff) - sdev->offset; |
961 | } | 971 | } |
962 | 972 | ||
963 | static int sony_nc_update_status_ng(struct backlight_device *bd) | 973 | static int sony_nc_update_status_ng(struct backlight_device *bd) |
964 | { | 974 | { |
965 | int value, result; | 975 | int value, result; |
966 | int *handle = (int *)bl_get_data(bd); | 976 | int *handle = (int *)bl_get_data(bd); |
977 | struct sony_backlight_props *sdev = | ||
978 | (struct sony_backlight_props *)bl_get_data(bd); | ||
967 | 979 | ||
968 | value = bd->props.brightness; | 980 | value = bd->props.brightness + sdev->offset; |
969 | if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) | 981 | if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) |
970 | return -EIO; | 982 | return -EIO; |
971 | 983 | ||
972 | return value; | 984 | return value; |
@@ -982,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = { | |||
982 | .update_status = sony_nc_update_status_ng, | 994 | .update_status = sony_nc_update_status_ng, |
983 | .get_brightness = sony_nc_get_brightness_ng, | 995 | .get_brightness = sony_nc_get_brightness_ng, |
984 | }; | 996 | }; |
985 | static int backlight_ng_handle; | ||
986 | static struct backlight_device *sony_backlight_device; | ||
987 | 997 | ||
988 | /* | 998 | /* |
989 | * New SNC-only Vaios event mapping to driver known keys | 999 | * New SNC-only Vaios event mapping to driver known keys |
@@ -1550,6 +1560,75 @@ static void sony_nc_kbd_backlight_resume(void) | |||
1550 | &ignore); | 1560 | &ignore); |
1551 | } | 1561 | } |
1552 | 1562 | ||
1563 | static void sony_nc_backlight_ng_read_limits(int handle, | ||
1564 | struct sony_backlight_props *props) | ||
1565 | { | ||
1566 | int offset; | ||
1567 | acpi_status status; | ||
1568 | u8 brlvl, i; | ||
1569 | u8 min = 0xff, max = 0x00; | ||
1570 | struct acpi_object_list params; | ||
1571 | union acpi_object in_obj; | ||
1572 | union acpi_object *lvl_enum; | ||
1573 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1574 | |||
1575 | props->handle = handle; | ||
1576 | props->offset = 0; | ||
1577 | props->maxlvl = 0xff; | ||
1578 | |||
1579 | offset = sony_find_snc_handle(handle); | ||
1580 | if (offset < 0) | ||
1581 | return; | ||
1582 | |||
1583 | /* try to read the boundaries from ACPI tables, if we fail the above | ||
1584 | * defaults should be reasonable | ||
1585 | */ | ||
1586 | params.count = 1; | ||
1587 | params.pointer = &in_obj; | ||
1588 | in_obj.type = ACPI_TYPE_INTEGER; | ||
1589 | in_obj.integer.value = offset; | ||
1590 | status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, | ||
1591 | &buffer); | ||
1592 | if (ACPI_FAILURE(status)) | ||
1593 | return; | ||
1594 | |||
1595 | lvl_enum = (union acpi_object *) buffer.pointer; | ||
1596 | if (!lvl_enum) { | ||
1597 | pr_err("No SN06 return object."); | ||
1598 | return; | ||
1599 | } | ||
1600 | if (lvl_enum->type != ACPI_TYPE_BUFFER) { | ||
1601 | pr_err("Invalid SN06 return object 0x%.2x\n", | ||
1602 | lvl_enum->type); | ||
1603 | goto out_invalid; | ||
1604 | } | ||
1605 | |||
1606 | /* the buffer lists brightness levels available, brightness levels are | ||
1607 | * from 0 to 8 in the array, other values are used by ALS control. | ||
1608 | */ | ||
1609 | for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { | ||
1610 | |||
1611 | brlvl = *(lvl_enum->buffer.pointer + i); | ||
1612 | dprintk("Brightness level: %d\n", brlvl); | ||
1613 | |||
1614 | if (!brlvl) | ||
1615 | break; | ||
1616 | |||
1617 | if (brlvl > max) | ||
1618 | max = brlvl; | ||
1619 | if (brlvl < min) | ||
1620 | min = brlvl; | ||
1621 | } | ||
1622 | props->offset = min; | ||
1623 | props->maxlvl = max; | ||
1624 | dprintk("Brightness levels: min=%d max=%d\n", props->offset, | ||
1625 | props->maxlvl); | ||
1626 | |||
1627 | out_invalid: | ||
1628 | kfree(buffer.pointer); | ||
1629 | return; | ||
1630 | } | ||
1631 | |||
1553 | static void sony_nc_backlight_setup(void) | 1632 | static void sony_nc_backlight_setup(void) |
1554 | { | 1633 | { |
1555 | acpi_handle unused; | 1634 | acpi_handle unused; |
@@ -1558,14 +1637,14 @@ static void sony_nc_backlight_setup(void) | |||
1558 | struct backlight_properties props; | 1637 | struct backlight_properties props; |
1559 | 1638 | ||
1560 | if (sony_find_snc_handle(0x12f) != -1) { | 1639 | if (sony_find_snc_handle(0x12f) != -1) { |
1561 | backlight_ng_handle = 0x12f; | ||
1562 | ops = &sony_backlight_ng_ops; | 1640 | ops = &sony_backlight_ng_ops; |
1563 | max_brightness = 0xff; | 1641 | sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); |
1642 | max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; | ||
1564 | 1643 | ||
1565 | } else if (sony_find_snc_handle(0x137) != -1) { | 1644 | } else if (sony_find_snc_handle(0x137) != -1) { |
1566 | backlight_ng_handle = 0x137; | ||
1567 | ops = &sony_backlight_ng_ops; | 1645 | ops = &sony_backlight_ng_ops; |
1568 | max_brightness = 0xff; | 1646 | sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); |
1647 | max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; | ||
1569 | 1648 | ||
1570 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", | 1649 | } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", |
1571 | &unused))) { | 1650 | &unused))) { |
@@ -1578,22 +1657,22 @@ static void sony_nc_backlight_setup(void) | |||
1578 | memset(&props, 0, sizeof(struct backlight_properties)); | 1657 | memset(&props, 0, sizeof(struct backlight_properties)); |
1579 | props.type = BACKLIGHT_PLATFORM; | 1658 | props.type = BACKLIGHT_PLATFORM; |
1580 | props.max_brightness = max_brightness; | 1659 | props.max_brightness = max_brightness; |
1581 | sony_backlight_device = backlight_device_register("sony", NULL, | 1660 | sony_bl_props.dev = backlight_device_register("sony", NULL, |
1582 | &backlight_ng_handle, | 1661 | &sony_bl_props, |
1583 | ops, &props); | 1662 | ops, &props); |
1584 | 1663 | ||
1585 | if (IS_ERR(sony_backlight_device)) { | 1664 | if (IS_ERR(sony_bl_props.dev)) { |
1586 | pr_warning(DRV_PFX "unable to register backlight device\n"); | 1665 | pr_warn(DRV_PFX "unable to register backlight device\n"); |
1587 | sony_backlight_device = NULL; | 1666 | sony_bl_props.dev = NULL; |
1588 | } else | 1667 | } else |
1589 | sony_backlight_device->props.brightness = | 1668 | sony_bl_props.dev->props.brightness = |
1590 | ops->get_brightness(sony_backlight_device); | 1669 | ops->get_brightness(sony_bl_props.dev); |
1591 | } | 1670 | } |
1592 | 1671 | ||
1593 | static void sony_nc_backlight_cleanup(void) | 1672 | static void sony_nc_backlight_cleanup(void) |
1594 | { | 1673 | { |
1595 | if (sony_backlight_device) | 1674 | if (sony_bl_props.dev) |
1596 | backlight_device_unregister(sony_backlight_device); | 1675 | backlight_device_unregister(sony_bl_props.dev); |
1597 | } | 1676 | } |
1598 | 1677 | ||
1599 | static int sony_nc_add(struct acpi_device *device) | 1678 | static int sony_nc_add(struct acpi_device *device) |
@@ -2591,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
2591 | mutex_lock(&spic_dev.lock); | 2670 | mutex_lock(&spic_dev.lock); |
2592 | switch (cmd) { | 2671 | switch (cmd) { |
2593 | case SONYPI_IOCGBRT: | 2672 | case SONYPI_IOCGBRT: |
2594 | if (sony_backlight_device == NULL) { | 2673 | if (sony_bl_props.dev == NULL) { |
2595 | ret = -EIO; | 2674 | ret = -EIO; |
2596 | break; | 2675 | break; |
2597 | } | 2676 | } |
@@ -2604,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
2604 | ret = -EFAULT; | 2683 | ret = -EFAULT; |
2605 | break; | 2684 | break; |
2606 | case SONYPI_IOCSBRT: | 2685 | case SONYPI_IOCSBRT: |
2607 | if (sony_backlight_device == NULL) { | 2686 | if (sony_bl_props.dev == NULL) { |
2608 | ret = -EIO; | 2687 | ret = -EIO; |
2609 | break; | 2688 | break; |
2610 | } | 2689 | } |
@@ -2618,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, | |||
2618 | break; | 2697 | break; |
2619 | } | 2698 | } |
2620 | /* sync the backlight device status */ | 2699 | /* sync the backlight device status */ |
2621 | sony_backlight_device->props.brightness = | 2700 | sony_bl_props.dev->props.brightness = |
2622 | sony_backlight_get_brightness(sony_backlight_device); | 2701 | sony_backlight_get_brightness(sony_bl_props.dev); |
2623 | break; | 2702 | break; |
2624 | case SONYPI_IOCGBAT1CAP: | 2703 | case SONYPI_IOCGBAT1CAP: |
2625 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { | 2704 | if (ec_read16(SONYPI_BAT1_FULL, &val16)) { |