aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2017-01-25 15:08:37 -0500
committerJiri Kosina <jkosina@suse.cz>2017-01-26 15:46:44 -0500
commit4922cd26f03c1c71bf7dd6cbdb638e7e36a4a50b (patch)
tree3a0bc15207ded7bc67070ff66114d97f20db4512
parent5ba13c6495010cd39e0ecb89ce1e546189bd6006 (diff)
HID: wacom: Support 2nd-gen Intuos Pro's Bluetooth classic interface
In addition to its USB interface, the second-generation Intuos Pro includes a Bluetooth radio that offers two pairing interfaces: classic and low-energy. The classic interface functions just like the earlier Bluetooth-enabled Intuos4 and Graphire4 tablets, appearing as a HID device that our driver can work with. The low-energy interface is intented to be used by userspace applications that make use of its paper-to-digital capabilities. Despite the USB interface using Wacom's new vendor-defined HID usages, the Bluetooth interface provides us with useless black-box "blob" report descriptors like past devices. We thus have to explicitly add support for the PIDs and reports used. These devices pack a /lot/ of information into a single Bluetooth input report. Each report contains up to seven snapshots of the pen state, four snapshots of the touch state (of five touches each), pad state, and battery data. Thankfully this isn't too hard for the driver to report -- it just takes a fair amount of code to extract! Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Ping Cheng <pingc@wacom.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/wacom_sys.c25
-rw-r--r--drivers/hid/wacom_wac.c197
-rw-r--r--drivers/hid/wacom_wac.h6
3 files changed, 226 insertions, 2 deletions
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 4dd7b80ffca4..4a70783e64e1 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -756,6 +756,10 @@ static int wacom_led_control(struct wacom *wacom)
756 report_id = WAC_CMD_WL_LED_CONTROL; 756 report_id = WAC_CMD_WL_LED_CONTROL;
757 buf_size = 13; 757 buf_size = 13;
758 } 758 }
759 else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
760 report_id = WAC_CMD_WL_INTUOSP2;
761 buf_size = 51;
762 }
759 buf = kzalloc(buf_size, GFP_KERNEL); 763 buf = kzalloc(buf_size, GFP_KERNEL);
760 if (!buf) 764 if (!buf)
761 return -ENOMEM; 765 return -ENOMEM;
@@ -781,6 +785,16 @@ static int wacom_led_control(struct wacom *wacom)
781 } else 785 } else
782 buf[1] = led_bits; 786 buf[1] = led_bits;
783 } 787 }
788 else if (wacom->wacom_wac.features.type == INTUOSP2_BT) {
789 buf[0] = report_id;
790 buf[4] = 100; // Power Connection LED (ORANGE)
791 buf[5] = 100; // BT Connection LED (BLUE)
792 buf[6] = 100; // Paper Mode (RED?)
793 buf[7] = 100; // Paper Mode (GREEN?)
794 buf[8] = 100; // Paper Mode (BLUE?)
795 buf[9] = wacom->led.llv;
796 buf[10] = wacom->led.groups[0].select & 0x03;
797 }
784 else { 798 else {
785 int led = wacom->led.groups[0].select | 0x4; 799 int led = wacom->led.groups[0].select | 0x4;
786 800
@@ -1409,6 +1423,17 @@ static int wacom_initialize_leds(struct wacom *wacom)
1409 &intuos5_led_attr_group); 1423 &intuos5_led_attr_group);
1410 break; 1424 break;
1411 1425
1426 case INTUOSP2_BT:
1427 wacom->led.llv = 50;
1428 wacom->led.max_llv = 100;
1429 error = wacom_leds_alloc_and_register(wacom, 1, 4, false);
1430 if (error) {
1431 hid_err(wacom->hdev,
1432 "cannot create leds err: %d\n", error);
1433 return error;
1434 }
1435 return 0;
1436
1412 case REMOTE: 1437 case REMOTE:
1413 wacom->led.llv = 255; 1438 wacom->led.llv = 255;
1414 wacom->led.max_llv = 255; 1439 wacom->led.max_llv = 255;
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index a23b736d05d2..ef29f7ad7664 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1190,6 +1190,161 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
1190 return count; 1190 return count;
1191} 1191}
1192 1192
1193static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
1194{
1195 const int pen_frame_len = 14;
1196 const int pen_frames = 7;
1197
1198 struct input_dev *pen_input = wacom->pen_input;
1199 unsigned char *data = wacom->data;
1200 int i;
1201
1202 wacom->serial[0] = get_unaligned_le64(&data[99]);
1203 wacom->id[0] = get_unaligned_le16(&data[107]);
1204 if (wacom->serial[0] >> 52 == 1) {
1205 /* Add back in missing bits of ID for non-USI pens */
1206 wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
1207 }
1208 wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
1209
1210 for (i = 0; i < pen_frames; i++) {
1211 unsigned char *frame = &data[i*pen_frame_len + 1];
1212
1213 if (!(frame[0] & 0x80))
1214 continue;
1215
1216 input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
1217 input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
1218 input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
1219 input_report_abs(pen_input, ABS_TILT_X, frame[7]);
1220 input_report_abs(pen_input, ABS_TILT_Y, frame[8]);
1221 input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9]));
1222 input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
1223 input_report_abs(pen_input, ABS_DISTANCE, frame[13]);
1224
1225 input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
1226 input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
1227 input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
1228
1229 input_report_key(pen_input, wacom->tool[0], 1);
1230 input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
1231 input_report_abs(pen_input, ABS_MISC,
1232 wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
1233
1234 wacom->shared->stylus_in_proximity = frame[0] & 0x40;
1235
1236 input_sync(pen_input);
1237 }
1238}
1239
1240static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
1241{
1242 const int finger_touch_len = 8;
1243 const int finger_frames = 4;
1244 const int finger_frame_len = 43;
1245
1246 struct input_dev *touch_input = wacom->touch_input;
1247 unsigned char *data = wacom->data;
1248 int num_contacts_left = 5;
1249 int i, j;
1250
1251 for (i = 0; i < finger_frames; i++) {
1252 unsigned char *frame = &data[i*finger_frame_len + 109];
1253 int current_num_contacts = frame[0] & 0x7F;
1254 int contacts_to_send;
1255
1256 if (!(frame[0] & 0x80))
1257 continue;
1258
1259 /*
1260 * First packet resets the counter since only the first
1261 * packet in series will have non-zero current_num_contacts.
1262 */
1263 if (current_num_contacts)
1264 wacom->num_contacts_left = current_num_contacts;
1265
1266 contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
1267
1268 for (j = 0; j < contacts_to_send; j++) {
1269 unsigned char *touch = &frame[j*finger_touch_len + 1];
1270 int slot = input_mt_get_slot_by_key(touch_input, touch[0]);
1271 int x = get_unaligned_le16(&touch[2]);
1272 int y = get_unaligned_le16(&touch[4]);
1273 int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X);
1274 int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y);
1275
1276 if (slot < 0)
1277 continue;
1278
1279 input_mt_slot(touch_input, slot);
1280 input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01);
1281 input_report_abs(touch_input, ABS_MT_POSITION_X, x);
1282 input_report_abs(touch_input, ABS_MT_POSITION_Y, y);
1283 input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h));
1284 input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h));
1285 input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h);
1286 }
1287
1288 input_mt_sync_frame(touch_input);
1289
1290 wacom->num_contacts_left -= contacts_to_send;
1291 if (wacom->num_contacts_left <= 0) {
1292 wacom->num_contacts_left = 0;
1293 wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
1294 }
1295 }
1296
1297 input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
1298 input_sync(touch_input);
1299}
1300
1301static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
1302{
1303 struct input_dev *pad_input = wacom->pad_input;
1304 unsigned char *data = wacom->data;
1305
1306 int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
1307 int ring = data[285];
1308 int prox = buttons | (ring & 0x80);
1309
1310 wacom_report_numbered_buttons(pad_input, 9, buttons);
1311
1312 input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
1313
1314 input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
1315 input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
1316 input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
1317
1318 input_sync(pad_input);
1319}
1320
1321static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
1322{
1323 unsigned char *data = wacom->data;
1324
1325 bool chg = data[284] & 0x80;
1326 int battery_status = data[284] & 0x7F;
1327
1328 wacom_notify_battery(wacom, battery_status, chg, 1, chg);
1329}
1330
1331static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
1332{
1333 unsigned char *data = wacom->data;
1334
1335 if (data[0] != 0x80) {
1336 dev_dbg(wacom->pen_input->dev.parent,
1337 "%s: received unknown report #%d\n", __func__, data[0]);
1338 return 0;
1339 }
1340
1341 wacom_intuos_pro2_bt_pen(wacom);
1342 wacom_intuos_pro2_bt_touch(wacom);
1343 wacom_intuos_pro2_bt_pad(wacom);
1344 wacom_intuos_pro2_bt_battery(wacom);
1345 return 0;
1346}
1347
1193static int wacom_24hdt_irq(struct wacom_wac *wacom) 1348static int wacom_24hdt_irq(struct wacom_wac *wacom)
1194{ 1349{
1195 struct input_dev *input = wacom->touch_input; 1350 struct input_dev *input = wacom->touch_input;
@@ -2667,6 +2822,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
2667 sync = wacom_intuos_irq(wacom_wac); 2822 sync = wacom_intuos_irq(wacom_wac);
2668 break; 2823 break;
2669 2824
2825 case INTUOSP2_BT:
2826 sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
2827 break;
2828
2670 case TABLETPC: 2829 case TABLETPC:
2671 case TABLETPCE: 2830 case TABLETPCE:
2672 case TABLETPC2FG: 2831 case TABLETPC2FG:
@@ -2838,6 +2997,13 @@ void wacom_setup_device_quirks(struct wacom *wacom)
2838 if (features->type == REMOTE) 2997 if (features->type == REMOTE)
2839 features->device_type = WACOM_DEVICETYPE_PAD; 2998 features->device_type = WACOM_DEVICETYPE_PAD;
2840 2999
3000 if (features->type == INTUOSP2_BT) {
3001 features->device_type |= WACOM_DEVICETYPE_PEN |
3002 WACOM_DEVICETYPE_PAD |
3003 WACOM_DEVICETYPE_TOUCH;
3004 features->quirks |= WACOM_QUIRK_BATTERY;
3005 }
3006
2841 switch (features->type) { 3007 switch (features->type) {
2842 case PL: 3008 case PL:
2843 case DTU: 3009 case DTU:
@@ -2984,6 +3150,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
2984 case INTUOSPL: 3150 case INTUOSPL:
2985 case INTUOS5S: 3151 case INTUOS5S:
2986 case INTUOSPS: 3152 case INTUOSPS:
3153 case INTUOSP2_BT:
2987 input_set_abs_params(input_dev, ABS_DISTANCE, 0, 3154 input_set_abs_params(input_dev, ABS_DISTANCE, 0,
2988 features->distance_max, 3155 features->distance_max,
2989 features->distance_fuzz, 0); 3156 features->distance_fuzz, 0);
@@ -3092,6 +3259,27 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
3092 } 3259 }
3093 3260
3094 switch (features->type) { 3261 switch (features->type) {
3262 case INTUOSP2_BT:
3263 input_dev->evbit[0] |= BIT_MASK(EV_SW);
3264 __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
3265
3266 if (wacom_wac->shared->touch->product == 0x361) {
3267 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3268 0, 12440, 4, 0);
3269 input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3270 0, 8640, 4, 0);
3271 }
3272 else if (wacom_wac->shared->touch->product == 0x360) {
3273 input_set_abs_params(input_dev, ABS_MT_POSITION_X,
3274 0, 8960, 4, 0);
3275 input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
3276 0, 5920, 4, 0);
3277 }
3278 input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
3279 input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
3280
3281 /* fall through */
3282
3095 case INTUOS5: 3283 case INTUOS5:
3096 case INTUOS5L: 3284 case INTUOS5L:
3097 case INTUOSPM: 3285 case INTUOSPM:
@@ -3389,6 +3577,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
3389 case INTUOSPL: 3577 case INTUOSPL:
3390 case INTUOS5S: 3578 case INTUOS5S:
3391 case INTUOSPS: 3579 case INTUOSPS:
3580 case INTUOSP2_BT:
3392 input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); 3581 input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
3393 break; 3582 break;
3394 3583
@@ -3947,6 +4136,12 @@ static const struct wacom_features wacom_features_0x343 =
3947 DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, 4136 DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
3948 WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, 4137 WACOM_DTU_OFFSET, WACOM_DTU_OFFSET,
3949 WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; 4138 WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
4139static const struct wacom_features wacom_features_0x360 =
4140 { "Wacom Intuos Pro M", 44800, 29600, 8191, 63,
4141 INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
4142static const struct wacom_features wacom_features_0x361 =
4143 { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
4144 INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 };
3950 4145
3951static const struct wacom_features wacom_features_HID_ANY_ID = 4146static const struct wacom_features wacom_features_HID_ANY_ID =
3952 { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; 4147 { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
@@ -4113,6 +4308,8 @@ const struct hid_device_id wacom_ids[] = {
4113 { USB_DEVICE_WACOM(0x33D) }, 4308 { USB_DEVICE_WACOM(0x33D) },
4114 { USB_DEVICE_WACOM(0x33E) }, 4309 { USB_DEVICE_WACOM(0x33E) },
4115 { USB_DEVICE_WACOM(0x343) }, 4310 { USB_DEVICE_WACOM(0x343) },
4311 { BT_DEVICE_WACOM(0x360) },
4312 { BT_DEVICE_WACOM(0x361) },
4116 { USB_DEVICE_WACOM(0x4001) }, 4313 { USB_DEVICE_WACOM(0x4001) },
4117 { USB_DEVICE_WACOM(0x4004) }, 4314 { USB_DEVICE_WACOM(0x4004) },
4118 { USB_DEVICE_WACOM(0x5000) }, 4315 { USB_DEVICE_WACOM(0x5000) },
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 804fda3e192a..d3482debae8a 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -12,8 +12,8 @@
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/hid.h> 13#include <linux/hid.h>
14 14
15/* maximum packet length for USB devices */ 15/* maximum packet length for USB/BT devices */
16#define WACOM_PKGLEN_MAX 192 16#define WACOM_PKGLEN_MAX 361
17 17
18#define WACOM_NAME_MAX 64 18#define WACOM_NAME_MAX 64
19#define WACOM_MAX_REMOTES 5 19#define WACOM_MAX_REMOTES 5
@@ -80,6 +80,7 @@
80#define WAC_CMD_ICON_BT_XFER 0x26 80#define WAC_CMD_ICON_BT_XFER 0x26
81#define WAC_CMD_DELETE_PAIRING 0x20 81#define WAC_CMD_DELETE_PAIRING 0x20
82#define WAC_CMD_UNPAIR_ALL 0xFF 82#define WAC_CMD_UNPAIR_ALL 0xFF
83#define WAC_CMD_WL_INTUOSP2 0x82
83 84
84/* device quirks */ 85/* device quirks */
85#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 86#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
@@ -179,6 +180,7 @@ enum {
179 INTUOSPS, 180 INTUOSPS,
180 INTUOSPM, 181 INTUOSPM,
181 INTUOSPL, 182 INTUOSPL,
183 INTUOSP2_BT,
182 WACOM_21UX2, 184 WACOM_21UX2,
183 WACOM_22HD, 185 WACOM_22HD,
184 DTK, 186 DTK,