diff options
-rw-r--r-- | drivers/hid/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hid/wacom.h | 4 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 63 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 53 |
4 files changed, 118 insertions, 3 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 78ac4811bd3c..bdacb552f0a3 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -862,6 +862,7 @@ config HID_WACOM select POWER_SUPPLY select NEW_LEDS select LEDS_CLASS + select LEDS_TRIGGERS help Say Y here if you want to use the USB or BT version of the Wacom Intuos or Graphire tablet. diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 9159dd3e4b90..8f8a16243f07 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -216,4 +216,8 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_battery_work(struct work_struct *work); +enum led_brightness wacom_leds_brightness_get(struct wacom_led *led); +struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group, + unsigned int id); +struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 3a651e288776..7e83352adbde 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -969,7 +969,7 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom, group); } -static enum led_brightness wacom_leds_brightness_get(struct wacom_led *led) +enum led_brightness wacom_leds_brightness_get(struct wacom_led *led) { struct wacom *wacom = led->wacom; @@ -1042,6 +1042,17 @@ static int wacom_led_register_one(struct device *dev, struct wacom *wacom, if (!name) return -ENOMEM; + if (!read_only) { + led->trigger.name = name; + error = devm_led_trigger_register(dev, &led->trigger); + if (error) { + hid_err(wacom->hdev, + "failed to register LED trigger %s: %d\n", + led->cdev.name, error); + return error; + } + } + led->group = group; led->id = id; led->wacom = wacom; @@ -1051,10 +1062,12 @@ static int wacom_led_register_one(struct device *dev, struct wacom *wacom, led->cdev.max_brightness = LED_FULL; led->cdev.flags = LED_HW_PLUGGABLE; led->cdev.brightness_get = __wacom_led_brightness_get; - if (!read_only) + if (!read_only) { led->cdev.brightness_set_blocking = wacom_led_brightness_set; - else + led->cdev.default_trigger = led->cdev.name; + } else { led->cdev.brightness_set = wacom_led_readonly_brightness_set; + } error = devm_led_classdev_register(dev, &led->cdev); if (error) { @@ -1131,6 +1144,50 @@ err: return error; } +struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group_id, + unsigned int id) +{ + struct wacom_group_leds *group; + + if (group_id >= wacom->led.count) + return NULL; + + group = &wacom->led.groups[group_id]; + + if (!group->leds) + return NULL; + + id %= group->count; + + return &group->leds[id]; +} + +/** + * wacom_led_next: gives the next available led with a wacom trigger. + * + * returns the next available struct wacom_led which has its default trigger + * or the current one if none is available. + */ +struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur) +{ + struct wacom_led *next_led; + int group, next; + + if (!wacom || !cur) + return NULL; + + group = cur->group; + next = cur->id; + + do { + next_led = wacom_led_find(wacom, group, ++next); + if (!next_led || next_led == cur) + return next_led; + } while (next_led->cdev.trigger != &next_led->trigger); + + return next_led; +} + static void wacom_led_groups_release(void *data) { struct wacom *wacom = data; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 1c882bb70f14..00e0c80be6d5 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2763,11 +2763,64 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev, __set_bit(BTN_BASE + (i-16), input_dev->keybit); } +static bool wacom_is_led_toggled(struct wacom *wacom, int button_count, + int mask, int group) +{ + int button_per_group; + + button_per_group = button_count/wacom->led.count; + + return mask & (1 << (group * button_per_group)); +} + +static void wacom_update_led(struct wacom *wacom, int button_count, int mask, + int group) +{ + struct wacom_led *led, *next_led; + int cur; + bool pressed; + + pressed = wacom_is_led_toggled(wacom, button_count, mask, group); + cur = wacom->led.groups[group].select; + + led = wacom_led_find(wacom, group, cur); + if (!led) { + hid_err(wacom->hdev, "can't find current LED %d in group %d\n", + cur, group); + return; + } + + if (!pressed) { + led->held = false; + return; + } + + if (led->held && pressed) + return; + + next_led = wacom_led_next(wacom, led); + if (!next_led) { + hid_err(wacom->hdev, "can't find next LED in group %d\n", + group); + return; + } + if (next_led == led) + return; + + next_led->held = true; + led_trigger_event(&next_led->trigger, + wacom_leds_brightness_get(next_led)); +} + static void wacom_report_numbered_buttons(struct input_dev *input_dev, int button_count, int mask) { + struct wacom *wacom = input_get_drvdata(input_dev); int i; + for (i = 0; i < wacom->led.count; i++) + wacom_update_led(wacom, button_count, mask, i); + for (i = 0; i < button_count && i < 10; i++) input_report_key(input_dev, BTN_0 + i, mask & (1 << i)); for (i = 10; i < button_count && i < 16; i++) |