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

authored by Mattia Dongili and committed by Matthew Garrett 62d2f23e 6192fa71

+103 -24
+103 -24
drivers/platform/x86/sony-laptop.c
··· 934 934 /* 935 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 945 static int sony_backlight_update_status(struct backlight_device *bd) 938 946 { 939 947 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", ··· 962 954 { 963 955 int result; 964 956 int *handle = (int *)bl_get_data(bd); 957 + struct sony_backlight_props *sdev = 958 + (struct sony_backlight_props *)bl_get_data(bd); 965 959 966 - sony_call_snc_handle(*handle, 0x0200, &result); 960 + sony_call_snc_handle(sdev->handle, 0x0200, &result); 967 961 968 - return result & 0xff; 962 + return (result & 0xff) - sdev->offset; 969 963 } 970 964 971 965 static int sony_nc_update_status_ng(struct backlight_device *bd) 972 966 { 973 967 int value, result; 974 968 int *handle = (int *)bl_get_data(bd); 969 + struct sony_backlight_props *sdev = 970 + (struct sony_backlight_props *)bl_get_data(bd); 975 971 976 - value = bd->props.brightness; 977 - if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) 972 + value = bd->props.brightness + sdev->offset; 973 + if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) 978 974 return -EIO; 979 975 980 976 return value; ··· 994 982 .update_status = sony_nc_update_status_ng, 995 983 .get_brightness = sony_nc_get_brightness_ng, 996 984 }; 997 - static int backlight_ng_handle; 998 - static struct backlight_device *sony_backlight_device; 999 985 1000 986 /* 1001 987 * New SNC-only Vaios event mapping to driver known keys ··· 1560 1550 &ignore); 1561 1551 } 1562 1552 1553 + static void sony_nc_backlight_ng_read_limits(int handle, 1554 + struct sony_backlight_props *props) 1555 + { 1556 + int offset; 1557 + acpi_status status; 1558 + u8 brlvl, i; 1559 + u8 min = 0xff, max = 0x00; 1560 + struct acpi_object_list params; 1561 + union acpi_object in_obj; 1562 + union acpi_object *lvl_enum; 1563 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 1564 + 1565 + props->handle = handle; 1566 + props->offset = 0; 1567 + props->maxlvl = 0xff; 1568 + 1569 + offset = sony_find_snc_handle(handle); 1570 + if (offset < 0) 1571 + return; 1572 + 1573 + /* try to read the boundaries from ACPI tables, if we fail the above 1574 + * defaults should be reasonable 1575 + */ 1576 + params.count = 1; 1577 + params.pointer = &in_obj; 1578 + in_obj.type = ACPI_TYPE_INTEGER; 1579 + in_obj.integer.value = offset; 1580 + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params, 1581 + &buffer); 1582 + if (ACPI_FAILURE(status)) 1583 + return; 1584 + 1585 + lvl_enum = (union acpi_object *) buffer.pointer; 1586 + if (!lvl_enum) { 1587 + pr_err("No SN06 return object."); 1588 + return; 1589 + } 1590 + if (lvl_enum->type != ACPI_TYPE_BUFFER) { 1591 + pr_err("Invalid SN06 return object 0x%.2x\n", 1592 + lvl_enum->type); 1593 + goto out_invalid; 1594 + } 1595 + 1596 + /* the buffer lists brightness levels available, brightness levels are 1597 + * from 0 to 8 in the array, other values are used by ALS control. 1598 + */ 1599 + for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { 1600 + 1601 + brlvl = *(lvl_enum->buffer.pointer + i); 1602 + dprintk("Brightness level: %d\n", brlvl); 1603 + 1604 + if (!brlvl) 1605 + break; 1606 + 1607 + if (brlvl > max) 1608 + max = brlvl; 1609 + if (brlvl < min) 1610 + min = brlvl; 1611 + } 1612 + props->offset = min; 1613 + props->maxlvl = max; 1614 + dprintk("Brightness levels: min=%d max=%d\n", props->offset, 1615 + props->maxlvl); 1616 + 1617 + out_invalid: 1618 + kfree(buffer.pointer); 1619 + return; 1620 + } 1621 + 1563 1622 static void sony_nc_backlight_setup(void) 1564 1623 { 1565 1624 acpi_handle unused; ··· 1637 1558 struct backlight_properties props; 1638 1559 1639 1560 if (sony_find_snc_handle(0x12f) != -1) { 1640 - backlight_ng_handle = 0x12f; 1641 1561 ops = &sony_backlight_ng_ops; 1642 - max_brightness = 0xff; 1562 + sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); 1563 + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 1643 1564 1644 1565 } else if (sony_find_snc_handle(0x137) != -1) { 1645 - backlight_ng_handle = 0x137; 1646 1566 ops = &sony_backlight_ng_ops; 1647 - max_brightness = 0xff; 1567 + sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); 1568 + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; 1648 1569 1649 1570 } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1650 1571 &unused))) { ··· 1657 1578 memset(&props, 0, sizeof(struct backlight_properties)); 1658 1579 props.type = BACKLIGHT_PLATFORM; 1659 1580 props.max_brightness = max_brightness; 1660 - sony_backlight_device = backlight_device_register("sony", NULL, 1661 - &backlight_ng_handle, 1662 - ops, &props); 1581 + sony_bl_props.dev = backlight_device_register("sony", NULL, 1582 + &sony_bl_props, 1583 + ops, &props); 1663 1584 1664 - if (IS_ERR(sony_backlight_device)) { 1665 - pr_warning(DRV_PFX "unable to register backlight device\n"); 1666 - sony_backlight_device = NULL; 1585 + if (IS_ERR(sony_bl_props.dev)) { 1586 + pr_warn(DRV_PFX "unable to register backlight device\n"); 1587 + sony_bl_props.dev = NULL; 1667 1588 } else 1668 - sony_backlight_device->props.brightness = 1669 - ops->get_brightness(sony_backlight_device); 1589 + sony_bl_props.dev->props.brightness = 1590 + ops->get_brightness(sony_bl_props.dev); 1670 1591 } 1671 1592 1672 1593 static void sony_nc_backlight_cleanup(void) 1673 1594 { 1674 - if (sony_backlight_device) 1675 - backlight_device_unregister(sony_backlight_device); 1595 + if (sony_bl_props.dev) 1596 + backlight_device_unregister(sony_bl_props.dev); 1676 1597 } 1677 1598 1678 1599 static int sony_nc_add(struct acpi_device *device) ··· 2670 2591 mutex_lock(&spic_dev.lock); 2671 2592 switch (cmd) { 2672 2593 case SONYPI_IOCGBRT: 2673 - if (sony_backlight_device == NULL) { 2594 + if (sony_bl_props.dev == NULL) { 2674 2595 ret = -EIO; 2675 2596 break; 2676 2597 } ··· 2683 2604 ret = -EFAULT; 2684 2605 break; 2685 2606 case SONYPI_IOCSBRT: 2686 - if (sony_backlight_device == NULL) { 2607 + if (sony_bl_props.dev == NULL) { 2687 2608 ret = -EIO; 2688 2609 break; 2689 2610 } ··· 2697 2618 break; 2698 2619 } 2699 2620 /* sync the backlight device status */ 2700 - sony_backlight_device->props.brightness = 2701 - sony_backlight_get_brightness(sony_backlight_device); 2621 + sony_bl_props.dev->props.brightness = 2622 + sony_backlight_get_brightness(sony_bl_props.dev); 2702 2623 break; 2703 2624 case SONYPI_IOCGBAT1CAP: 2704 2625 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {