Commit c11fb13a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Jiri Kosina:

 - regression fixes (reverts) for module loading changes that turned out
   to be incompatible with some userspace, from Benjamin Tissoires

 - regression fix for special Logitech unifiying receiver 0xc52f, from
   Hans de Goede

 - a few device ID additions to logitech driver, from Hans de Goede

 - fix for Bluetooth support on 2nd-gen Wacom Intuos Pro, from Jason
   Gerecke

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: logitech-dj: Fix 064d:c52f receiver support
  Revert "HID: core: Call request_module before doing device_add"
  Revert "HID: core: Do not call request_module() in async context"
  Revert "HID: Increase maximum report size allowed by hid_field_extract()"
  HID: a4tech: fix horizontal scrolling
  HID: hyperv: Add a module description line
  HID: logitech-hidpp: Add support for the S510 remote control
  HID: multitouch: handle faulty Elo touch device
  HID: wacom: Sync INTUOSP2_BT touch state after each frame if necessary
  HID: wacom: Correct button numbering 2nd-gen Intuos Pro over Bluetooth
  HID: wacom: Send BTN_TOUCH in response to INTUOSP2_BT eraser contact
  HID: wacom: Don't report anything prior to the tool entering range
  HID: wacom: Don't set tool type until we're in range
  HID: rmi: Use SET_REPORT request on control endpoint for Acer Switch 3 and 5
  HID: logitech-hidpp: add support for the MX5500 keyboard
  HID: logitech-dj: add support for the Logitech MX5500's Bluetooth Mini-Receiver
  HID: i2c-hid: add iBall Aer3 to descriptor override
parents b076173a 3ed224e2
...@@ -35,8 +35,10 @@ static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -35,8 +35,10 @@ static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
{ {
struct a4tech_sc *a4 = hid_get_drvdata(hdev); struct a4tech_sc *a4 = hid_get_drvdata(hdev);
if (usage->type == EV_REL && usage->code == REL_WHEEL) if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
set_bit(REL_HWHEEL, *bit); set_bit(REL_HWHEEL, *bit);
set_bit(REL_HWHEEL_HI_RES, *bit);
}
if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
return -1; return -1;
...@@ -57,7 +59,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field, ...@@ -57,7 +59,7 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
input = field->hidinput->input; input = field->hidinput->input;
if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) { if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
if (usage->type == EV_REL && usage->code == REL_WHEEL) { if (usage->type == EV_REL && usage->code == REL_WHEEL_HI_RES) {
a4->delayed_value = value; a4->delayed_value = value;
return 1; return 1;
} }
...@@ -65,6 +67,8 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field, ...@@ -65,6 +67,8 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
if (usage->hid == 0x000100b8) { if (usage->hid == 0x000100b8) {
input_event(input, EV_REL, value ? REL_HWHEEL : input_event(input, EV_REL, value ? REL_HWHEEL :
REL_WHEEL, a4->delayed_value); REL_WHEEL, a4->delayed_value);
input_event(input, EV_REL, value ? REL_HWHEEL_HI_RES :
REL_WHEEL_HI_RES, a4->delayed_value * 120);
return 1; return 1;
} }
} }
...@@ -74,8 +78,9 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field, ...@@ -74,8 +78,9 @@ static int a4_event(struct hid_device *hdev, struct hid_field *field,
return 1; return 1;
} }
if (usage->code == REL_WHEEL && a4->hw_wheel) { if (usage->code == REL_WHEEL_HI_RES && a4->hw_wheel) {
input_event(input, usage->type, REL_HWHEEL, value); input_event(input, usage->type, REL_HWHEEL, value);
input_event(input, usage->type, REL_HWHEEL_HI_RES, value * 120);
return 1; return 1;
} }
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/async.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hiddev.h> #include <linux/hiddev.h>
...@@ -1311,10 +1310,10 @@ static u32 __extract(u8 *report, unsigned offset, int n) ...@@ -1311,10 +1310,10 @@ static u32 __extract(u8 *report, unsigned offset, int n)
u32 hid_field_extract(const struct hid_device *hid, u8 *report, u32 hid_field_extract(const struct hid_device *hid, u8 *report,
unsigned offset, unsigned n) unsigned offset, unsigned n)
{ {
if (n > 256) { if (n > 32) {
hid_warn(hid, "hid_field_extract() called with n (%d) > 256! (%s)\n", hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n",
n, current->comm); n, current->comm);
n = 256; n = 32;
} }
return __extract(report, offset, n); return __extract(report, offset, n);
...@@ -2362,15 +2361,6 @@ int hid_add_device(struct hid_device *hdev) ...@@ -2362,15 +2361,6 @@ int hid_add_device(struct hid_device *hdev)
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
hdev->vendor, hdev->product, atomic_inc_return(&id)); hdev->vendor, hdev->product, atomic_inc_return(&id));
/*
* Try loading the module for the device before the add, so that we do
* not first have hid-generic binding only to have it replaced
* immediately afterwards with a specialized driver.
*/
if (!current_is_async())
request_module("hid:b%04Xg%04Xv%08Xp%08X", hdev->bus,
hdev->group, hdev->vendor, hdev->product);
hid_debug_register(hdev, dev_name(&hdev->dev)); hid_debug_register(hdev, dev_name(&hdev->dev));
ret = device_add(&hdev->dev); ret = device_add(&hdev->dev);
if (!ret) if (!ret)
......
...@@ -606,5 +606,7 @@ static void __exit mousevsc_exit(void) ...@@ -606,5 +606,7 @@ static void __exit mousevsc_exit(void)
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver");
module_init(mousevsc_init); module_init(mousevsc_init);
module_exit(mousevsc_exit); module_exit(mousevsc_exit);
...@@ -1086,6 +1086,7 @@ ...@@ -1086,6 +1086,7 @@
#define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 #define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3
#define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3
#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710
#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7
#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047
#define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855 #define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855
......
...@@ -113,6 +113,7 @@ enum recvr_type { ...@@ -113,6 +113,7 @@ enum recvr_type {
recvr_type_dj, recvr_type_dj,
recvr_type_hidpp, recvr_type_hidpp,
recvr_type_gaming_hidpp, recvr_type_gaming_hidpp,
recvr_type_mouse_only,
recvr_type_27mhz, recvr_type_27mhz,
recvr_type_bluetooth, recvr_type_bluetooth,
}; };
...@@ -864,9 +865,12 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev, ...@@ -864,9 +865,12 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
schedule_work(&djrcv_dev->work); schedule_work(&djrcv_dev->work);
} }
static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report, static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
struct hidpp_event *hidpp_report,
struct dj_workitem *workitem) struct dj_workitem *workitem)
{ {
struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
workitem->type = WORKITEM_TYPE_PAIRED; workitem->type = WORKITEM_TYPE_PAIRED;
workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & workitem->device_type = hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
HIDPP_DEVICE_TYPE_MASK; HIDPP_DEVICE_TYPE_MASK;
...@@ -880,6 +884,8 @@ static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report, ...@@ -880,6 +884,8 @@ static void logi_hidpp_dev_conn_notif_equad(struct hidpp_event *hidpp_report,
break; break;
case REPORT_TYPE_MOUSE: case REPORT_TYPE_MOUSE:
workitem->reports_supported |= STD_MOUSE | HIDPP; workitem->reports_supported |= STD_MOUSE | HIDPP;
if (djrcv_dev->type == recvr_type_mouse_only)
workitem->reports_supported |= MULTIMEDIA;
break; break;
} }
} }
...@@ -923,7 +929,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -923,7 +929,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
case 0x01: case 0x01:
device_type = "Bluetooth"; device_type = "Bluetooth";
/* Bluetooth connect packet contents is the same as (e)QUAD */ /* Bluetooth connect packet contents is the same as (e)QUAD */
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
if (!(hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] & if (!(hidpp_report->params[HIDPP_PARAM_DEVICE_INFO] &
HIDPP_MANUFACTURER_MASK)) { HIDPP_MANUFACTURER_MASK)) {
hid_info(hdev, "Non Logitech device connected on slot %d\n", hid_info(hdev, "Non Logitech device connected on slot %d\n",
...@@ -937,18 +943,18 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -937,18 +943,18 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break; break;
case 0x03: case 0x03:
device_type = "QUAD or eQUAD"; device_type = "QUAD or eQUAD";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x04: case 0x04:
device_type = "eQUAD step 4 DJ"; device_type = "eQUAD step 4 DJ";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x05: case 0x05:
device_type = "DFU Lite"; device_type = "DFU Lite";
break; break;
case 0x06: case 0x06:
device_type = "eQUAD step 4 Lite"; device_type = "eQUAD step 4 Lite";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x07: case 0x07:
device_type = "eQUAD step 4 Gaming"; device_type = "eQUAD step 4 Gaming";
...@@ -958,11 +964,11 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -958,11 +964,11 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break; break;
case 0x0a: case 0x0a:
device_type = "eQUAD nano Lite"; device_type = "eQUAD nano Lite";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x0c: case 0x0c:
device_type = "eQUAD Lightspeed"; device_type = "eQUAD Lightspeed";
logi_hidpp_dev_conn_notif_equad(hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
workitem.reports_supported |= STD_KEYBOARD; workitem.reports_supported |= STD_KEYBOARD;
break; break;
} }
...@@ -1313,7 +1319,8 @@ static int logi_dj_ll_parse(struct hid_device *hid) ...@@ -1313,7 +1319,8 @@ static int logi_dj_ll_parse(struct hid_device *hid)
if (djdev->reports_supported & STD_MOUSE) { if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: %llx\n", dbg_hid("%s: sending a mouse descriptor, reports_supported: %llx\n",
__func__, djdev->reports_supported); __func__, djdev->reports_supported);
if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp) if (djdev->dj_receiver_dev->type == recvr_type_gaming_hidpp ||
djdev->dj_receiver_dev->type == recvr_type_mouse_only)
rdcat(rdesc, &rsize, mse_high_res_descriptor, rdcat(rdesc, &rsize, mse_high_res_descriptor,
sizeof(mse_high_res_descriptor)); sizeof(mse_high_res_descriptor));
else if (djdev->dj_receiver_dev->type == recvr_type_27mhz) else if (djdev->dj_receiver_dev->type == recvr_type_27mhz)
...@@ -1556,15 +1563,19 @@ static int logi_dj_raw_event(struct hid_device *hdev, ...@@ -1556,15 +1563,19 @@ static int logi_dj_raw_event(struct hid_device *hdev,
data[0] = data[1]; data[0] = data[1];
data[1] = 0; data[1] = 0;
} }
/* The 27 MHz mouse-only receiver sends unnumbered mouse data */ /*
* Mouse-only receivers send unnumbered mouse data. The 27 MHz
* receiver uses 6 byte packets, the nano receiver 8 bytes.
*/
if (djrcv_dev->unnumbered_application == HID_GD_MOUSE && if (djrcv_dev->unnumbered_application == HID_GD_MOUSE &&
size == 6) { size <= 8) {
u8 mouse_report[7]; u8 mouse_report[9];
/* Prepend report id */ /* Prepend report id */
mouse_report[0] = REPORT_TYPE_MOUSE; mouse_report[0] = REPORT_TYPE_MOUSE;
memcpy(mouse_report + 1, data, 6); memcpy(mouse_report + 1, data, size);
logi_dj_recv_forward_input_report(hdev, mouse_report, 7); logi_dj_recv_forward_input_report(hdev, mouse_report,
size + 1);
} }
return false; return false;
...@@ -1635,6 +1646,7 @@ static int logi_dj_probe(struct hid_device *hdev, ...@@ -1635,6 +1646,7 @@ static int logi_dj_probe(struct hid_device *hdev,
case recvr_type_dj: no_dj_interfaces = 3; break; case recvr_type_dj: no_dj_interfaces = 3; break;
case recvr_type_hidpp: no_dj_interfaces = 2; break; case recvr_type_hidpp: no_dj_interfaces = 2; break;
case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break; case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break;
case recvr_type_mouse_only: no_dj_interfaces = 2; break;
case recvr_type_27mhz: no_dj_interfaces = 2; break; case recvr_type_27mhz: no_dj_interfaces = 2; break;
case recvr_type_bluetooth: no_dj_interfaces = 2; break; case recvr_type_bluetooth: no_dj_interfaces = 2; break;
} }
...@@ -1808,10 +1820,10 @@ static const struct hid_device_id logi_dj_receivers[] = { ...@@ -1808,10 +1820,10 @@ static const struct hid_device_id logi_dj_receivers[] = {
{HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, {HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2), USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2),
.driver_data = recvr_type_dj}, .driver_data = recvr_type_dj},
{ /* Logitech Nano (non DJ) receiver */ { /* Logitech Nano mouse only receiver */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER),
.driver_data = recvr_type_hidpp}, .driver_data = recvr_type_mouse_only},
{ /* Logitech Nano (non DJ) receiver */ { /* Logitech Nano (non DJ) receiver */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
...@@ -1836,6 +1848,14 @@ static const struct hid_device_id logi_dj_receivers[] = { ...@@ -1836,6 +1848,14 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
0xc70a), 0xc70a),
.driver_data = recvr_type_bluetooth}, .driver_data = recvr_type_bluetooth},
{ /* Logitech MX5500 HID++ / bluetooth receiver keyboard intf. */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
0xc71b),
.driver_data = recvr_type_bluetooth},
{ /* Logitech MX5500 HID++ / bluetooth receiver mouse intf. */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
0xc71c),
.driver_data = recvr_type_bluetooth},
{} {}
}; };
......
...@@ -3728,6 +3728,9 @@ static const struct hid_device_id hidpp_devices[] = { ...@@ -3728,6 +3728,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */ { /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */
LDJ_DEVICE(0xb305), LDJ_DEVICE(0xb305),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{ /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */
LDJ_DEVICE(0xb30b),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{ LDJ_DEVICE(HID_ANY_ID) }, { LDJ_DEVICE(HID_ANY_ID) },
...@@ -3740,6 +3743,9 @@ static const struct hid_device_id hidpp_devices[] = { ...@@ -3740,6 +3743,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* Keyboard MX3200 (Y-RAV80) */ { /* Keyboard MX3200 (Y-RAV80) */
L27MHZ_DEVICE(0x005c), L27MHZ_DEVICE(0x005c),
.driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL }, .driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL },
{ /* S510 Media Remote */
L27MHZ_DEVICE(0x00fe),
.driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL },
{ L27MHZ_DEVICE(HID_ANY_ID) }, { L27MHZ_DEVICE(HID_ANY_ID) },
...@@ -3756,6 +3762,9 @@ static const struct hid_device_id hidpp_devices[] = { ...@@ -3756,6 +3762,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ /* MX5000 keyboard over Bluetooth */ { /* MX5000 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305), HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{ /* MX5500 keyboard over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
{} {}
}; };
......
...@@ -637,6 +637,13 @@ static void mt_store_field(struct hid_device *hdev, ...@@ -637,6 +637,13 @@ static void mt_store_field(struct hid_device *hdev,
if (*target != DEFAULT_TRUE && if (*target != DEFAULT_TRUE &&
*target != DEFAULT_FALSE && *target != DEFAULT_FALSE &&
*target != DEFAULT_ZERO) { *target != DEFAULT_ZERO) {
if (usage->contactid == DEFAULT_ZERO ||
usage->x == DEFAULT_ZERO ||
usage->y == DEFAULT_ZERO) {
hid_dbg(hdev,
"ignoring duplicate usage on incomplete");
return;
}
usage = mt_allocate_usage(hdev, application); usage = mt_allocate_usage(hdev, application);
if (!usage) if (!usage)
return; return;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
/* device flags */ /* device flags */
#define RMI_DEVICE BIT(0) #define RMI_DEVICE BIT(0)
#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1)
#define RMI_DEVICE_OUTPUT_SET_REPORT BIT(2)
/* /*
* retrieve the ctrl registers * retrieve the ctrl registers
...@@ -163,9 +164,19 @@ static int rmi_set_mode(struct hid_device *hdev, u8 mode) ...@@ -163,9 +164,19 @@ static int rmi_set_mode(struct hid_device *hdev, u8 mode)
static int rmi_write_report(struct hid_device *hdev, u8 *report, int len) static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
{ {
struct rmi_data *data = hid_get_drvdata(hdev);
int ret; int ret;
if (data->device_flags & RMI_DEVICE_OUTPUT_SET_REPORT) {
/*
* Talk to device by using SET_REPORT requests instead.
*/
ret = hid_hw_raw_request(hdev, report[0], report,
len, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
} else {
ret = hid_hw_output_report(hdev, (void *)report, len); ret = hid_hw_output_report(hdev, (void *)report, len);
}
if (ret < 0) { if (ret < 0) {
dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret); dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
return ret; return ret;
...@@ -747,6 +758,8 @@ static const struct hid_device_id rmi_id[] = { ...@@ -747,6 +758,8 @@ static const struct hid_device_id rmi_id[] = {
.driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5),
.driver_data = RMI_DEVICE_OUTPUT_SET_REPORT },
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
{ } { }
}; };
......
...@@ -354,6 +354,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { ...@@ -354,6 +354,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
}, },
.driver_data = (void *)&sipodev_desc .driver_data = (void *)&sipodev_desc
}, },
{
.ident = "iBall Aer3",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "iBall"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Aer3"),
},
.driver_data = (void *)&sipodev_desc
},
{ } /* Terminate list */ { } /* Terminate list */
}; };
......
...@@ -1232,13 +1232,13 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1232,13 +1232,13 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
/* Add back in missing bits of ID for non-USI pens */ /* Add back in missing bits of ID for non-USI pens */
wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF; wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF;
} }
wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0]));
for (i = 0; i < pen_frames; i++) { for (i = 0; i < pen_frames; i++) {
unsigned char *frame = &data[i*pen_frame_len + 1]; unsigned char *frame = &data[i*pen_frame_len + 1];
bool valid = frame[0] & 0x80; bool valid = frame[0] & 0x80;
bool prox = frame[0] & 0x40; bool prox = frame[0] & 0x40;
bool range = frame[0] & 0x20; bool range = frame[0] & 0x20;
bool invert = frame[0] & 0x10;
if (!valid) if (!valid)
continue; continue;
...@@ -1247,9 +1247,24 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1247,9 +1247,24 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
wacom->shared->stylus_in_proximity = false; wacom->shared->stylus_in_proximity = false;
wacom_exit_report(wacom); wacom_exit_report(wacom);
input_sync(pen_input); input_sync(pen_input);
wacom->tool[0] = 0;
wacom->id[0] = 0;
wacom->serial[0] = 0;
return; return;
} }
if (range) { if (range) {
if (!wacom->tool[0]) { /* first in range */
/* Going into range select tool */
if (invert)
wacom->tool[0] = BTN_TOOL_RUBBER;
else if (wacom->id[0])
wacom->tool[0] = wacom_intuos_get_tool_type(wacom->id[0]);
else
wacom->tool[0] = BTN_TOOL_PEN;
}
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); 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_Y, get_unaligned_le16(&frame[3]));
...@@ -1271,6 +1286,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1271,6 +1286,8 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
get_unaligned_le16(&frame[11])); get_unaligned_le16(&frame[11]));
} }
} }
if (wacom->tool[0]) {
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
if (wacom->features.type == INTUOSP2_BT) { if (wacom->features.type == INTUOSP2_BT) {
input_report_abs(pen_input, ABS_DISTANCE, input_report_abs(pen_input, ABS_DISTANCE,
...@@ -1280,7 +1297,7 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1280,7 +1297,7 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
range ? frame[7] : wacom->features.distance_max); range ? frame[7] : wacom->features.distance_max);
} }
input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01); input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x09);
input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02); input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02);
input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04); input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04);
...@@ -1288,6 +1305,7 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1288,6 +1305,7 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]); input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]);
input_report_abs(pen_input, ABS_MISC, input_report_abs(pen_input, ABS_MISC,
wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */ wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */
}
wacom->shared->stylus_in_proximity = prox; wacom->shared->stylus_in_proximity = prox;
...@@ -1349,11 +1367,17 @@ static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom) ...@@ -1349,11 +1367,17 @@ static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom)
if (wacom->num_contacts_left <= 0) { if (wacom->num_contacts_left <= 0) {
wacom->num_contacts_left = 0; wacom->num_contacts_left = 0;
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
input_sync(touch_input);
} }
} }
if (wacom->num_contacts_left == 0) {
// Be careful that we don't accidentally call input_sync with
// only a partial set of fingers of processed
input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7)); input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7));
input_sync(touch_input); input_sync(touch_input);
}
} }
static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom) static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
...@@ -1361,7 +1385,7 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom) ...@@ -1361,7 +1385,7 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)