|
@@ -1202,15 +1202,24 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
|
|
|
|
|
|
static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|
|
{
|
|
|
- const int pen_frame_len = 14;
|
|
|
- const int pen_frames = 7;
|
|
|
+ int pen_frame_len, pen_frames;
|
|
|
|
|
|
struct input_dev *pen_input = wacom->pen_input;
|
|
|
unsigned char *data = wacom->data;
|
|
|
int i;
|
|
|
|
|
|
- wacom->serial[0] = get_unaligned_le64(&data[99]);
|
|
|
- wacom->id[0] = get_unaligned_le16(&data[107]);
|
|
|
+ if (wacom->features.type == INTUOSP2_BT) {
|
|
|
+ wacom->serial[0] = get_unaligned_le64(&data[99]);
|
|
|
+ wacom->id[0] = get_unaligned_le16(&data[107]);
|
|
|
+ pen_frame_len = 14;
|
|
|
+ pen_frames = 7;
|
|
|
+ } else {
|
|
|
+ wacom->serial[0] = get_unaligned_le64(&data[33]);
|
|
|
+ wacom->id[0] = get_unaligned_le16(&data[41]);
|
|
|
+ pen_frame_len = 8;
|
|
|
+ pen_frames = 4;
|
|
|
+ }
|
|
|
+
|
|
|
if (wacom->serial[0] >> 52 == 1) {
|
|
|
/* Add back in missing bits of ID for non-USI pens */
|
|
|
wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
|
|
@@ -1227,21 +1236,35 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|
|
continue;
|
|
|
|
|
|
if (range) {
|
|
|
- /* Fix rotation alignment: userspace expects zero at left */
|
|
|
- int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
|
|
|
- rotation += 1800/4;
|
|
|
- if (rotation > 899)
|
|
|
- rotation -= 1800;
|
|
|
-
|
|
|
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
|
|
|
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
|
|
|
- input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]);
|
|
|
- input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]);
|
|
|
- input_report_abs(pen_input, ABS_Z, rotation);
|
|
|
- input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
|
|
|
+
|
|
|
+ if (wacom->features.type == INTUOSP2_BT) {
|
|
|
+ /* Fix rotation alignment: userspace expects zero at left */
|
|
|
+ int16_t rotation =
|
|
|
+ (int16_t)get_unaligned_le16(&frame[9]);
|
|
|
+ rotation += 1800/4;
|
|
|
+
|
|
|
+ if (rotation > 899)
|
|
|
+ rotation -= 1800;
|
|
|
+
|
|
|
+ input_report_abs(pen_input, ABS_TILT_X,
|
|
|
+ (char)frame[7]);
|
|
|
+ input_report_abs(pen_input, ABS_TILT_Y,
|
|
|
+ (char)frame[8]);
|
|
|
+ input_report_abs(pen_input, ABS_Z, rotation);
|
|
|
+ input_report_abs(pen_input, ABS_WHEEL,
|
|
|
+ get_unaligned_le16(&frame[11]));
|
|
|
+ }
|
|
|
}
|
|
|
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
|
|
|
- input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max);
|
|
|
+ if (wacom->features.type == INTUOSP2_BT) {
|
|
|
+ input_report_abs(pen_input, ABS_DISTANCE,
|
|
|
+ range ? frame[13] : wacom->features.distance_max);
|
|
|
+ } else {
|
|
|
+ input_report_abs(pen_input, ABS_DISTANCE,
|
|
|
+ range ? frame[7] : wacom->features.distance_max);
|
|
|
+ }
|
|
|
|
|
|
input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01);
|
|
|
input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
|
|
@@ -1357,20 +1380,52 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
|
|
|
battery_status, chg, 1, chg);
|
|
|
}
|
|
|
|
|
|
+static void wacom_intuos_gen3_bt_pad(struct wacom_wac *wacom)
|
|
|
+{
|
|
|
+ struct input_dev *pad_input = wacom->pad_input;
|
|
|
+ unsigned char *data = wacom->data;
|
|
|
+
|
|
|
+ int buttons = data[44];
|
|
|
+
|
|
|
+ wacom_report_numbered_buttons(pad_input, 4, buttons);
|
|
|
+
|
|
|
+ input_report_key(pad_input, wacom->tool[1], buttons ? 1 : 0);
|
|
|
+ input_report_abs(pad_input, ABS_MISC, buttons ? PAD_DEVICE_ID : 0);
|
|
|
+ input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff);
|
|
|
+
|
|
|
+ input_sync(pad_input);
|
|
|
+}
|
|
|
+
|
|
|
+static void wacom_intuos_gen3_bt_battery(struct wacom_wac *wacom)
|
|
|
+{
|
|
|
+ unsigned char *data = wacom->data;
|
|
|
+
|
|
|
+ bool chg = data[45] & 0x80;
|
|
|
+ int battery_status = data[45] & 0x7F;
|
|
|
+
|
|
|
+ wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
|
|
|
+ battery_status, chg, 1, chg);
|
|
|
+}
|
|
|
+
|
|
|
static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
|
|
|
{
|
|
|
unsigned char *data = wacom->data;
|
|
|
|
|
|
- if (data[0] != 0x80) {
|
|
|
+ if (data[0] != 0x80 && data[0] != 0x81) {
|
|
|
dev_dbg(wacom->pen_input->dev.parent,
|
|
|
"%s: received unknown report #%d\n", __func__, data[0]);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
wacom_intuos_pro2_bt_pen(wacom);
|
|
|
- wacom_intuos_pro2_bt_touch(wacom);
|
|
|
- wacom_intuos_pro2_bt_pad(wacom);
|
|
|
- wacom_intuos_pro2_bt_battery(wacom);
|
|
|
+ if (wacom->features.type == INTUOSP2_BT) {
|
|
|
+ wacom_intuos_pro2_bt_touch(wacom);
|
|
|
+ wacom_intuos_pro2_bt_pad(wacom);
|
|
|
+ wacom_intuos_pro2_bt_battery(wacom);
|
|
|
+ } else {
|
|
|
+ wacom_intuos_gen3_bt_pad(wacom);
|
|
|
+ wacom_intuos_gen3_bt_battery(wacom);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1660,7 +1715,8 @@ int wacom_equivalent_usage(int usage)
|
|
|
usage == WACOM_HID_WD_TOUCHSTRIP ||
|
|
|
usage == WACOM_HID_WD_TOUCHSTRIP2 ||
|
|
|
usage == WACOM_HID_WD_TOUCHRING ||
|
|
|
- usage == WACOM_HID_WD_TOUCHRINGSTATUS) {
|
|
|
+ usage == WACOM_HID_WD_TOUCHRINGSTATUS ||
|
|
|
+ usage == WACOM_HID_WD_REPORT_VALID) {
|
|
|
return usage;
|
|
|
}
|
|
|
|
|
@@ -2017,7 +2073,7 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev,
|
|
|
}
|
|
|
|
|
|
static void wacom_wac_pad_report(struct hid_device *hdev,
|
|
|
- struct hid_report *report)
|
|
|
+ struct hid_report *report, struct hid_field *field)
|
|
|
{
|
|
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
@@ -2025,7 +2081,7 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
|
|
|
bool active = wacom_wac->hid_data.inrange_state != 0;
|
|
|
|
|
|
/* report prox for expresskey events */
|
|
|
- if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
|
|
|
+ if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
|
|
|
wacom_wac->hid_data.pad_input_event_flag) {
|
|
|
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
|
|
|
input_sync(input);
|
|
@@ -2144,6 +2200,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
|
|
|
struct input_dev *input = wacom_wac->pen_input;
|
|
|
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
|
|
|
|
|
+ if (wacom_wac->is_invalid_bt_frame)
|
|
|
+ return;
|
|
|
+
|
|
|
switch (equivalent_usage) {
|
|
|
case HID_GD_Z:
|
|
|
/*
|
|
@@ -2240,6 +2299,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
|
|
|
features->offset_bottom);
|
|
|
features->offset_bottom = value;
|
|
|
return;
|
|
|
+ case WACOM_HID_WD_REPORT_VALID:
|
|
|
+ wacom_wac->is_invalid_bt_frame = !value;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
/* send pen events only when touch is up or forced out
|
|
@@ -2258,6 +2320,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
|
|
|
static void wacom_wac_pen_pre_report(struct hid_device *hdev,
|
|
|
struct hid_report *report)
|
|
|
{
|
|
|
+ struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
|
+
|
|
|
+ wacom_wac->is_invalid_bt_frame = false;
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2270,6 +2336,9 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
|
|
bool range = wacom_wac->hid_data.inrange_state;
|
|
|
bool sense = wacom_wac->hid_data.sense_state;
|
|
|
|
|
|
+ if (wacom_wac->is_invalid_bt_frame)
|
|
|
+ return;
|
|
|
+
|
|
|
if (!wacom_wac->tool[0] && range) { /* first in range */
|
|
|
/* Going into range select tool */
|
|
|
if (wacom_wac->hid_data.invert_state)
|
|
@@ -2572,11 +2641,13 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
|
|
|
wacom_wac_finger_event(hdev, field, usage, value);
|
|
|
}
|
|
|
|
|
|
-static void wacom_report_events(struct hid_device *hdev, struct hid_report *report)
|
|
|
+static void wacom_report_events(struct hid_device *hdev,
|
|
|
+ struct hid_report *report, int collection_index,
|
|
|
+ int field_index)
|
|
|
{
|
|
|
int r;
|
|
|
|
|
|
- for (r = 0; r < report->maxfield; r++) {
|
|
|
+ for (r = field_index; r < report->maxfield; r++) {
|
|
|
struct hid_field *field;
|
|
|
unsigned count, n;
|
|
|
|
|
@@ -2586,30 +2657,23 @@ static void wacom_report_events(struct hid_device *hdev, struct hid_report *repo
|
|
|
if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
|
|
|
continue;
|
|
|
|
|
|
- for (n = 0; n < count; n++)
|
|
|
- wacom_wac_event(hdev, field, &field->usage[n], field->value[n]);
|
|
|
+ for (n = 0 ; n < count; n++) {
|
|
|
+ if (field->usage[n].collection_index == collection_index)
|
|
|
+ wacom_wac_event(hdev, field, &field->usage[n],
|
|
|
+ field->value[n]);
|
|
|
+ else
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|
|
+static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *report,
|
|
|
+ int collection_index, struct hid_field *field,
|
|
|
+ int field_index)
|
|
|
{
|
|
|
struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
- struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
|
- struct hid_field *field = report->field[0];
|
|
|
|
|
|
- if (wacom_wac->features.type != HID_GENERIC)
|
|
|
- return;
|
|
|
-
|
|
|
- wacom_wac_battery_pre_report(hdev, report);
|
|
|
-
|
|
|
- if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
|
|
|
- wacom_wac_pad_pre_report(hdev, report);
|
|
|
- else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
|
|
|
- wacom_wac_pen_pre_report(hdev, report);
|
|
|
- else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
|
|
|
- wacom_wac_finger_pre_report(hdev, report);
|
|
|
-
|
|
|
- wacom_report_events(hdev, report);
|
|
|
+ wacom_report_events(hdev, report, collection_index, field_index);
|
|
|
|
|
|
/*
|
|
|
* Non-input reports may be sent prior to the device being
|
|
@@ -2619,16 +2683,63 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|
|
* processing functions.
|
|
|
*/
|
|
|
if (report->type != HID_INPUT_REPORT)
|
|
|
- return;
|
|
|
-
|
|
|
- wacom_wac_battery_report(hdev, report);
|
|
|
+ return -1;
|
|
|
|
|
|
if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
|
|
|
- wacom_wac_pad_report(hdev, report);
|
|
|
+ wacom_wac_pad_report(hdev, report, field);
|
|
|
else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
|
|
|
wacom_wac_pen_report(hdev, report);
|
|
|
else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
|
|
|
wacom_wac_finger_report(hdev, report);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
|
|
|
+{
|
|
|
+ struct wacom *wacom = hid_get_drvdata(hdev);
|
|
|
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
|
|
|
+ struct hid_field *field;
|
|
|
+ bool pad_in_hid_field = false, pen_in_hid_field = false,
|
|
|
+ finger_in_hid_field = false;
|
|
|
+ int r;
|
|
|
+ int prev_collection = -1;
|
|
|
+
|
|
|
+ if (wacom_wac->features.type != HID_GENERIC)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (r = 0; r < report->maxfield; r++) {
|
|
|
+ field = report->field[r];
|
|
|
+
|
|
|
+ if (WACOM_PAD_FIELD(field))
|
|
|
+ pad_in_hid_field = true;
|
|
|
+ if (WACOM_PEN_FIELD(field))
|
|
|
+ pen_in_hid_field = true;
|
|
|
+ if (WACOM_FINGER_FIELD(field))
|
|
|
+ finger_in_hid_field = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ wacom_wac_battery_pre_report(hdev, report);
|
|
|
+
|
|
|
+ if (pad_in_hid_field && wacom->wacom_wac.pad_input)
|
|
|
+ wacom_wac_pad_pre_report(hdev, report);
|
|
|
+ if (pen_in_hid_field && wacom->wacom_wac.pen_input)
|
|
|
+ wacom_wac_pen_pre_report(hdev, report);
|
|
|
+ if (finger_in_hid_field && wacom->wacom_wac.touch_input)
|
|
|
+ wacom_wac_finger_pre_report(hdev, report);
|
|
|
+
|
|
|
+ for (r = 0; r < report->maxfield; r++) {
|
|
|
+ field = report->field[r];
|
|
|
+
|
|
|
+ if (field->usage[0].collection_index != prev_collection) {
|
|
|
+ if (wacom_wac_collection(hdev, report,
|
|
|
+ field->usage[0].collection_index, field, r) < 0)
|
|
|
+ return;
|
|
|
+ prev_collection = field->usage[0].collection_index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ wacom_wac_battery_report(hdev, report);
|
|
|
}
|
|
|
|
|
|
static int wacom_bpt_touch(struct wacom_wac *wacom)
|
|
@@ -3093,6 +3204,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
|
|
break;
|
|
|
|
|
|
case INTUOSP2_BT:
|
|
|
+ case INTUOSHT3_BT:
|
|
|
sync = wacom_intuos_pro2_bt_irq(wacom_wac, len);
|
|
|
break;
|
|
|
|
|
@@ -3272,6 +3384,12 @@ void wacom_setup_device_quirks(struct wacom *wacom)
|
|
|
features->quirks |= WACOM_QUIRK_BATTERY;
|
|
|
}
|
|
|
|
|
|
+ if (features->type == INTUOSHT3_BT) {
|
|
|
+ features->device_type |= WACOM_DEVICETYPE_PEN |
|
|
|
+ WACOM_DEVICETYPE_PAD;
|
|
|
+ features->quirks |= WACOM_QUIRK_BATTERY;
|
|
|
+ }
|
|
|
+
|
|
|
switch (features->type) {
|
|
|
case PL:
|
|
|
case DTU:
|
|
@@ -3466,7 +3584,9 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
|
|
|
case BAMBOO_PT:
|
|
|
case BAMBOO_PEN:
|
|
|
case INTUOSHT2:
|
|
|
- if (features->type == INTUOSHT2) {
|
|
|
+ case INTUOSHT3_BT:
|
|
|
+ if (features->type == INTUOSHT2 ||
|
|
|
+ features->type == INTUOSHT3_BT) {
|
|
|
wacom_setup_basic_pro_pen(wacom_wac);
|
|
|
} else {
|
|
|
__clear_bit(ABS_MISC, input_dev->absbit);
|
|
@@ -3887,6 +4007,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
|
|
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
|
|
|
break;
|
|
|
|
|
|
+ case INTUOSHT3_BT:
|
|
|
case HID_GENERIC:
|
|
|
break;
|
|
|
|
|
@@ -4415,6 +4536,12 @@ static const struct wacom_features wacom_features_0x360 =
|
|
|
static const struct wacom_features wacom_features_0x361 =
|
|
|
{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
|
|
|
INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
|
|
|
+static const struct wacom_features wacom_features_0x377 =
|
|
|
+ { "Wacom Intuos BT S", 15200, 9500, 4095, 63,
|
|
|
+ INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
|
|
|
+static const struct wacom_features wacom_features_0x379 =
|
|
|
+ { "Wacom Intuos BT M", 21600, 13500, 4095, 63,
|
|
|
+ INTUOSHT3_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
|
|
|
static const struct wacom_features wacom_features_0x37A =
|
|
|
{ "Wacom One by Wacom S", 15200, 9500, 2047, 63,
|
|
|
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
|
@@ -4589,6 +4716,8 @@ const struct hid_device_id wacom_ids[] = {
|
|
|
{ USB_DEVICE_WACOM(0x343) },
|
|
|
{ BT_DEVICE_WACOM(0x360) },
|
|
|
{ BT_DEVICE_WACOM(0x361) },
|
|
|
+ { BT_DEVICE_WACOM(0x377) },
|
|
|
+ { BT_DEVICE_WACOM(0x379) },
|
|
|
{ USB_DEVICE_WACOM(0x37A) },
|
|
|
{ USB_DEVICE_WACOM(0x37B) },
|
|
|
{ USB_DEVICE_WACOM(0x4001) },
|