Skip to content

Commit 4f4ab4b

Browse files
jigpuJiri Kosina
authored andcommitted
HID: wacom: Improve behavior of non-standard LED brightness values
Assigning a non-standard brightness value to an LED can cause the value to slowly drift downward over time as the effects of integer division accumulate. Each time that an LED is triggered, a series of set and get calls occur. For example, if we assume a tablet with max_hlv = 100, then when brightness is set to "200" through sysfs, the hlv value written to hardware will be `200*100/255 = 78`. If the LED trigger is later activated, the hlv value will be used to determine the brightness: `78*255/100 = 198`. This lower brightness then used to set the brightness of the next LED. However, `198*100/255 = 77`, so the next LED ends up slightly dimmer. Each subsequent trigger activation will cause the brightness to continue drifting down until we reach a point where the result of integer divsion does not introduce any new error. This commit corrects the issue by being more careful about how we handle scaling between the two ranges (0..max_{h,l}lv) and (0..LED_FULL). Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Signed-off-by: Jiri Kosina <jkosina@suse.com>
1 parent 2a770b4 commit 4f4ab4b

File tree

2 files changed

+12
-4
lines changed

2 files changed

+12
-4
lines changed

drivers/hid/wacom.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ static inline __u32 wacom_s32tou(s32 value, __u8 n)
218218
return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value;
219219
}
220220

221+
static inline u32 wacom_rescale(u32 value, u32 in_max, u32 out_max)
222+
{
223+
if (in_max == 0 || out_max == 0)
224+
return 0;
225+
value = clamp(value, 0, in_max);
226+
return DIV_ROUND_CLOSEST(value * out_max, in_max);
227+
}
228+
221229
extern const struct hid_device_id wacom_ids[];
222230

223231
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);

drivers/hid/wacom_sys.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,10 +1302,10 @@ enum led_brightness wacom_leds_brightness_get(struct wacom_led *led)
13021302
struct wacom *wacom = led->wacom;
13031303

13041304
if (wacom->led.max_hlv)
1305-
return led->hlv * LED_FULL / wacom->led.max_hlv;
1305+
return wacom_rescale(led->hlv, wacom->led.max_hlv, LED_FULL);
13061306

13071307
if (wacom->led.max_llv)
1308-
return led->llv * LED_FULL / wacom->led.max_llv;
1308+
return wacom_rescale(led->llv, wacom->led.max_llv, LED_FULL);
13091309

13101310
/* device doesn't support brightness tuning */
13111311
return LED_FULL;
@@ -1337,8 +1337,8 @@ static int wacom_led_brightness_set(struct led_classdev *cdev,
13371337
goto out;
13381338
}
13391339

1340-
led->llv = wacom->led.llv = wacom->led.max_llv * brightness / LED_FULL;
1341-
led->hlv = wacom->led.hlv = wacom->led.max_hlv * brightness / LED_FULL;
1340+
led->llv = wacom->led.llv = wacom_rescale(brightness, LED_FULL, wacom->led.max_llv);
1341+
led->hlv = wacom->led.hlv = wacom_rescale(brightness, LED_FULL, wacom->led.max_hlv);
13421342

13431343
wacom->led.groups[led->group].select = led->id;
13441344

0 commit comments

Comments
 (0)