diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2014-09-23 12:08:08 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-10-01 03:11:23 -0400 |
commit | 7704ac937345d4b502062952657027234aa86a37 (patch) | |
tree | f74ae80b7e96d23da461256dde4ec1a57a7968af | |
parent | 494078b0bb578c4cf1e00275dd3224d793013488 (diff) |
HID: wacom: implement generic HID handling for pen generic devices
ISDv4 and v5 are plain HID devices. We can directly implement a generic
HID parsing/handling and remove the need to manually add those PID in
the list of supported devices.
This patch implements the pen support only. The finger part will come in
a later patch.
To be properly notified of an .event() and a .report(), we need to force
hid-core to go through the HID parsing. By default, wacom.ko binds only
hidraw, so the hid parsing is not done by hid-core. When a true HID device
is there, we add the flag HID_CLAIMED_DRIVER to hid->claimed which will
force hid-core to parse the incoming reports.
(Note that this can be easily backported by directly setting the .claimed
flag to HID_CLAIMED_DRIVER even if hid-core does not support
HID_CONNECT_DRIVER)
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-core.c | 3 | ||||
-rw-r--r-- | drivers/hid/wacom.h | 6 | ||||
-rw-r--r-- | drivers/hid/wacom_sys.c | 12 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 179 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.h | 8 | ||||
-rw-r--r-- | include/linux/hid.h | 2 |
6 files changed, 208 insertions, 2 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 12b6e67d9de0..583344dba3c6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1591,6 +1591,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) | |||
1591 | if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) | 1591 | if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) |
1592 | hdev->claimed |= HID_CLAIMED_HIDRAW; | 1592 | hdev->claimed |= HID_CLAIMED_HIDRAW; |
1593 | 1593 | ||
1594 | if (connect_mask & HID_CONNECT_DRIVER) | ||
1595 | hdev->claimed |= HID_CLAIMED_DRIVER; | ||
1596 | |||
1594 | /* Drivers with the ->raw_event callback set are not required to connect | 1597 | /* Drivers with the ->raw_event callback set are not required to connect |
1595 | * to any other listener. */ | 1598 | * to any other listener. */ |
1596 | if (!hdev->claimed && !hdev->driver->raw_event) { | 1599 | if (!hdev->claimed && !hdev->driver->raw_event) { |
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 64bc1b296d91..0cc53440543a 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h | |||
@@ -89,6 +89,7 @@ | |||
89 | #include <linux/slab.h> | 89 | #include <linux/slab.h> |
90 | #include <linux/module.h> | 90 | #include <linux/module.h> |
91 | #include <linux/mod_devicetable.h> | 91 | #include <linux/mod_devicetable.h> |
92 | #include <linux/hid.h> | ||
92 | #include <linux/usb/input.h> | 93 | #include <linux/usb/input.h> |
93 | #include <linux/power_supply.h> | 94 | #include <linux/power_supply.h> |
94 | #include <asm/unaligned.h> | 95 | #include <asm/unaligned.h> |
@@ -143,4 +144,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
143 | struct wacom_wac *wacom_wac); | 144 | struct wacom_wac *wacom_wac); |
144 | int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, | 145 | int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, |
145 | struct wacom_wac *wacom_wac); | 146 | struct wacom_wac *wacom_wac); |
147 | void wacom_wac_usage_mapping(struct hid_device *hdev, | ||
148 | struct hid_field *field, struct hid_usage *usage); | ||
149 | int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, | ||
150 | struct hid_usage *usage, __s32 value); | ||
151 | void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); | ||
146 | #endif | 152 | #endif |
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 21ac2baa21be..dd288b2fbfe8 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c | |||
@@ -13,7 +13,6 @@ | |||
13 | 13 | ||
14 | #include "wacom_wac.h" | 14 | #include "wacom_wac.h" |
15 | #include "wacom.h" | 15 | #include "wacom.h" |
16 | #include <linux/hid.h> | ||
17 | 16 | ||
18 | #define WAC_MSG_RETRIES 5 | 17 | #define WAC_MSG_RETRIES 5 |
19 | 18 | ||
@@ -215,6 +214,9 @@ static void wacom_usage_mapping(struct hid_device *hdev, | |||
215 | features->pressure_max = field->logical_maximum; | 214 | features->pressure_max = field->logical_maximum; |
216 | break; | 215 | break; |
217 | } | 216 | } |
217 | |||
218 | if (features->type == HID_GENERIC) | ||
219 | wacom_wac_usage_mapping(hdev, field, usage); | ||
218 | } | 220 | } |
219 | 221 | ||
220 | static void wacom_parse_hid(struct hid_device *hdev, | 222 | static void wacom_parse_hid(struct hid_device *hdev, |
@@ -1318,6 +1320,7 @@ static int wacom_probe(struct hid_device *hdev, | |||
1318 | struct wacom_wac *wacom_wac; | 1320 | struct wacom_wac *wacom_wac; |
1319 | struct wacom_features *features; | 1321 | struct wacom_features *features; |
1320 | int error; | 1322 | int error; |
1323 | unsigned int connect_mask = HID_CONNECT_HIDRAW; | ||
1321 | 1324 | ||
1322 | if (!id->driver_data) | 1325 | if (!id->driver_data) |
1323 | return -EINVAL; | 1326 | return -EINVAL; |
@@ -1451,8 +1454,11 @@ static int wacom_probe(struct hid_device *hdev, | |||
1451 | /* Note that if query fails it is not a hard failure */ | 1454 | /* Note that if query fails it is not a hard failure */ |
1452 | wacom_query_tablet_data(hdev, features); | 1455 | wacom_query_tablet_data(hdev, features); |
1453 | 1456 | ||
1457 | if (features->type == HID_GENERIC) | ||
1458 | connect_mask |= HID_CONNECT_DRIVER; | ||
1459 | |||
1454 | /* Regular HID work starts now */ | 1460 | /* Regular HID work starts now */ |
1455 | error = hid_hw_start(hdev, HID_CONNECT_HIDRAW); | 1461 | error = hid_hw_start(hdev, connect_mask); |
1456 | if (error) { | 1462 | if (error) { |
1457 | hid_err(hdev, "hw start failed\n"); | 1463 | hid_err(hdev, "hw start failed\n"); |
1458 | goto fail_hw_start; | 1464 | goto fail_hw_start; |
@@ -1532,6 +1538,8 @@ static struct hid_driver wacom_driver = { | |||
1532 | .id_table = wacom_ids, | 1538 | .id_table = wacom_ids, |
1533 | .probe = wacom_probe, | 1539 | .probe = wacom_probe, |
1534 | .remove = wacom_remove, | 1540 | .remove = wacom_remove, |
1541 | .event = wacom_wac_event, | ||
1542 | .report = wacom_wac_report, | ||
1535 | #ifdef CONFIG_PM | 1543 | #ifdef CONFIG_PM |
1536 | .resume = wacom_resume, | 1544 | .resume = wacom_resume, |
1537 | .reset_resume = wacom_reset_resume, | 1545 | .reset_resume = wacom_reset_resume, |
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index b8180e40534d..e77d46d85a11 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c | |||
@@ -1248,6 +1248,176 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) | |||
1248 | return 0; | 1248 | return 0; |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | static void wacom_map_usage(struct wacom *wacom, struct hid_usage *usage, | ||
1252 | struct hid_field *field, __u8 type, __u16 code, int fuzz) | ||
1253 | { | ||
1254 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
1255 | struct input_dev *input = wacom_wac->input; | ||
1256 | int fmin = field->logical_minimum; | ||
1257 | int fmax = field->logical_maximum; | ||
1258 | |||
1259 | usage->type = type; | ||
1260 | usage->code = code; | ||
1261 | |||
1262 | set_bit(type, input->evbit); | ||
1263 | |||
1264 | switch (type) { | ||
1265 | case EV_ABS: | ||
1266 | input_set_abs_params(input, code, fmin, fmax, fuzz, 0); | ||
1267 | input_abs_set_res(input, code, | ||
1268 | hidinput_calc_abs_res(field, code)); | ||
1269 | break; | ||
1270 | case EV_KEY: | ||
1271 | input_set_capability(input, EV_KEY, code); | ||
1272 | break; | ||
1273 | case EV_MSC: | ||
1274 | input_set_capability(input, EV_MSC, code); | ||
1275 | break; | ||
1276 | } | ||
1277 | } | ||
1278 | |||
1279 | static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, | ||
1280 | struct hid_field *field, struct hid_usage *usage) | ||
1281 | { | ||
1282 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1283 | |||
1284 | switch (usage->hid) { | ||
1285 | case HID_GD_X: | ||
1286 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); | ||
1287 | break; | ||
1288 | case HID_GD_Y: | ||
1289 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); | ||
1290 | break; | ||
1291 | case HID_DG_TIPPRESSURE: | ||
1292 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_PRESSURE, 0); | ||
1293 | break; | ||
1294 | case HID_DG_INRANGE: | ||
1295 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOOL_PEN, 0); | ||
1296 | break; | ||
1297 | case HID_DG_INVERT: | ||
1298 | wacom_map_usage(wacom, usage, field, EV_KEY, | ||
1299 | BTN_TOOL_RUBBER, 0); | ||
1300 | break; | ||
1301 | case HID_DG_ERASER: | ||
1302 | case HID_DG_TIPSWITCH: | ||
1303 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); | ||
1304 | break; | ||
1305 | case HID_DG_BARRELSWITCH: | ||
1306 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS, 0); | ||
1307 | break; | ||
1308 | case HID_DG_BARRELSWITCH2: | ||
1309 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS2, 0); | ||
1310 | break; | ||
1311 | case HID_DG_TOOLSERIALNUMBER: | ||
1312 | wacom_map_usage(wacom, usage, field, EV_MSC, MSC_SERIAL, 0); | ||
1313 | break; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, | ||
1318 | struct hid_usage *usage, __s32 value) | ||
1319 | { | ||
1320 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1321 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
1322 | struct input_dev *input = wacom_wac->input; | ||
1323 | |||
1324 | /* checking which Tool / tip switch to send */ | ||
1325 | switch (usage->hid) { | ||
1326 | case HID_DG_INRANGE: | ||
1327 | wacom_wac->hid_data.inrange_state = value; | ||
1328 | return 0; | ||
1329 | case HID_DG_INVERT: | ||
1330 | wacom_wac->hid_data.invert_state = value; | ||
1331 | return 0; | ||
1332 | case HID_DG_ERASER: | ||
1333 | case HID_DG_TIPSWITCH: | ||
1334 | wacom_wac->hid_data.tipswitch |= value; | ||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | /* send pen events only when touch is up or forced out */ | ||
1339 | if (!usage->type || wacom_wac->shared->touch_down) | ||
1340 | return 0; | ||
1341 | |||
1342 | input_event(input, usage->type, usage->code, value); | ||
1343 | |||
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | static void wacom_wac_pen_report(struct hid_device *hdev, | ||
1348 | struct hid_report *report) | ||
1349 | { | ||
1350 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1351 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
1352 | struct input_dev *input = wacom_wac->input; | ||
1353 | bool prox = wacom_wac->hid_data.inrange_state; | ||
1354 | |||
1355 | if (!wacom_wac->shared->stylus_in_proximity) /* first in prox */ | ||
1356 | /* Going into proximity select tool */ | ||
1357 | wacom_wac->tool[0] = wacom_wac->hid_data.invert_state ? | ||
1358 | BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
1359 | |||
1360 | /* keep pen state for touch events */ | ||
1361 | wacom_wac->shared->stylus_in_proximity = prox; | ||
1362 | |||
1363 | /* send pen events only when touch is up or forced out */ | ||
1364 | if (!wacom_wac->shared->touch_down) { | ||
1365 | input_report_key(input, BTN_TOUCH, | ||
1366 | wacom_wac->hid_data.tipswitch); | ||
1367 | input_report_key(input, wacom_wac->tool[0], prox); | ||
1368 | |||
1369 | wacom_wac->hid_data.tipswitch = false; | ||
1370 | |||
1371 | input_sync(input); | ||
1372 | } | ||
1373 | } | ||
1374 | |||
1375 | #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ | ||
1376 | ((f)->physical == HID_DG_STYLUS)) | ||
1377 | #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ | ||
1378 | ((f)->physical == HID_DG_FINGER)) | ||
1379 | |||
1380 | void wacom_wac_usage_mapping(struct hid_device *hdev, | ||
1381 | struct hid_field *field, struct hid_usage *usage) | ||
1382 | { | ||
1383 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1384 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
1385 | struct input_dev *input = wacom_wac->input; | ||
1386 | |||
1387 | /* currently, only direct devices have proper hid report descriptors */ | ||
1388 | __set_bit(INPUT_PROP_DIRECT, input->propbit); | ||
1389 | |||
1390 | if (WACOM_PEN_FIELD(field)) | ||
1391 | return wacom_wac_pen_usage_mapping(hdev, field, usage); | ||
1392 | } | ||
1393 | |||
1394 | int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, | ||
1395 | struct hid_usage *usage, __s32 value) | ||
1396 | { | ||
1397 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1398 | |||
1399 | if (wacom->wacom_wac.features.type != HID_GENERIC) | ||
1400 | return 0; | ||
1401 | |||
1402 | if (WACOM_PEN_FIELD(field)) | ||
1403 | return wacom_wac_pen_event(hdev, field, usage, value); | ||
1404 | |||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) | ||
1409 | { | ||
1410 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
1411 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
1412 | struct hid_field *field = report->field[0]; | ||
1413 | |||
1414 | if (wacom_wac->features.type != HID_GENERIC) | ||
1415 | return; | ||
1416 | |||
1417 | if (WACOM_PEN_FIELD(field)) | ||
1418 | return wacom_wac_pen_report(hdev, report); | ||
1419 | } | ||
1420 | |||
1251 | static int wacom_bpt_touch(struct wacom_wac *wacom) | 1421 | static int wacom_bpt_touch(struct wacom_wac *wacom) |
1252 | { | 1422 | { |
1253 | struct wacom_features *features = &wacom->features; | 1423 | struct wacom_features *features = &wacom->features; |
@@ -1746,6 +1916,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, | |||
1746 | 1916 | ||
1747 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 1917 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
1748 | 1918 | ||
1919 | if (features->type == HID_GENERIC) | ||
1920 | /* setup has already been done */ | ||
1921 | return 0; | ||
1922 | |||
1749 | __set_bit(BTN_TOUCH, input_dev->keybit); | 1923 | __set_bit(BTN_TOUCH, input_dev->keybit); |
1750 | __set_bit(ABS_MISC, input_dev->absbit); | 1924 | __set_bit(ABS_MISC, input_dev->absbit); |
1751 | 1925 | ||
@@ -2585,6 +2759,9 @@ static const struct wacom_features wacom_features_0x30C = | |||
2585 | .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10, | 2759 | .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30A, .touch_max = 10, |
2586 | .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; | 2760 | .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; |
2587 | 2761 | ||
2762 | static const struct wacom_features wacom_features_HID_ANY_ID = | ||
2763 | { "Wacom HID", .type = HID_GENERIC }; | ||
2764 | |||
2588 | #define USB_DEVICE_WACOM(prod) \ | 2765 | #define USB_DEVICE_WACOM(prod) \ |
2589 | HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\ | 2766 | HID_DEVICE(BUS_USB, HID_GROUP_WACOM, USB_VENDOR_ID_WACOM, prod),\ |
2590 | .driver_data = (kernel_ulong_t)&wacom_features_##prod | 2767 | .driver_data = (kernel_ulong_t)&wacom_features_##prod |
@@ -2729,6 +2906,8 @@ const struct hid_device_id wacom_ids[] = { | |||
2729 | { USB_DEVICE_WACOM(0x4004) }, | 2906 | { USB_DEVICE_WACOM(0x4004) }, |
2730 | { USB_DEVICE_WACOM(0x5000) }, | 2907 | { USB_DEVICE_WACOM(0x5000) }, |
2731 | { USB_DEVICE_WACOM(0x5002) }, | 2908 | { USB_DEVICE_WACOM(0x5002) }, |
2909 | |||
2910 | { USB_DEVICE_WACOM(HID_ANY_ID) }, | ||
2732 | { } | 2911 | { } |
2733 | }; | 2912 | }; |
2734 | MODULE_DEVICE_TABLE(hid, wacom_ids); | 2913 | MODULE_DEVICE_TABLE(hid, wacom_ids); |
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 72f9ca8e5cd4..f472eac292d5 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h | |||
@@ -113,6 +113,7 @@ enum { | |||
113 | MTSCREEN, | 113 | MTSCREEN, |
114 | MTTPC, | 114 | MTTPC, |
115 | MTTPC_B, | 115 | MTTPC_B, |
116 | HID_GENERIC, | ||
116 | MAX_TYPE | 117 | MAX_TYPE |
117 | }; | 118 | }; |
118 | 119 | ||
@@ -154,6 +155,12 @@ struct wacom_shared { | |||
154 | struct input_dev *touch_input; | 155 | struct input_dev *touch_input; |
155 | }; | 156 | }; |
156 | 157 | ||
158 | struct hid_data { | ||
159 | bool inrange_state; | ||
160 | bool invert_state; | ||
161 | bool tipswitch; | ||
162 | }; | ||
163 | |||
157 | struct wacom_wac { | 164 | struct wacom_wac { |
158 | char name[WACOM_NAME_MAX]; | 165 | char name[WACOM_NAME_MAX]; |
159 | char pad_name[WACOM_NAME_MAX]; | 166 | char pad_name[WACOM_NAME_MAX]; |
@@ -175,6 +182,7 @@ struct wacom_wac { | |||
175 | int ps_connected; | 182 | int ps_connected; |
176 | u8 bt_features; | 183 | u8 bt_features; |
177 | u8 bt_high_speed; | 184 | u8 bt_high_speed; |
185 | struct hid_data hid_data; | ||
178 | }; | 186 | }; |
179 | 187 | ||
180 | #endif | 188 | #endif |
diff --git a/include/linux/hid.h b/include/linux/hid.h index f53c4a9cca1d..3dcd00496064 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -265,6 +265,7 @@ struct hid_item { | |||
265 | #define HID_CONNECT_HIDDEV 0x08 | 265 | #define HID_CONNECT_HIDDEV 0x08 |
266 | #define HID_CONNECT_HIDDEV_FORCE 0x10 | 266 | #define HID_CONNECT_HIDDEV_FORCE 0x10 |
267 | #define HID_CONNECT_FF 0x20 | 267 | #define HID_CONNECT_FF 0x20 |
268 | #define HID_CONNECT_DRIVER 0x40 | ||
268 | #define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \ | 269 | #define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \ |
269 | HID_CONNECT_HIDDEV|HID_CONNECT_FF) | 270 | HID_CONNECT_HIDDEV|HID_CONNECT_FF) |
270 | 271 | ||
@@ -440,6 +441,7 @@ struct hid_output_fifo { | |||
440 | #define HID_CLAIMED_INPUT 1 | 441 | #define HID_CLAIMED_INPUT 1 |
441 | #define HID_CLAIMED_HIDDEV 2 | 442 | #define HID_CLAIMED_HIDDEV 2 |
442 | #define HID_CLAIMED_HIDRAW 4 | 443 | #define HID_CLAIMED_HIDRAW 4 |
444 | #define HID_CLAIMED_DRIVER 8 | ||
443 | 445 | ||
444 | #define HID_STAT_ADDED 1 | 446 | #define HID_STAT_ADDED 1 |
445 | #define HID_STAT_PARSED 2 | 447 | #define HID_STAT_PARSED 2 |