diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2016-07-13 12:06:10 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2016-08-05 07:39:19 -0400 |
commit | 97f5541fc0c7ed107103e6f87a6522f5327ab4b0 (patch) | |
tree | fa1e72787ac36f7fb130a20d12cad0227bb21717 | |
parent | 9f1015d45f62d3b1c6719a1ccffaded89b157e10 (diff) |
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>
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-wacom | 5 | ||||
-rw-r--r-- | drivers/hid/wacom.h | 19 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 195 |
3 files changed, 209 insertions, 10 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index dca429340772..2aa5503ee200 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom | |||
@@ -24,6 +24,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status0_luminance | |||
24 | Date: August 2014 | 24 | Date: August 2014 |
25 | Contact: linux-input@vger.kernel.org | 25 | Contact: linux-input@vger.kernel.org |
26 | Description: | 26 | Description: |
27 | <obsoleted by the LED class API now exported by the driver> | ||
27 | Writing to this file sets the status LED luminance (1..127) | 28 | Writing to this file sets the status LED luminance (1..127) |
28 | when the stylus does not touch the tablet surface, and no | 29 | when the stylus does not touch the tablet surface, and no |
29 | button is pressed on the stylus. This luminance level is | 30 | button is pressed on the stylus. This luminance level is |
@@ -33,6 +34,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status1_luminance | |||
33 | Date: August 2014 | 34 | Date: August 2014 |
34 | Contact: linux-input@vger.kernel.org | 35 | Contact: linux-input@vger.kernel.org |
35 | Description: | 36 | Description: |
37 | <obsoleted by the LED class API now exported by the driver> | ||
36 | Writing to this file sets the status LED luminance (1..127) | 38 | Writing to this file sets the status LED luminance (1..127) |
37 | when the stylus touches the tablet surface, or any button is | 39 | when the stylus touches the tablet surface, or any button is |
38 | pressed on the stylus. | 40 | pressed on the stylus. |
@@ -41,6 +43,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led0_select | |||
41 | Date: August 2014 | 43 | Date: August 2014 |
42 | Contact: linux-input@vger.kernel.org | 44 | Contact: linux-input@vger.kernel.org |
43 | Description: | 45 | Description: |
46 | <obsoleted by the LED class API now exported by the driver> | ||
44 | Writing to this file sets which one of the four (for Intuos 4 | 47 | Writing to this file sets which one of the four (for Intuos 4 |
45 | and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq | 48 | and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq |
46 | 24HD) status LEDs is active (0..3). The other three LEDs on the | 49 | 24HD) status LEDs is active (0..3). The other three LEDs on the |
@@ -50,6 +53,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_led/status_led1_select | |||
50 | Date: August 2014 | 53 | Date: August 2014 |
51 | Contact: linux-input@vger.kernel.org | 54 | Contact: linux-input@vger.kernel.org |
52 | Description: | 55 | Description: |
56 | <obsoleted by the LED class API now exported by the driver> | ||
53 | Writing to this file sets which one of the left four (for Cintiq 21UX2 | 57 | Writing to this file sets which one of the left four (for Cintiq 21UX2 |
54 | and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on | 58 | and Cintiq 24HD) status LEDs is active (0..3). The other three LEDs on |
55 | the left are always inactive. | 59 | the left are always inactive. |
@@ -91,6 +95,7 @@ What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/wacom_remote/<serial_number>/r | |||
91 | Date: July 2015 | 95 | Date: July 2015 |
92 | Contact: linux-input@vger.kernel.org | 96 | Contact: linux-input@vger.kernel.org |
93 | Description: | 97 | Description: |
98 | <obsoleted by the LED class API now exported by the driver> | ||
94 | Reading from this file reports the mode status of the | 99 | Reading from this file reports the mode status of the |
95 | remote as indicated by the LED lights on the device. If no | 100 | remote as indicated by the LED lights on the device. If no |
96 | reports have been received from the paired device, reading | 101 | reports have been received from the paired device, reading |
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 @@ | |||
91 | #include <linux/mod_devicetable.h> | 91 | #include <linux/mod_devicetable.h> |
92 | #include <linux/hid.h> | 92 | #include <linux/hid.h> |
93 | #include <linux/kfifo.h> | 93 | #include <linux/kfifo.h> |
94 | #include <linux/leds.h> | ||
94 | #include <linux/usb/input.h> | 95 | #include <linux/usb/input.h> |
95 | #include <linux/power_supply.h> | 96 | #include <linux/power_supply.h> |
96 | #include <asm/unaligned.h> | 97 | #include <asm/unaligned.h> |
@@ -112,8 +113,23 @@ enum wacom_worker { | |||
112 | WACOM_WORKER_REMOTE, | 113 | WACOM_WORKER_REMOTE, |
113 | }; | 114 | }; |
114 | 115 | ||
116 | struct wacom; | ||
117 | |||
118 | struct wacom_led { | ||
119 | struct led_classdev cdev; | ||
120 | struct led_trigger trigger; | ||
121 | struct wacom *wacom; | ||
122 | unsigned int group; | ||
123 | unsigned int id; | ||
124 | u8 llv; | ||
125 | u8 hlv; | ||
126 | bool held; | ||
127 | }; | ||
128 | |||
115 | struct wacom_group_leds { | 129 | struct wacom_group_leds { |
116 | u8 select; /* status led selector (0..3) */ | 130 | u8 select; /* status led selector (0..3) */ |
131 | struct wacom_led *leds; | ||
132 | unsigned int count; | ||
117 | }; | 133 | }; |
118 | 134 | ||
119 | struct wacom_battery { | 135 | struct wacom_battery { |
@@ -154,9 +170,12 @@ struct wacom { | |||
154 | struct wacom_remote *remote; | 170 | struct wacom_remote *remote; |
155 | struct wacom_leds { | 171 | struct wacom_leds { |
156 | struct wacom_group_leds *groups; | 172 | struct wacom_group_leds *groups; |
173 | unsigned int count; | ||
157 | u8 llv; /* status led brightness no button (1..127) */ | 174 | u8 llv; /* status led brightness no button (1..127) */ |
158 | u8 hlv; /* status led brightness button pressed (1..127) */ | 175 | u8 hlv; /* status led brightness button pressed (1..127) */ |
159 | u8 img_lum; /* OLED matrix display brightness */ | 176 | u8 img_lum; /* OLED matrix display brightness */ |
177 | u8 max_llv; /* maximum brightness of LED (llv) */ | ||
178 | u8 max_hlv; /* maximum brightness of LED (hlv) */ | ||
160 | } led; | 179 | } led; |
161 | struct wacom_battery battery; | 180 | struct wacom_battery battery; |
162 | bool resources; | 181 | 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) | |||
647 | unsigned char report_id = WAC_CMD_LED_CONTROL; | 647 | unsigned char report_id = WAC_CMD_LED_CONTROL; |
648 | int buf_size = 9; | 648 | int buf_size = 9; |
649 | 649 | ||
650 | if (!hid_get_drvdata(wacom->hdev)) | ||
651 | return -ENODEV; | ||
652 | |||
650 | if (!wacom->led.groups) | 653 | if (!wacom->led.groups) |
651 | return -ENOTSUPP; | 654 | return -ENOTSUPP; |
652 | 655 | ||
@@ -966,31 +969,194 @@ static int wacom_devm_sysfs_create_group(struct wacom *wacom, | |||
966 | group); | 969 | group); |
967 | } | 970 | } |
968 | 971 | ||
972 | static enum led_brightness wacom_leds_brightness_get(struct wacom_led *led) | ||
973 | { | ||
974 | struct wacom *wacom = led->wacom; | ||
975 | |||
976 | if (wacom->led.max_hlv) | ||
977 | return led->hlv * LED_FULL / wacom->led.max_hlv; | ||
978 | |||
979 | if (wacom->led.max_llv) | ||
980 | return led->llv * LED_FULL / wacom->led.max_llv; | ||
981 | |||
982 | /* device doesn't support brightness tuning */ | ||
983 | return LED_FULL; | ||
984 | } | ||
985 | |||
986 | static enum led_brightness __wacom_led_brightness_get(struct led_classdev *cdev) | ||
987 | { | ||
988 | struct wacom_led *led = container_of(cdev, struct wacom_led, cdev); | ||
989 | struct wacom *wacom = led->wacom; | ||
990 | |||
991 | if (wacom->led.groups[led->group].select != led->id) | ||
992 | return LED_OFF; | ||
993 | |||
994 | return wacom_leds_brightness_get(led); | ||
995 | } | ||
996 | |||
997 | static int wacom_led_brightness_set(struct led_classdev *cdev, | ||
998 | enum led_brightness brightness) | ||
999 | { | ||
1000 | struct wacom_led *led = container_of(cdev, struct wacom_led, cdev); | ||
1001 | struct wacom *wacom = led->wacom; | ||
1002 | int error; | ||
1003 | |||
1004 | mutex_lock(&wacom->lock); | ||
1005 | |||
1006 | if (!wacom->led.groups || (brightness == LED_OFF && | ||
1007 | wacom->led.groups[led->group].select != led->id)) { | ||
1008 | error = 0; | ||
1009 | goto out; | ||
1010 | } | ||
1011 | |||
1012 | led->llv = wacom->led.llv = wacom->led.max_llv * brightness / LED_FULL; | ||
1013 | led->hlv = wacom->led.hlv = wacom->led.max_hlv * brightness / LED_FULL; | ||
1014 | |||
1015 | wacom->led.groups[led->group].select = led->id; | ||
1016 | |||
1017 | error = wacom_led_control(wacom); | ||
1018 | |||
1019 | out: | ||
1020 | mutex_unlock(&wacom->lock); | ||
1021 | |||
1022 | return error; | ||
1023 | } | ||
1024 | |||
1025 | static void wacom_led_readonly_brightness_set(struct led_classdev *cdev, | ||
1026 | enum led_brightness brightness) | ||
1027 | { | ||
1028 | } | ||
1029 | |||
1030 | static int wacom_led_register_one(struct device *dev, struct wacom *wacom, | ||
1031 | struct wacom_led *led, unsigned int group, | ||
1032 | unsigned int id, bool read_only) | ||
1033 | { | ||
1034 | int error; | ||
1035 | char *name; | ||
1036 | |||
1037 | name = devm_kasprintf(dev, GFP_KERNEL, | ||
1038 | "%s::wacom-%d.%d", | ||
1039 | dev_name(dev), | ||
1040 | group, | ||
1041 | id); | ||
1042 | if (!name) | ||
1043 | return -ENOMEM; | ||
1044 | |||
1045 | led->group = group; | ||
1046 | led->id = id; | ||
1047 | led->wacom = wacom; | ||
1048 | led->llv = wacom->led.llv; | ||
1049 | led->hlv = wacom->led.hlv; | ||
1050 | led->cdev.name = name; | ||
1051 | led->cdev.max_brightness = LED_FULL; | ||
1052 | led->cdev.flags = LED_HW_PLUGGABLE; | ||
1053 | led->cdev.brightness_get = __wacom_led_brightness_get; | ||
1054 | if (!read_only) | ||
1055 | led->cdev.brightness_set_blocking = wacom_led_brightness_set; | ||
1056 | else | ||
1057 | led->cdev.brightness_set = wacom_led_readonly_brightness_set; | ||
1058 | |||
1059 | error = devm_led_classdev_register(dev, &led->cdev); | ||
1060 | if (error) { | ||
1061 | hid_err(wacom->hdev, | ||
1062 | "failed to register LED %s: %d\n", | ||
1063 | led->cdev.name, error); | ||
1064 | led->cdev.name = NULL; | ||
1065 | return error; | ||
1066 | } | ||
1067 | |||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int wacom_led_groups_alloc_and_register_one(struct device *dev, | ||
1072 | struct wacom *wacom, | ||
1073 | int group_id, int count, | ||
1074 | bool read_only) | ||
1075 | { | ||
1076 | struct wacom_led *leds; | ||
1077 | int i, error; | ||
1078 | |||
1079 | if (group_id >= wacom->led.count || count <= 0) | ||
1080 | return -EINVAL; | ||
1081 | |||
1082 | if (!devres_open_group(dev, &wacom->led.groups[group_id], GFP_KERNEL)) | ||
1083 | return -ENOMEM; | ||
1084 | |||
1085 | leds = devm_kzalloc(dev, sizeof(struct wacom_led) * count, GFP_KERNEL); | ||
1086 | if (!leds) { | ||
1087 | error = -ENOMEM; | ||
1088 | goto err; | ||
1089 | } | ||
1090 | |||
1091 | wacom->led.groups[group_id].leds = leds; | ||
1092 | wacom->led.groups[group_id].count = count; | ||
1093 | |||
1094 | for (i = 0; i < count; i++) { | ||
1095 | error = wacom_led_register_one(dev, wacom, &leds[i], | ||
1096 | group_id, i, read_only); | ||
1097 | if (error) | ||
1098 | goto err; | ||
1099 | } | ||
1100 | |||
1101 | devres_remove_group(dev, &wacom->led.groups[group_id]); | ||
1102 | return 0; | ||
1103 | |||
1104 | err: | ||
1105 | devres_release_group(dev, &wacom->led.groups[group_id]); | ||
1106 | return error; | ||
1107 | } | ||
1108 | |||
969 | static void wacom_led_groups_release(void *data) | 1109 | static void wacom_led_groups_release(void *data) |
970 | { | 1110 | { |
971 | struct wacom *wacom = data; | 1111 | struct wacom *wacom = data; |
972 | 1112 | ||
973 | wacom->led.groups = NULL; | 1113 | wacom->led.groups = NULL; |
1114 | wacom->led.count = 0; | ||
974 | } | 1115 | } |
975 | 1116 | ||
976 | static int wacom_led_groups_allocate(struct wacom *wacom, int count) | 1117 | static int wacom_led_groups_allocate(struct wacom *wacom, int count) |
977 | { | 1118 | { |
1119 | struct device *dev = &wacom->hdev->dev; | ||
978 | struct wacom_group_leds *groups; | 1120 | struct wacom_group_leds *groups; |
979 | int error; | 1121 | int error; |
980 | 1122 | ||
981 | groups = devm_kzalloc(&wacom->hdev->dev, | 1123 | groups = devm_kzalloc(dev, sizeof(struct wacom_group_leds) * count, |
982 | sizeof(struct wacom_group_leds) * count, | ||
983 | GFP_KERNEL); | 1124 | GFP_KERNEL); |
984 | if (!groups) | 1125 | if (!groups) |
985 | return -ENOMEM; | 1126 | return -ENOMEM; |
986 | 1127 | ||
987 | error = devm_add_action_or_reset(&wacom->hdev->dev, | 1128 | error = devm_add_action_or_reset(dev, wacom_led_groups_release, wacom); |
988 | wacom_led_groups_release, | ||
989 | wacom); | ||
990 | if (error) | 1129 | if (error) |
991 | return error; | 1130 | return error; |
992 | 1131 | ||
993 | wacom->led.groups = groups; | 1132 | wacom->led.groups = groups; |
1133 | wacom->led.count = count; | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static int wacom_leds_alloc_and_register(struct wacom *wacom, int group_count, | ||
1139 | int led_per_group, bool read_only) | ||
1140 | { | ||
1141 | struct device *dev; | ||
1142 | int i, error; | ||
1143 | |||
1144 | if (!wacom->wacom_wac.pad_input) | ||
1145 | return -EINVAL; | ||
1146 | |||
1147 | dev = &wacom->wacom_wac.pad_input->dev; | ||
1148 | |||
1149 | error = wacom_led_groups_allocate(wacom, group_count); | ||
1150 | if (error) | ||
1151 | return error; | ||
1152 | |||
1153 | for (i = 0; i < group_count; i++) { | ||
1154 | error = wacom_led_groups_alloc_and_register_one(dev, wacom, i, | ||
1155 | led_per_group, | ||
1156 | read_only); | ||
1157 | if (error) | ||
1158 | return error; | ||
1159 | } | ||
994 | 1160 | ||
995 | return 0; | 1161 | return 0; |
996 | } | 1162 | } |
@@ -1010,9 +1176,11 @@ static int wacom_initialize_leds(struct wacom *wacom) | |||
1010 | case INTUOS4L: | 1176 | case INTUOS4L: |
1011 | wacom->led.llv = 10; | 1177 | wacom->led.llv = 10; |
1012 | wacom->led.hlv = 20; | 1178 | wacom->led.hlv = 20; |
1179 | wacom->led.max_llv = 127; | ||
1180 | wacom->led.max_hlv = 127; | ||
1013 | wacom->led.img_lum = 10; | 1181 | wacom->led.img_lum = 10; |
1014 | 1182 | ||
1015 | error = wacom_led_groups_allocate(wacom, 1); | 1183 | error = wacom_leds_alloc_and_register(wacom, 1, 4, false); |
1016 | if (error) { | 1184 | if (error) { |
1017 | hid_err(wacom->hdev, | 1185 | hid_err(wacom->hdev, |
1018 | "cannot create leds err: %d\n", error); | 1186 | "cannot create leds err: %d\n", error); |
@@ -1029,7 +1197,7 @@ static int wacom_initialize_leds(struct wacom *wacom) | |||
1029 | wacom->led.hlv = 0; | 1197 | wacom->led.hlv = 0; |
1030 | wacom->led.img_lum = 0; | 1198 | wacom->led.img_lum = 0; |
1031 | 1199 | ||
1032 | error = wacom_led_groups_allocate(wacom, 2); | 1200 | error = wacom_leds_alloc_and_register(wacom, 2, 4, false); |
1033 | if (error) { | 1201 | if (error) { |
1034 | hid_err(wacom->hdev, | 1202 | hid_err(wacom->hdev, |
1035 | "cannot create leds err: %d\n", error); | 1203 | "cannot create leds err: %d\n", error); |
@@ -1047,10 +1215,9 @@ static int wacom_initialize_leds(struct wacom *wacom) | |||
1047 | case INTUOSPM: | 1215 | case INTUOSPM: |
1048 | case INTUOSPL: | 1216 | case INTUOSPL: |
1049 | wacom->led.llv = 32; | 1217 | wacom->led.llv = 32; |
1050 | wacom->led.hlv = 0; | 1218 | wacom->led.max_llv = 96; |
1051 | wacom->led.img_lum = 0; | ||
1052 | 1219 | ||
1053 | error = wacom_led_groups_allocate(wacom, 1); | 1220 | error = wacom_leds_alloc_and_register(wacom, 1, 4, false); |
1054 | if (error) { | 1221 | if (error) { |
1055 | hid_err(wacom->hdev, | 1222 | hid_err(wacom->hdev, |
1056 | "cannot create leds err: %d\n", error); | 1223 | "cannot create leds err: %d\n", error); |
@@ -1062,6 +1229,8 @@ static int wacom_initialize_leds(struct wacom *wacom) | |||
1062 | break; | 1229 | break; |
1063 | 1230 | ||
1064 | case REMOTE: | 1231 | case REMOTE: |
1232 | wacom->led.llv = 255; | ||
1233 | wacom->led.max_llv = 255; | ||
1065 | error = wacom_led_groups_allocate(wacom, 5); | 1234 | error = wacom_led_groups_allocate(wacom, 5); |
1066 | if (error) { | 1235 | if (error) { |
1067 | hid_err(wacom->hdev, | 1236 | hid_err(wacom->hdev, |
@@ -1987,6 +2156,12 @@ static int wacom_remote_create_one(struct wacom *wacom, u32 serial, | |||
1987 | if (error) | 2156 | if (error) |
1988 | goto fail; | 2157 | goto fail; |
1989 | 2158 | ||
2159 | error = wacom_led_groups_alloc_and_register_one( | ||
2160 | &remote->remotes[index].input->dev, | ||
2161 | wacom, index, 3, true); | ||
2162 | if (error) | ||
2163 | goto fail; | ||
2164 | |||
1990 | remote->remotes[index].registered = true; | 2165 | remote->remotes[index].registered = true; |
1991 | 2166 | ||
1992 | devres_close_group(dev, &remote->remotes[index]); | 2167 | devres_close_group(dev, &remote->remotes[index]); |