summaryrefslogtreecommitdiffstats
path: root/drivers/hid/wacom_wac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/wacom_wac.c')
-rw-r--r--drivers/hid/wacom_wac.c351
1 files changed, 200 insertions, 151 deletions
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index c68ac65db7ff..e274c9dc32f3 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -773,131 +773,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
return 0;
}
-static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
-{
- unsigned char *data = wacom_wac->data;
- struct input_dev *input;
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- struct wacom_remote *remote = wacom->remote;
- int bat_charging, bat_percent, touch_ring_mode;
- __u32 serial;
- int i, index = -1;
- unsigned long flags;
-
- if (data[0] != WACOM_REPORT_REMOTE) {
- hid_dbg(wacom->hdev, "%s: received unknown report #%d",
- __func__, data[0]);
- return 0;
- }
-
- serial = data[3] + (data[4] << 8) + (data[5] << 16);
- wacom_wac->id[0] = PAD_DEVICE_ID;
-
- spin_lock_irqsave(&remote->remote_lock, flags);
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->remotes[i].serial == serial) {
- index = i;
- break;
- }
- }
-
- if (index < 0 || !remote->remotes[index].registered)
- goto out;
-
- input = remote->remotes[index].input;
-
- input_report_key(input, BTN_0, (data[9] & 0x01));
- input_report_key(input, BTN_1, (data[9] & 0x02));
- input_report_key(input, BTN_2, (data[9] & 0x04));
- input_report_key(input, BTN_3, (data[9] & 0x08));
- input_report_key(input, BTN_4, (data[9] & 0x10));
- input_report_key(input, BTN_5, (data[9] & 0x20));
- input_report_key(input, BTN_6, (data[9] & 0x40));
- input_report_key(input, BTN_7, (data[9] & 0x80));
-
- input_report_key(input, BTN_8, (data[10] & 0x01));
- input_report_key(input, BTN_9, (data[10] & 0x02));
- input_report_key(input, BTN_A, (data[10] & 0x04));
- input_report_key(input, BTN_B, (data[10] & 0x08));
- input_report_key(input, BTN_C, (data[10] & 0x10));
- input_report_key(input, BTN_X, (data[10] & 0x20));
- input_report_key(input, BTN_Y, (data[10] & 0x40));
- input_report_key(input, BTN_Z, (data[10] & 0x80));
-
- input_report_key(input, BTN_BASE, (data[11] & 0x01));
- input_report_key(input, BTN_BASE2, (data[11] & 0x02));
-
- if (data[12] & 0x80)
- input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
- else
- input_report_abs(input, ABS_WHEEL, 0);
-
- bat_percent = data[7] & 0x7f;
- bat_charging = !!(data[7] & 0x80);
-
- if (data[9] | data[10] | (data[11] & 0x03) | data[12])
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- else
- input_report_abs(input, ABS_MISC, 0);
-
- input_event(input, EV_MSC, MSC_SERIAL, serial);
-
- input_sync(input);
-
- /*Which mode select (LED light) is currently on?*/
- touch_ring_mode = (data[11] & 0xC0) >> 6;
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- if (remote->remotes[i].serial == serial)
- wacom->led.groups[i].select = touch_ring_mode;
- }
-
- __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
- bat_charging, 1, bat_charging);
-
-out:
- spin_unlock_irqrestore(&remote->remote_lock, flags);
- return 0;
-}
-
-static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
-{
- struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
- unsigned char *data = wacom_wac->data;
- struct wacom_remote *remote = wacom->remote;
- struct wacom_remote_data remote_data;
- unsigned long flags;
- int i, ret;
-
- if (data[0] != WACOM_REPORT_DEVICE_LIST)
- return;
-
- memset(&remote_data, 0, sizeof(struct wacom_remote_data));
-
- for (i = 0; i < WACOM_MAX_REMOTES; i++) {
- int j = i * 6;
- int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
- bool connected = data[j+2];
-
- remote_data.remote[i].serial = serial;
- remote_data.remote[i].connected = connected;
- }
-
- spin_lock_irqsave(&remote->remote_lock, flags);
-
- ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
- if (ret != sizeof(remote_data)) {
- spin_unlock_irqrestore(&remote->remote_lock, flags);
- hid_err(wacom->hdev, "Can't queue Remote status event.\n");
- return;
- }
-
- spin_unlock_irqrestore(&remote->remote_lock, flags);
-
- wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
-}
-
static inline bool report_touch_events(struct wacom_wac *wacom)
{
return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
@@ -1116,6 +991,131 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 0;
}
+static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+ unsigned char *data = wacom_wac->data;
+ struct input_dev *input;
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct wacom_remote *remote = wacom->remote;
+ int bat_charging, bat_percent, touch_ring_mode;
+ __u32 serial;
+ int i, index = -1;
+ unsigned long flags;
+
+ if (data[0] != WACOM_REPORT_REMOTE) {
+ hid_dbg(wacom->hdev, "%s: received unknown report #%d",
+ __func__, data[0]);
+ return 0;
+ }
+
+ serial = data[3] + (data[4] << 8) + (data[5] << 16);
+ wacom_wac->id[0] = PAD_DEVICE_ID;
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0 || !remote->remotes[index].registered)
+ goto out;
+
+ input = remote->remotes[index].input;
+
+ input_report_key(input, BTN_0, (data[9] & 0x01));
+ input_report_key(input, BTN_1, (data[9] & 0x02));
+ input_report_key(input, BTN_2, (data[9] & 0x04));
+ input_report_key(input, BTN_3, (data[9] & 0x08));
+ input_report_key(input, BTN_4, (data[9] & 0x10));
+ input_report_key(input, BTN_5, (data[9] & 0x20));
+ input_report_key(input, BTN_6, (data[9] & 0x40));
+ input_report_key(input, BTN_7, (data[9] & 0x80));
+
+ input_report_key(input, BTN_8, (data[10] & 0x01));
+ input_report_key(input, BTN_9, (data[10] & 0x02));
+ input_report_key(input, BTN_A, (data[10] & 0x04));
+ input_report_key(input, BTN_B, (data[10] & 0x08));
+ input_report_key(input, BTN_C, (data[10] & 0x10));
+ input_report_key(input, BTN_X, (data[10] & 0x20));
+ input_report_key(input, BTN_Y, (data[10] & 0x40));
+ input_report_key(input, BTN_Z, (data[10] & 0x80));
+
+ input_report_key(input, BTN_BASE, (data[11] & 0x01));
+ input_report_key(input, BTN_BASE2, (data[11] & 0x02));
+
+ if (data[12] & 0x80)
+ input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
+ else
+ input_report_abs(input, ABS_WHEEL, 0);
+
+ bat_percent = data[7] & 0x7f;
+ bat_charging = !!(data[7] & 0x80);
+
+ if (data[9] | data[10] | (data[11] & 0x03) | data[12])
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ else
+ input_report_abs(input, ABS_MISC, 0);
+
+ input_event(input, EV_MSC, MSC_SERIAL, serial);
+
+ input_sync(input);
+
+ /*Which mode select (LED light) is currently on?*/
+ touch_ring_mode = (data[11] & 0xC0) >> 6;
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ if (remote->remotes[i].serial == serial)
+ wacom->led.groups[i].select = touch_ring_mode;
+ }
+
+ __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+ bat_charging, 1, bat_charging);
+
+out:
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ return 0;
+}
+
+static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+ struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ unsigned char *data = wacom_wac->data;
+ struct wacom_remote *remote = wacom->remote;
+ struct wacom_remote_data remote_data;
+ unsigned long flags;
+ int i, ret;
+
+ if (data[0] != WACOM_REPORT_DEVICE_LIST)
+ return;
+
+ memset(&remote_data, 0, sizeof(struct wacom_remote_data));
+
+ for (i = 0; i < WACOM_MAX_REMOTES; i++) {
+ int j = i * 6;
+ int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
+ bool connected = data[j+2];
+
+ remote_data.remote[i].serial = serial;
+ remote_data.remote[i].connected = connected;
+ }
+
+ spin_lock_irqsave(&remote->remote_lock, flags);
+
+ ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
+ if (ret != sizeof(remote_data)) {
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+ hid_err(wacom->hdev, "Can't queue Remote status event.\n");
+ return;
+ }
+
+ spin_unlock_irqrestore(&remote->remote_lock, flags);
+
+ wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
+}
+
static int int_dist(int x1, int y1, int x2, int y2)
{
int x = x2 - x1;
@@ -1571,37 +1571,38 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
{
unsigned char *data = wacom->data;
- if (wacom->pen_input)
+ if (wacom->pen_input) {
dev_dbg(wacom->pen_input->dev.parent,
"%s: received report #%d\n", __func__, data[0]);
- else if (wacom->touch_input)
+
+ if (len == WACOM_PKGLEN_PENABLED ||
+ data[0] == WACOM_REPORT_PENABLED)
+ return wacom_tpc_pen(wacom);
+ }
+ else if (wacom->touch_input) {
dev_dbg(wacom->touch_input->dev.parent,
"%s: received report #%d\n", __func__, data[0]);
- switch (len) {
- case WACOM_PKGLEN_TPC1FG:
- return wacom_tpc_single_touch(wacom, len);
-
- case WACOM_PKGLEN_TPC2FG:
- return wacom_tpc_mt_touch(wacom);
+ switch (len) {
+ case WACOM_PKGLEN_TPC1FG:
+ return wacom_tpc_single_touch(wacom, len);
- case WACOM_PKGLEN_PENABLED:
- return wacom_tpc_pen(wacom);
+ case WACOM_PKGLEN_TPC2FG:
+ return wacom_tpc_mt_touch(wacom);
- default:
- switch (data[0]) {
- case WACOM_REPORT_TPC1FG:
- case WACOM_REPORT_TPCHID:
- case WACOM_REPORT_TPCST:
- case WACOM_REPORT_TPC1FGE:
- return wacom_tpc_single_touch(wacom, len);
+ default:
+ switch (data[0]) {
+ case WACOM_REPORT_TPC1FG:
+ case WACOM_REPORT_TPCHID:
+ case WACOM_REPORT_TPCST:
+ case WACOM_REPORT_TPC1FGE:
+ return wacom_tpc_single_touch(wacom, len);
- case WACOM_REPORT_TPCMT:
- case WACOM_REPORT_TPCMT2:
- return wacom_mt_touch(wacom);
+ case WACOM_REPORT_TPCMT:
+ case WACOM_REPORT_TPCMT2:
+ return wacom_mt_touch(wacom);
- case WACOM_REPORT_PENABLED:
- return wacom_tpc_pen(wacom);
+ }
}
}
@@ -1739,6 +1740,7 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
case WACOM_HID_WD_TOUCHONOFF:
+ case WACOM_HID_WD_MUTE_DEVICE:
/*
* This usage, which is used to mute touch events, comes
* from the pad packet, but is reported on the touch
@@ -1768,6 +1770,26 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
+ case WACOM_HID_WD_BUTTONCONFIG:
+ wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_ONSCREEN_KEYBOARD:
+ wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_CONTROLPANEL:
+ wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
+ case WACOM_HID_WD_MODE_CHANGE:
+ /* do not overwrite previous data */
+ if (!wacom_wac->has_mode_change) {
+ wacom_wac->has_mode_change = true;
+ wacom_wac->is_direct_mode = true;
+ }
+ features->device_type |= WACOM_DEVICETYPE_PAD;
+ break;
}
switch (equivalent_usage & 0xfffffff0) {
@@ -1811,12 +1833,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
struct wacom_features *features = &wacom_wac->features;
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
int i;
+ bool is_touch_on = value;
/*
* Avoid reporting this event and setting inrange_state if this usage
* hasn't been mapped.
*/
- if (!usage->type)
+ if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
return;
if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
@@ -1830,14 +1853,28 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
input_event(input, usage->type, usage->code, 0);
break;
+ 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:
if (wacom_wac->shared->touch_input) {
input_report_switch(wacom_wac->shared->touch_input,
- SW_MUTE_DEVICE, !value);
+ SW_MUTE_DEVICE, !is_touch_on);
input_sync(wacom_wac->shared->touch_input);
}
break;
+ case WACOM_HID_WD_MODE_CHANGE:
+ if (wacom_wac->is_direct_mode != value) {
+ wacom_wac->is_direct_mode = value;
+ wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
+ }
+ break;
+
case WACOM_HID_WD_BUTTONCENTER:
for (i = 0; i < wacom->led.count; i++)
wacom_update_led(wacom, features->numbered_buttons,
@@ -1845,6 +1882,8 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
/* fall through*/
default:
input_event(input, usage->type, usage->code, value);
+ if (value)
+ wacom_wac->hid_data.pad_input_event_flag = true;
break;
}
}
@@ -1885,9 +1924,12 @@ 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(report->field[0]->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);
+ if (!active)
+ wacom_wac->hid_data.pad_input_event_flag = false;
}
}
@@ -2197,6 +2239,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
bool prox = hid_data->tipswitch &&
report_touch_events(wacom_wac);
+ if (wacom_wac->shared->has_mute_touch_switch &&
+ !wacom_wac->shared->is_touch_on) {
+ if (!wacom_wac->shared->touch_down)
+ return;
+ prox = 0;
+ }
+
wacom_wac->hid_data.num_received++;
if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
return;
@@ -4127,7 +4176,7 @@ static const struct wacom_features wacom_features_0x300 =
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x301 =
{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
- BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x302 =
{ "Wacom Intuos PT S", 15200, 9500, 1023, 31,
INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,