Commit 740c84ee authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-4.16/wacom' into for-linus

Pull Wacom device driver updates. These don't have to go on top of the
hid_have_special_driver[] revamp, as the whole group is assumed to
have a special driver based on VID.
parents a44f3ec6 c9472189
...@@ -56,6 +56,107 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf, ...@@ -56,6 +56,107 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
return retval; return retval;
} }
static void wacom_wac_queue_insert(struct hid_device *hdev,
struct kfifo_rec_ptr_2 *fifo,
u8 *raw_data, int size)
{
bool warned = false;
while (kfifo_avail(fifo) < size) {
if (!warned)
hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__);
warned = true;
kfifo_skip(fifo);
}
kfifo_in(fifo, raw_data, size);
}
static void wacom_wac_queue_flush(struct hid_device *hdev,
struct kfifo_rec_ptr_2 *fifo)
{
while (!kfifo_is_empty(fifo)) {
u8 buf[WACOM_PKGLEN_MAX];
int size;
int err;
size = kfifo_out(fifo, buf, sizeof(buf));
err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false);
if (err) {
hid_warn(hdev, "%s: unable to flush event due to error %d\n",
__func__, err);
}
}
}
static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
struct hid_report *report, u8 *raw_data, int size)
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom_wac->features;
bool flush = false;
bool insert = false;
int i, j;
if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL))
return 0;
/* Queue events which have invalid tool type or serial number */
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->maxusage; j++) {
struct hid_field *field = report->field[i];
struct hid_usage *usage = &field->usage[j];
unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
unsigned int offset;
unsigned int size;
unsigned int value;
if (equivalent_usage != HID_DG_INRANGE &&
equivalent_usage != HID_DG_TOOLSERIALNUMBER &&
equivalent_usage != WACOM_HID_WD_SERIALHI &&
equivalent_usage != WACOM_HID_WD_TOOLTYPE)
continue;
offset = field->report_offset;
size = field->report_size;
value = hid_field_extract(hdev, raw_data+1, offset + j * size, size);
/* If we go out of range, we need to flush the queue ASAP */
if (equivalent_usage == HID_DG_INRANGE)
value = !value;
if (value) {
flush = true;
switch (equivalent_usage) {
case HID_DG_TOOLSERIALNUMBER:
wacom_wac->serial[0] = value;
break;
case WACOM_HID_WD_SERIALHI:
wacom_wac->serial[0] |= ((__u64)value) << 32;
break;
case WACOM_HID_WD_TOOLTYPE:
wacom_wac->id[0] = value;
break;
}
}
else {
insert = true;
}
}
}
if (flush)
wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
else if (insert)
wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo, raw_data, size);
return insert && !flush;
}
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size) u8 *raw_data, int size)
{ {
...@@ -64,6 +165,9 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -64,6 +165,9 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
if (size > WACOM_PKGLEN_MAX) if (size > WACOM_PKGLEN_MAX)
return 1; return 1;
if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size))
return -1;
memcpy(wacom->wacom_wac.data, raw_data, size); memcpy(wacom->wacom_wac.data, raw_data, size);
wacom_wac_irq(&wacom->wacom_wac, size); wacom_wac_irq(&wacom->wacom_wac, size);
...@@ -2347,23 +2451,23 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index) ...@@ -2347,23 +2451,23 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
int i; int i;
unsigned long flags; unsigned long flags;
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
spin_lock_irqsave(&remote->remote_lock, flags); spin_lock_irqsave(&remote->remote_lock, flags);
remote->remotes[index].registered = false; remote->remotes[i].registered = false;
spin_unlock_irqrestore(&remote->remote_lock, flags); spin_unlock_irqrestore(&remote->remote_lock, flags);
if (remote->remotes[index].battery.battery) if (remote->remotes[i].battery.battery)
devres_release_group(&wacom->hdev->dev, devres_release_group(&wacom->hdev->dev,
&remote->remotes[index].battery.bat_desc); &remote->remotes[i].battery.bat_desc);
if (remote->remotes[index].group.name) if (remote->remotes[i].group.name)
devres_release_group(&wacom->hdev->dev, devres_release_group(&wacom->hdev->dev,
&remote->remotes[index]); &remote->remotes[i]);
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
if (remote->remotes[i].serial == serial) {
remote->remotes[i].serial = 0; remote->remotes[i].serial = 0;
remote->remotes[i].group.name = NULL; remote->remotes[i].group.name = NULL;
remote->remotes[i].registered = false;
remote->remotes[i].battery.battery = NULL; remote->remotes[i].battery.battery = NULL;
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN; wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
} }
...@@ -2580,6 +2684,10 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -2580,6 +2684,10 @@ static int wacom_probe(struct hid_device *hdev,
goto fail; goto fail;
} }
error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
if (error)
goto fail;
wacom_wac->hid_data.inputmode = -1; wacom_wac->hid_data.inputmode = -1;
wacom_wac->mode_report = -1; wacom_wac->mode_report = -1;
...@@ -2643,6 +2751,8 @@ static void wacom_remove(struct hid_device *hdev) ...@@ -2643,6 +2751,8 @@ static void wacom_remove(struct hid_device *hdev)
if (wacom->wacom_wac.features.type != REMOTE) if (wacom->wacom_wac.features.type != REMOTE)
wacom_release_resources(wacom); wacom_release_resources(wacom);
kfifo_free(&wacom_wac->pen_fifo);
hid_set_drvdata(hdev, NULL); hid_set_drvdata(hdev, NULL);
} }
......
...@@ -1924,7 +1924,6 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -1924,7 +1924,6 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
struct wacom_features *features = &wacom_wac->features; struct wacom_features *features = &wacom_wac->features;
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
int i; int i;
bool is_touch_on = value;
bool do_report = false; bool do_report = false;
/* /*
...@@ -1969,16 +1968,17 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -1969,16 +1968,17 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
break; break;
case WACOM_HID_WD_MUTE_DEVICE: case WACOM_HID_WD_MUTE_DEVICE:
if (wacom_wac->shared->touch_input && value) {
wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on;
is_touch_on = wacom_wac->shared->is_touch_on;
}
/* fall through*/
case WACOM_HID_WD_TOUCHONOFF: case WACOM_HID_WD_TOUCHONOFF:
if (wacom_wac->shared->touch_input) { if (wacom_wac->shared->touch_input) {
bool *is_touch_on = &wacom_wac->shared->is_touch_on;
if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value)
*is_touch_on = !(*is_touch_on);
else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)
*is_touch_on = value;
input_report_switch(wacom_wac->shared->touch_input, input_report_switch(wacom_wac->shared->touch_input,
SW_MUTE_DEVICE, !is_touch_on); SW_MUTE_DEVICE, !(*is_touch_on));
input_sync(wacom_wac->shared->touch_input); input_sync(wacom_wac->shared->touch_input);
} }
break; break;
...@@ -2085,7 +2085,29 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, ...@@ -2085,7 +2085,29 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0); wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0);
break; break;
case HID_DG_TOOLSERIALNUMBER: case HID_DG_TOOLSERIALNUMBER:
features->quirks |= WACOM_QUIRK_TOOLSERIAL;
wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0); wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
/* Adjust AES usages to match modern convention */
if (usage->hid == WACOM_HID_WT_SERIALNUMBER && field->report_size == 16) {
if (field->index + 2 < field->report->maxfield) {
struct hid_field *a = field->report->field[field->index + 1];
struct hid_field *b = field->report->field[field->index + 2];
if (a->maxusage > 0 && a->usage[0].hid == HID_DG_TOOLSERIALNUMBER && a->report_size == 32 &&
b->maxusage > 0 && b->usage[0].hid == 0xFF000000 && b->report_size == 8) {
features->quirks |= WACOM_QUIRK_AESPEN;
usage->hid = WACOM_HID_WD_TOOLTYPE;
field->logical_minimum = S16_MIN;
field->logical_maximum = S16_MAX;
a->logical_minimum = S32_MIN;
a->logical_maximum = S32_MAX;
b->usage[0].hid = WACOM_HID_WD_SERIALHI;
b->logical_minimum = 0;
b->logical_maximum = U8_MAX;
}
}
}
break; break;
case WACOM_HID_WD_SENSE: case WACOM_HID_WD_SENSE:
features->quirks |= WACOM_QUIRK_SENSE; features->quirks |= WACOM_QUIRK_SENSE;
...@@ -2093,6 +2115,8 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, ...@@ -2093,6 +2115,8 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
break; break;
case WACOM_HID_WD_SERIALHI: case WACOM_HID_WD_SERIALHI:
wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0); wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
if (!(features->quirks & WACOM_QUIRK_AESPEN)) {
set_bit(EV_KEY, input->evbit); set_bit(EV_KEY, input->evbit);
input_set_capability(input, EV_KEY, BTN_TOOL_PEN); input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER); input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
...@@ -2103,6 +2127,7 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, ...@@ -2103,6 +2127,7 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE); input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
input_set_capability(input, EV_KEY, BTN_TOOL_LENS); input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
} }
}
break; break;
case WACOM_HID_WD_FINGERWHEEL: case WACOM_HID_WD_FINGERWHEEL:
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
...@@ -4390,6 +4415,12 @@ static const struct wacom_features wacom_features_0x360 = ...@@ -4390,6 +4415,12 @@ static const struct wacom_features wacom_features_0x360 =
static const struct wacom_features wacom_features_0x361 = static const struct wacom_features wacom_features_0x361 =
{ "Wacom Intuos Pro L", 62200, 43200, 8191, 63, { "Wacom Intuos Pro L", 62200, 43200, 8191, 63,
INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 }; INTUOSP2_BT, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 10 };
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 };
static const struct wacom_features wacom_features_0x37B =
{ "Wacom One by Wacom M", 21600, 13500, 2047, 63,
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_HID_ANY_ID = static const struct wacom_features wacom_features_HID_ANY_ID =
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
...@@ -4558,6 +4589,8 @@ const struct hid_device_id wacom_ids[] = { ...@@ -4558,6 +4589,8 @@ const struct hid_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x343) }, { USB_DEVICE_WACOM(0x343) },
{ BT_DEVICE_WACOM(0x360) }, { BT_DEVICE_WACOM(0x360) },
{ BT_DEVICE_WACOM(0x361) }, { BT_DEVICE_WACOM(0x361) },
{ USB_DEVICE_WACOM(0x37A) },
{ USB_DEVICE_WACOM(0x37B) },
{ USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x4004) },
{ USB_DEVICE_WACOM(0x5000) }, { USB_DEVICE_WACOM(0x5000) },
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/kfifo.h>
/* maximum packet length for USB/BT devices */ /* maximum packet length for USB/BT devices */
#define WACOM_PKGLEN_MAX 361 #define WACOM_PKGLEN_MAX 361
...@@ -86,7 +87,9 @@ ...@@ -86,7 +87,9 @@
/* device quirks */ /* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
#define WACOM_QUIRK_SENSE 0x0002 #define WACOM_QUIRK_SENSE 0x0002
#define WACOM_QUIRK_AESPEN 0x0004
#define WACOM_QUIRK_BATTERY 0x0008 #define WACOM_QUIRK_BATTERY 0x0008
#define WACOM_QUIRK_TOOLSERIAL 0x0010
/* device types */ /* device types */
#define WACOM_DEVICETYPE_NONE 0x0000 #define WACOM_DEVICETYPE_NONE 0x0000
...@@ -107,6 +110,7 @@ ...@@ -107,6 +110,7 @@
#define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02) #define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02)
#define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36) #define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36)
#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39) #define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
#define WACOM_HID_WD_SERIALNUMBER (WACOM_HID_UP_WACOMDIGITIZER | 0x5b)
#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c) #define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
#define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77) #define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132) #define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
...@@ -150,6 +154,7 @@ ...@@ -150,6 +154,7 @@
#define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04) #define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04)
#define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05) #define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05)
#define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55) #define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55)
#define WACOM_HID_WT_SERIALNUMBER (WACOM_HID_UP_WACOMTOUCH | 0x5b)
#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130) #define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130)
#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131) #define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
...@@ -336,6 +341,7 @@ struct wacom_wac { ...@@ -336,6 +341,7 @@ struct wacom_wac {
struct input_dev *pen_input; struct input_dev *pen_input;
struct input_dev *touch_input; struct input_dev *touch_input;
struct input_dev *pad_input; struct input_dev *pad_input;
struct kfifo_rec_ptr_2 pen_fifo;
int pid; int pid;
int num_contacts_left; int num_contacts_left;
u8 bt_features; u8 bt_features;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment