diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2016-07-13 18:06:10 +0200 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2016-08-05 13:39:19 +0200 |
commit | 97f5541fc0c7ed107103e6f87a6522f5327ab4b0 (patch) | |
tree | fa1e72787ac36f7fb130a20d12cad0227bb21717 /drivers/hid | |
parent | 9f1015d45f62d3b1c6719a1ccffaded89b157e10 (diff) | |
download | linux-97f5541fc0c7ed107103e6f87a6522f5327ab4b0.tar.bz2 |
HID: wacom: leds: use the ledclass instead of custom made sysfs files
The now obsolete sysfs files for LEDs and EKRemote are kept for backward
compatibility.
Both the EKR (read-only) and the regular Cintiqs and Intuos are now
sharing the same led API.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Ping Cheng <pingc@wacom.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/wacom.h | 19 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 195 |
2 files changed, 204 insertions, 10 deletions
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 768d69602e7a..0c498c46de5f 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -91,6 +91,7 @@ #include <linux/mod_devicetable.h> #include <linux/hid.h> #include <linux/kfifo.h> +#include <linux/leds.h> #include <linux/usb/input.h> #include <linux/power_supply.h> #include <asm/unaligned.h> @@ -112,8 +113,23 @@ enum wacom_worker { WACOM_WORKER_REMOTE, }; +struct wacom; + +struct wacom_led { + struct led_classdev cdev; + struct led_trigger trigger; + struct wacom *wacom; + unsigned int group; + unsigned int id; + u8 llv; + u8 hlv; + bool held; +}; + struct wacom_group_leds { u8 select; /* status led selector (0..3) */ + struct wacom_led *leds; + unsigned int count; }; struct wacom_battery { @@ -154,9 +170,12 @@ struct wacom { struct wacom_remote *remote; struct wacom_leds { struct wacom_group_leds *groups; + unsigned int count; u8 llv; /* status led brightness no button (1..127) */ u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ + u8 max_llv; /* maximum brightness of LED (llv) */ + u8 max_hlv; /* maximum brightness of LED (hlv) */ } led; struct wacom_battery battery; bool resources; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 1d79215a7968..c5d518da0d0f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -647,6 +647,9 @@ static int wacom_led_control(struct wacom *wacom) unsigned char report_id = WAC_CMD_LED_CONTROL; int buf_size = 9; + if (!hid_get_drvdata(wacom->hdev)) + return -ENODEV; + if (!wacom->led.groups) return -ENOTSUPP; @@ -966,31 +969,194 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom, group); } +static enum led_brightness wacom_leds_brightness_get(struct wacom_led *led) +{ + struct wacom *wacom = led->wacom; + + if (wacom->led.max_hlv) + return led->hlv * LED_FULL / wacom->led.max_hlv; + + if (wacom->led.max_llv) + return led->llv * LED_FULL / wacom->led.max_llv; + + /* device doesn't support brightness tuning */ + return LED_FULL; +} + +static enum led_brightness __wacom_led_brightness_get(struct led_classdev *cdev) +{ + struct wacom_led *led = container_of(cdev, struct wacom_led, cdev); + struct wacom *wacom = led->wacom; + + if (wacom->led.groups[led->group].select != led->id) + return LED_OFF; + + return wacom_leds_brightness_get(led); +} + +static int wacom_led_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct wacom_led *led = container_of(cdev, struct wacom_led, cdev); + struct wacom *wacom = led->wacom; + int error; + + mutex_lock(&wacom->lock); + + if (!wacom->led.groups || (brightness == LED_OFF && + wacom->led.groups[led->group].select != led->id)) { + error = 0; + goto out; + } + + led->llv = wacom->led.llv = wacom->led.max_llv * brightness / LED_FULL; + led->hlv = wacom->led.hlv = wacom->led.max_hlv * brightness / LED_FULL; + + wacom->led.groups[led->group].select = led->id; + + error = wacom_led_control(wacom); + +out: + mutex_unlock(&wacom->lock); + + return error; +} + +static void wacom_led_readonly_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ +} + +static int wacom_led_register_one(struct device *dev, struct wacom *wacom, + struct wacom_led *led, unsigned int group, + unsigned int id, bool read_only) +{ + int error; + char *name; + + name = devm_kasprintf(dev, GFP_KERNEL, + "%s::wacom-%d.%d", + dev_name(dev), + group, + id); + if (!name) + return -ENOMEM; + + led->group = group; + led->id = id; + led->wacom = wacom; + led->llv = wacom->led.llv; + led->hlv = wacom->led.hlv; + led->cdev.name = name; + led->cdev.max_brightness = LED_FULL; + led->cdev.flags = LED_HW_PLUGGABLE; + led->cdev.brightness_get = __wacom_led_brightness_get; + if (!read_only) + led->cdev.brightness_set_blocking = wacom_led_brightness_set; + else + led->cdev.brightness_set = wacom_led_readonly_brightness_set; + + error = devm_led_classdev_register(dev, &led->cdev); + if (error) { + hid_err(wacom->hdev, + "failed to register LED %s: %d\n", + led->cdev.name, error); + led->cdev.name = NULL; + return error; + } + + return 0; +} + +static int wacom_led_groups_alloc_and_register_one(struct device *dev, + struct wacom *wacom, + int group_id, int count, + bool read_only) +{ + struct wacom_led *leds; + int i, error; + + if (group_id >= wacom->led.count || count <= 0) + return -EINVAL; + + if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL)) + return -ENOMEM; + + leds = devm_kzalloc(dev, sizeof(struct wacom_led) * count, GFP_KERNEL); + if (!leds) { + error = -ENOMEM; + goto err; + } + + wacom->led.groups[group_id].leds = leds; + wacom->led.groups[group_id].count = count; + + for (i = 0; i < count; i++) { + error = wacom_led_register_one(dev, wacom, &leds[i], + group_id, i, read_only); + if (error) + goto err; + } + + devres_remove_group(dev, &wacom->led.groups[group_id]); + return 0; + +err: + devres_release_group(dev, &wacom->led.groups[group_id]); + return error; +} + static void wacom_led_groups_release(void *data) { struct wacom *wacom = data; wacom->led.groups = NULL; + wacom->led.count = 0; } static int wacom_led_groups_allocate(struct wacom *wacom, int count) { + struct device *dev = &wacom->hdev->dev; struct wacom_group_leds *groups; int error; - groups = devm_kzalloc(&wacom->hdev->dev, - sizeof(struct wacom_group_leds) * count, + groups = devm_kzalloc(dev, sizeof(struct wacom_group_leds) * count, GFP_KERNEL); if (!groups) return -ENOMEM; - error = devm_add_action_or_reset(&wacom->hdev->dev, - wacom_led_groups_release, - wacom); + error = devm_add_action_or_reset(dev, wacom_led_groups_release, wacom); if (error) return error; wacom->led.groups = groups; + wacom->led.count = count; + + return 0; +} + +static int wacom_leds_alloc_and_register(struct wacom *wacom, int group_count, + int led_per_group, bool read_only) +{ + struct device *dev; + int i, error; + + if (!wacom->wacom_wac.pad_input) + return -EINVAL; + + dev = &wacom->wacom_wac.pad_input->dev; + + error = wacom_led_groups_allocate(wacom, group_count); + if (error) + return error; + + for (i = 0; i < group_count; i++) { + error = wacom_led_groups_alloc_and_register_one(dev, wacom, i, + led_per_group, + read_only); + if (error) + return error; + } return 0; } @@ -1010,9 +1176,11 @@ static int wacom_initialize_leds(struct wacom *wacom) case INTUOS4L: wacom->led.llv = 10; wacom->led.hlv = 20; + wacom->led.max_llv = 127; + wacom->led.max_hlv = 127; wacom->led.img_lum = 10; - error = wacom_led_groups_allocate(wacom, 1); + error = wacom_leds_alloc_and_register(wacom, 1, 4, false); if (error) { hid_err(wacom->hdev, "cannot create leds err: %d\n", error); @@ -1029,7 +1197,7 @@ static int wacom_initialize_leds(struct wacom *wacom) wacom->led.hlv = 0; wacom->led.img_lum = 0; - error = wacom_led_groups_allocate(wacom, 2); + error = wacom_leds_alloc_and_register(wacom, 2, 4, false); if (error) { hid_err(wacom->hdev, "cannot create leds err: %d\n", error); @@ -1047,10 +1215,9 @@ static int wacom_initialize_leds(struct wacom *wacom) case INTUOSPM: case INTUOSPL: wacom->led.llv = 32; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; + wacom->led.max_llv = 96; - error = wacom_led_groups_allocate(wacom, 1); + error = wacom_leds_alloc_and_register(wacom, 1, 4, false); if (error) { hid_err(wacom->hdev, "cannot create leds err: %d\n", error); @@ -1062,6 +1229,8 @@ static int wacom_initialize_leds(struct wacom *wacom) break; case REMOTE: + wacom->led.llv = 255; + wacom->led.max_llv = 255; error = wacom_led_groups_allocate(wacom, 5); if (error) { hid_err(wacom->hdev, @@ -1987,6 +2156,12 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial, if (error) goto fail; + error = wacom_led_groups_alloc_and_register_one( + &remote->remotes[index].input->dev, + wacom, index, 3, true); + if (error) + goto fail; + remote->remotes[index].registered = true; devres_close_group(dev, &remote->remotes[index]); |