mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 17:41:44 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - remove hid_have_special_driver[] entry hard requirement for any newly supported VID/PID by a specific non-core hid driver, and general related cleanup of HID matching core, from Benjamin Tissoires - support for new Wacom devices and a few small fixups for already supported ones in Wacom driver, from Aaron Armstrong Skomra and Jason Gerecke - sysfs interface fix for roccat driver from Dan Carpenter - support for new Asus HW (T100TAF, T100HA, T200TA) from Hans de Goede - improved support for Jabra devices, from Niels Skou Olsen - other assorted small fixes and new device IDs * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (30 commits) HID: quirks: Fix keyboard + touchpad on Toshiba Click Mini not working HID: roccat: prevent an out of bounds read in kovaplus_profile_activated() HID: asus: Fix special function keys on T200TA HID: asus: Add touchpad max x/y and resolution info for the T200TA HID: wacom: Add support for One by Wacom (CTL-472 / CTL-672) HID: wacom: Fix reporting of touch toggle (WACOM_HID_WD_MUTE_DEVICE) events HID: intel-ish-hid: Enable Cannon Lake and Coffee Lake laptop/desktop HID: elecom: rewrite report fixup for EX-G and future mice HID: sony: Report DS4 version info through sysfs HID: sony: Print reversed MAC address via %pMR HID: wacom: EKR: ensure devres groups at higher indexes are released HID: rmi: Support the Fujitsu R726 Pad dock using hid-rmi HID: add quirk for another PIXART OEM mouse used by HP HID: quirks: make array hid_quirks static HID: hid-multitouch: support fine-grain orientation reporting HID: asus: Add product-id for the T100TAF and T100HA keyboard docks HID: elo: clear BTN_LEFT mapping HID: multitouch: Combine all left-button events in a frame HID: multitouch: Only look at non touch fields in first packet of a frame HID: multitouch: Properly deal with Win8 PTP reports with 0 touches ...
This commit is contained in:
commit
183b6366cf
@ -31,7 +31,7 @@ device-specific compatible properties, which should be used in addition to the
|
||||
|
||||
- vdd-supply: phandle of the regulator that provides the supply voltage.
|
||||
- post-power-on-delay-ms: time required by the device after enabling its regulators
|
||||
before it is ready for communication. Must be used with 'vdd-supply'.
|
||||
or powering it on, before it is ready for communication.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -269,10 +269,11 @@ ABS_MT_ORIENTATION
|
||||
The orientation of the touching ellipse. The value should describe a signed
|
||||
quarter of a revolution clockwise around the touch center. The signed value
|
||||
range is arbitrary, but zero should be returned for an ellipse aligned with
|
||||
the Y axis of the surface, a negative value when the ellipse is turned to
|
||||
the left, and a positive value when the ellipse is turned to the
|
||||
right. When completely aligned with the X axis, the range max should be
|
||||
returned.
|
||||
the Y axis (north) of the surface, a negative value when the ellipse is
|
||||
turned to the left, and a positive value when the ellipse is turned to the
|
||||
right. When aligned with the X axis in the positive direction, the range
|
||||
max should be returned; when aligned with the X axis in the negative
|
||||
direction, the range -max should be returned.
|
||||
|
||||
Touch ellipsis are symmetrical by default. For devices capable of true 360
|
||||
degree orientation, the reported orientation must exceed the range max to
|
||||
|
@ -280,6 +280,7 @@ config HID_ELECOM
|
||||
---help---
|
||||
Support for ELECOM devices:
|
||||
- BM084 Bluetooth Mouse
|
||||
- EX-G Trackball (Wired and wireless)
|
||||
- DEFT Trackball (Wired and wireless)
|
||||
- HUGE Trackball (Wired and wireless)
|
||||
|
||||
@ -396,6 +397,17 @@ config HID_ITE
|
||||
---help---
|
||||
Support for ITE devices not fully compliant with HID standard.
|
||||
|
||||
config HID_JABRA
|
||||
tristate "Jabra USB HID Driver"
|
||||
depends on HID
|
||||
---help---
|
||||
Support for Jabra USB HID devices.
|
||||
|
||||
Prevents mapping of vendor defined HID usages to input events. Without
|
||||
this driver HID reports from Jabra devices may incorrectly be seen as
|
||||
mouse button events.
|
||||
Say M here if you may ever plug in a Jabra USB device.
|
||||
|
||||
config HID_TWINHAN
|
||||
tristate "Twinhan IR remote control"
|
||||
depends on HID
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Makefile for the HID driver
|
||||
#
|
||||
hid-y := hid-core.o hid-input.o
|
||||
hid-y := hid-core.o hid-input.o hid-quirks.o
|
||||
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
|
||||
|
||||
obj-$(CONFIG_HID) += hid.o
|
||||
@ -52,6 +52,7 @@ obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
|
||||
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
|
||||
obj-$(CONFIG_HID_ICADE) += hid-icade.o
|
||||
obj-$(CONFIG_HID_ITE) += hid-ite.o
|
||||
obj-$(CONFIG_HID_JABRA) += hid-jabra.o
|
||||
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
|
||||
obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
|
||||
obj-$(CONFIG_HID_KYE) += hid-kye.o
|
||||
|
@ -26,6 +26,7 @@
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input/mt.h>
|
||||
@ -119,6 +120,24 @@ static const struct asus_touchpad_info asus_t100ta_tp = {
|
||||
.max_contacts = 5,
|
||||
};
|
||||
|
||||
static const struct asus_touchpad_info asus_t100ha_tp = {
|
||||
.max_x = 2640,
|
||||
.max_y = 1320,
|
||||
.res_x = 30, /* units/mm */
|
||||
.res_y = 29, /* units/mm */
|
||||
.contact_size = 5,
|
||||
.max_contacts = 5,
|
||||
};
|
||||
|
||||
static const struct asus_touchpad_info asus_t200ta_tp = {
|
||||
.max_x = 3120,
|
||||
.max_y = 1716,
|
||||
.res_x = 30, /* units/mm */
|
||||
.res_y = 28, /* units/mm */
|
||||
.contact_size = 5,
|
||||
.max_contacts = 5,
|
||||
};
|
||||
|
||||
static const struct asus_touchpad_info asus_t100chi_tp = {
|
||||
.max_x = 2640,
|
||||
.max_y = 1320,
|
||||
@ -606,7 +625,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
|
||||
drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING;
|
||||
drvdata->tp = &asus_t100ta_tp;
|
||||
/*
|
||||
* The T100HA uses the same USB-ids as the T100TAF and
|
||||
* the T200TA uses the same USB-ids as the T100TA, while
|
||||
* both have different max x/y values as the T100TA[F].
|
||||
*/
|
||||
if (dmi_match(DMI_PRODUCT_NAME, "T100HAN"))
|
||||
drvdata->tp = &asus_t100ha_tp;
|
||||
else if (dmi_match(DMI_PRODUCT_NAME, "T200TA"))
|
||||
drvdata->tp = &asus_t200ta_tp;
|
||||
else
|
||||
drvdata->tp = &asus_t100ta_tp;
|
||||
}
|
||||
}
|
||||
|
||||
@ -686,9 +715,10 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
|
||||
rdesc[55] = 0xdd;
|
||||
}
|
||||
/* For the T100TA keyboard dock */
|
||||
/* For the T100TA/T200TA keyboard dock */
|
||||
if (drvdata->quirks & QUIRK_T100_KEYBOARD &&
|
||||
*rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) {
|
||||
(*rsize == 76 || *rsize == 101) &&
|
||||
rdesc[73] == 0x81 && rdesc[74] == 0x01) {
|
||||
hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
|
||||
rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
|
||||
}
|
||||
@ -751,7 +781,10 @@ static const struct hid_device_id asus_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD),
|
||||
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
|
||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD),
|
||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,15 @@
|
||||
/*
|
||||
* HID driver for ELECOM devices.
|
||||
* HID driver for ELECOM devices:
|
||||
* - BM084 Bluetooth Mouse
|
||||
* - EX-G Trackball (Wired and wireless)
|
||||
* - DEFT Trackball (Wired and wireless)
|
||||
* - HUGE Trackball (Wired and wireless)
|
||||
*
|
||||
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
|
||||
* Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
|
||||
* Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu>
|
||||
* Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org>
|
||||
* Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -19,6 +25,34 @@
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
/*
|
||||
* Certain ELECOM mice misreport their button count meaning that they only work
|
||||
* correctly with the ELECOM mouse assistant software which is unavailable for
|
||||
* Linux. A four extra INPUT reports and a FEATURE report are described by the
|
||||
* report descriptor but it does not appear that these enable software to
|
||||
* control what the extra buttons map to. The only simple and straightforward
|
||||
* solution seems to involve fixing up the report descriptor.
|
||||
*
|
||||
* Report descriptor format:
|
||||
* Positions 13, 15, 21 and 31 store the button bit count, button usage minimum,
|
||||
* button usage maximum and padding bit count respectively.
|
||||
*/
|
||||
#define MOUSE_BUTTONS_MAX 8
|
||||
static void mouse_button_fixup(struct hid_device *hdev,
|
||||
__u8 *rdesc, unsigned int rsize,
|
||||
int nbuttons)
|
||||
{
|
||||
if (rsize < 32 || rdesc[12] != 0x95 ||
|
||||
rdesc[14] != 0x75 || rdesc[15] != 0x01 ||
|
||||
rdesc[20] != 0x29 || rdesc[30] != 0x75)
|
||||
return;
|
||||
hid_info(hdev, "Fixing up Elecom mouse button count\n");
|
||||
nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX);
|
||||
rdesc[13] = nbuttons;
|
||||
rdesc[21] = nbuttons;
|
||||
rdesc[31] = MOUSE_BUTTONS_MAX - nbuttons;
|
||||
}
|
||||
|
||||
static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
@ -31,45 +65,15 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
rdesc[47] = 0x00;
|
||||
}
|
||||
break;
|
||||
case USB_DEVICE_ID_ELECOM_EX_G_WIRED:
|
||||
case USB_DEVICE_ID_ELECOM_EX_G_WIRELESS:
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 6);
|
||||
break;
|
||||
case USB_DEVICE_ID_ELECOM_DEFT_WIRED:
|
||||
case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS:
|
||||
case USB_DEVICE_ID_ELECOM_HUGE_WIRED:
|
||||
case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS:
|
||||
/* The DEFT/HUGE trackball has eight buttons, but its descriptor
|
||||
* only reports five, disabling the three Fn buttons on the top
|
||||
* of the mouse.
|
||||
*
|
||||
* Apply the following diff to the descriptor:
|
||||
*
|
||||
* Collection (Physical), Collection (Physical),
|
||||
* Report ID (1), Report ID (1),
|
||||
* Report Count (5), -> Report Count (8),
|
||||
* Report Size (1), Report Size (1),
|
||||
* Usage Page (Button), Usage Page (Button),
|
||||
* Usage Minimum (01h), Usage Minimum (01h),
|
||||
* Usage Maximum (05h), -> Usage Maximum (08h),
|
||||
* Logical Minimum (0), Logical Minimum (0),
|
||||
* Logical Maximum (1), Logical Maximum (1),
|
||||
* Input (Variable), Input (Variable),
|
||||
* Report Count (1), -> Report Count (0),
|
||||
* Report Size (3), Report Size (3),
|
||||
* Input (Constant), Input (Constant),
|
||||
* Report Size (16), Report Size (16),
|
||||
* Report Count (2), Report Count (2),
|
||||
* Usage Page (Desktop), Usage Page (Desktop),
|
||||
* Usage (X), Usage (X),
|
||||
* Usage (Y), Usage (Y),
|
||||
* Logical Minimum (-32768), Logical Minimum (-32768),
|
||||
* Logical Maximum (32767), Logical Maximum (32767),
|
||||
* Input (Variable, Relative), Input (Variable, Relative),
|
||||
* End Collection, End Collection,
|
||||
*/
|
||||
if (*rsize == 213 && rdesc[13] == 5 && rdesc[21] == 5) {
|
||||
hid_info(hdev, "Fixing up Elecom DEFT/HUGE Fn buttons\n");
|
||||
rdesc[13] = 8; /* Button/Variable Report Count */
|
||||
rdesc[21] = 8; /* Button/Variable Usage Maximum */
|
||||
rdesc[29] = 0; /* Button/Constant Report Count */
|
||||
}
|
||||
mouse_button_fixup(hdev, rdesc, *rsize, 8);
|
||||
break;
|
||||
}
|
||||
return rdesc;
|
||||
@ -77,6 +81,8 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
|
||||
static const struct hid_device_id elecom_devices[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRELESS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) },
|
||||
|
@ -42,6 +42,12 @@ static int elo_input_configured(struct hid_device *hdev,
|
||||
{
|
||||
struct input_dev *input = hidinput->input;
|
||||
|
||||
/*
|
||||
* ELO devices have one Button usage in GenDesk field, which makes
|
||||
* hid-input map it to BTN_LEFT; that confuses userspace, which then
|
||||
* considers the device to be a mouse/touchpad instead of touchscreen.
|
||||
*/
|
||||
clear_bit(BTN_LEFT, input->keybit);
|
||||
set_bit(BTN_TOUCH, input->keybit);
|
||||
set_bit(ABS_PRESSURE, input->absbit);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
|
||||
|
@ -24,8 +24,71 @@
|
||||
|
||||
#include <linux/hid.h>
|
||||
|
||||
static struct hid_driver hid_generic;
|
||||
|
||||
static int __unmap_hid_generic(struct device *dev, void *data)
|
||||
{
|
||||
struct hid_driver *hdrv = data;
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
|
||||
/* only unbind matching devices already bound to hid-generic */
|
||||
if (hdev->driver != &hid_generic ||
|
||||
hid_match_device(hdev, hdrv) == NULL)
|
||||
return 0;
|
||||
|
||||
if (dev->parent) /* Needed for USB */
|
||||
device_lock(dev->parent);
|
||||
device_release_driver(dev);
|
||||
if (dev->parent)
|
||||
device_unlock(dev->parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hid_generic_add_driver(struct hid_driver *hdrv)
|
||||
{
|
||||
bus_for_each_dev(&hid_bus_type, NULL, hdrv, __unmap_hid_generic);
|
||||
}
|
||||
|
||||
static void hid_generic_removed_driver(struct hid_driver *hdrv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = driver_attach(&hid_generic.driver);
|
||||
}
|
||||
|
||||
static int __check_hid_generic(struct device_driver *drv, void *data)
|
||||
{
|
||||
struct hid_driver *hdrv = to_hid_driver(drv);
|
||||
struct hid_device *hdev = data;
|
||||
|
||||
if (hdrv == &hid_generic)
|
||||
return 0;
|
||||
|
||||
return hid_match_device(hdev, hdrv) != NULL;
|
||||
}
|
||||
|
||||
static bool hid_generic_match(struct hid_device *hdev,
|
||||
bool ignore_special_driver)
|
||||
{
|
||||
if (ignore_special_driver)
|
||||
return true;
|
||||
|
||||
if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If any other driver wants the device, leave the device to this other
|
||||
* driver.
|
||||
*/
|
||||
if (bus_for_each_drv(&hid_bus_type, NULL, hdev, __check_hid_generic))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct hid_device_id hid_table[] = {
|
||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
|
||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, hid_table);
|
||||
@ -33,6 +96,9 @@ MODULE_DEVICE_TABLE(hid, hid_table);
|
||||
static struct hid_driver hid_generic = {
|
||||
.name = "hid-generic",
|
||||
.id_table = hid_table,
|
||||
.match = hid_generic_match,
|
||||
.bus_add_driver = hid_generic_add_driver,
|
||||
.bus_removed_driver = hid_generic_removed_driver,
|
||||
};
|
||||
module_hid_driver(hid_generic);
|
||||
|
||||
|
@ -178,7 +178,8 @@
|
||||
#define USB_VENDOR_ID_ASUSTEK 0x0b05
|
||||
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
|
||||
#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
|
||||
#define USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD 0x17e0
|
||||
#define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD 0x17e0
|
||||
#define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807
|
||||
#define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502
|
||||
#define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a
|
||||
#define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585
|
||||
@ -370,6 +371,8 @@
|
||||
|
||||
#define USB_VENDOR_ID_ELECOM 0x056e
|
||||
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
|
||||
#define USB_DEVICE_ID_ELECOM_EX_G_WIRED 0x00fb
|
||||
#define USB_DEVICE_ID_ELECOM_EX_G_WIRELESS 0x00fc
|
||||
#define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe
|
||||
#define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff
|
||||
#define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c
|
||||
@ -535,6 +538,7 @@
|
||||
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a
|
||||
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
|
||||
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
|
||||
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
|
||||
|
||||
#define USB_VENDOR_ID_HUION 0x256c
|
||||
#define USB_DEVICE_ID_HUION_TABLET 0x006e
|
||||
@ -1156,6 +1160,7 @@
|
||||
#define USB_VENDOR_ID_PRIMAX 0x0461
|
||||
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
|
||||
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
|
||||
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
|
||||
|
||||
|
||||
#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
|
||||
|
58
drivers/hid/hid-jabra.c
Normal file
58
drivers/hid/hid-jabra.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Jabra USB HID Driver
|
||||
*
|
||||
* Copyright (c) 2017 Niels Skou Olsen <nolsen@jabra.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
#define HID_UP_VENDOR_DEFINED_MIN 0xff000000
|
||||
#define HID_UP_VENDOR_DEFINED_MAX 0xffff0000
|
||||
|
||||
static int jabra_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
int is_vendor_defined =
|
||||
((usage->hid & HID_USAGE_PAGE) >= HID_UP_VENDOR_DEFINED_MIN &&
|
||||
(usage->hid & HID_USAGE_PAGE) <= HID_UP_VENDOR_DEFINED_MAX);
|
||||
|
||||
dbg_hid("hid=0x%08x appl=0x%08x coll_idx=0x%02x usage_idx=0x%02x: %s\n",
|
||||
usage->hid,
|
||||
field->application,
|
||||
usage->collection_index,
|
||||
usage->usage_index,
|
||||
is_vendor_defined ? "ignored" : "defaulted");
|
||||
|
||||
/* Ignore vendor defined usages, default map standard usages */
|
||||
return is_vendor_defined ? -1 : 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id jabra_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_JABRA, HID_ANY_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, jabra_devices);
|
||||
|
||||
static struct hid_driver jabra_driver = {
|
||||
.name = "jabra",
|
||||
.id_table = jabra_devices,
|
||||
.input_mapping = jabra_input_mapping,
|
||||
};
|
||||
module_hid_driver(jabra_driver);
|
||||
|
||||
MODULE_AUTHOR("Niels Skou Olsen <nolsen@jabra.com>");
|
||||
MODULE_DESCRIPTION("Jabra USB HID Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -85,11 +85,12 @@ MODULE_LICENSE("GPL");
|
||||
#define MT_IO_FLAGS_PENDING_SLOTS 2
|
||||
|
||||
struct mt_slot {
|
||||
__s32 x, y, cx, cy, p, w, h;
|
||||
__s32 x, y, cx, cy, p, w, h, a;
|
||||
__s32 contactid; /* the device ContactID assigned to this slot */
|
||||
bool touch_state; /* is the touch valid? */
|
||||
bool inrange_state; /* is the finger in proximity of the sensor? */
|
||||
bool confidence_state; /* is the touch made by a finger? */
|
||||
bool has_azimuth; /* the contact reports azimuth */
|
||||
};
|
||||
|
||||
struct mt_class {
|
||||
@ -119,6 +120,10 @@ struct mt_device {
|
||||
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
|
||||
int cc_index; /* contact count field index in the report */
|
||||
int cc_value_index; /* contact count value index in the field */
|
||||
int scantime_index; /* scantime field index in the report */
|
||||
int scantime_val_index; /* scantime value index in the field */
|
||||
int prev_scantime; /* scantime reported in the previous packet */
|
||||
int left_button_state; /* left button state */
|
||||
unsigned last_slot_field; /* the last field of a slot */
|
||||
unsigned mt_report_id; /* the report ID of the multitouch device */
|
||||
unsigned long initial_quirks; /* initial quirks state */
|
||||
@ -582,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
|
||||
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
||||
cls->sn_height);
|
||||
input_set_abs_params(hi->input,
|
||||
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
|
||||
/*
|
||||
* Only set ABS_MT_ORIENTATION if it is not
|
||||
* already set by the HID_DG_AZIMUTH usage.
|
||||
*/
|
||||
if (!test_bit(ABS_MT_ORIENTATION,
|
||||
hi->input->absbit))
|
||||
input_set_abs_params(hi->input,
|
||||
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||
}
|
||||
mt_store_field(usage, td, hi);
|
||||
return 1;
|
||||
@ -599,6 +611,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
EV_MSC, MSC_TIMESTAMP);
|
||||
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
|
||||
mt_store_field(usage, td, hi);
|
||||
/* Ignore if indexes are out of bounds. */
|
||||
if (field->index >= field->report->maxfield ||
|
||||
usage->usage_index >= field->report_count)
|
||||
return 1;
|
||||
td->scantime_index = field->index;
|
||||
td->scantime_val_index = usage->usage_index;
|
||||
return 1;
|
||||
case HID_DG_CONTACTCOUNT:
|
||||
/* Ignore if indexes are out of bounds. */
|
||||
@ -608,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
td->cc_index = field->index;
|
||||
td->cc_value_index = usage->usage_index;
|
||||
return 1;
|
||||
case HID_DG_AZIMUTH:
|
||||
hid_map_usage(hi, usage, bit, max,
|
||||
EV_ABS, ABS_MT_ORIENTATION);
|
||||
/*
|
||||
* Azimuth has the range of [0, MAX) representing a full
|
||||
* revolution. Set ABS_MT_ORIENTATION to a quarter of
|
||||
* MAX according the definition of ABS_MT_ORIENTATION
|
||||
*/
|
||||
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
|
||||
-field->logical_maximum / 4,
|
||||
field->logical_maximum / 4,
|
||||
cls->sn_move ?
|
||||
field->logical_maximum / cls->sn_move : 0, 0);
|
||||
mt_store_field(usage, td, hi);
|
||||
return 1;
|
||||
case HID_DG_CONTACTMAX:
|
||||
/* we don't set td->last_slot_field as contactcount and
|
||||
* contact max are global to the report */
|
||||
@ -700,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
||||
int wide = (s->w > s->h);
|
||||
int major = max(s->w, s->h);
|
||||
int minor = min(s->w, s->h);
|
||||
int orientation = wide;
|
||||
|
||||
if (s->has_azimuth)
|
||||
orientation = s->a;
|
||||
|
||||
/*
|
||||
* divided by two to match visual scale of touch
|
||||
@ -716,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
||||
input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
|
||||
input_event(input, EV_ABS, ABS_MT_DISTANCE,
|
||||
!s->touch_state);
|
||||
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
|
||||
input_event(input, EV_ABS, ABS_MT_ORIENTATION,
|
||||
orientation);
|
||||
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
|
||||
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
|
||||
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
|
||||
@ -734,10 +772,16 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
||||
*/
|
||||
static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
|
||||
{
|
||||
__s32 cls = td->mtclass.name;
|
||||
|
||||
if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL)
|
||||
input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
|
||||
|
||||
input_mt_sync_frame(input);
|
||||
input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
|
||||
input_sync(input);
|
||||
td->num_received = 0;
|
||||
td->left_button_state = 0;
|
||||
if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
|
||||
set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
|
||||
else
|
||||
@ -778,9 +822,11 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
|
||||
}
|
||||
|
||||
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
struct hid_usage *usage, __s32 value,
|
||||
bool first_packet)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
__s32 cls = td->mtclass.name;
|
||||
__s32 quirks = td->mtclass.quirks;
|
||||
struct input_dev *input = field->hidinput->input;
|
||||
|
||||
@ -832,11 +878,49 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
break;
|
||||
case HID_DG_CONTACTCOUNT:
|
||||
break;
|
||||
case HID_DG_AZIMUTH:
|
||||
/*
|
||||
* Azimuth is counter-clockwise and ranges from [0, MAX)
|
||||
* (a full revolution). Convert it to clockwise ranging
|
||||
* [-MAX/2, MAX/2].
|
||||
*
|
||||
* Note that ABS_MT_ORIENTATION require us to report
|
||||
* the limit of [-MAX/4, MAX/4], but the value can go
|
||||
* out of range to [-MAX/2, MAX/2] to report an upside
|
||||
* down ellipsis.
|
||||
*/
|
||||
if (value > field->logical_maximum / 2)
|
||||
value -= field->logical_maximum;
|
||||
td->curdata.a = -value;
|
||||
td->curdata.has_azimuth = true;
|
||||
break;
|
||||
case HID_DG_TOUCH:
|
||||
/* do nothing */
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* For Win8 PTP touchpads we should only look at
|
||||
* non finger/touch events in the first_packet of
|
||||
* a (possible) multi-packet frame.
|
||||
*/
|
||||
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
||||
!first_packet)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For Win8 PTP touchpads we map both the clickpad click
|
||||
* and any "external" left buttons to BTN_LEFT if a
|
||||
* device claims to have both we need to report 1 for
|
||||
* BTN_LEFT if either is pressed, so we or all values
|
||||
* together and report the result in mt_sync_frame().
|
||||
*/
|
||||
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
||||
usage->type == EV_KEY && usage->code == BTN_LEFT) {
|
||||
td->left_button_state |= value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (usage->type)
|
||||
input_event(input, usage->type, usage->code,
|
||||
value);
|
||||
@ -855,9 +939,11 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
__s32 cls = td->mtclass.name;
|
||||
struct hid_field *field;
|
||||
bool first_packet;
|
||||
unsigned count;
|
||||
int r, n;
|
||||
int r, n, scantime = 0;
|
||||
|
||||
/* sticky fingers release in progress, abort */
|
||||
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||
@ -867,13 +953,31 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
||||
* Includes multi-packet support where subsequent
|
||||
* packets are sent with zero contactcount.
|
||||
*/
|
||||
if (td->scantime_index >= 0) {
|
||||
field = report->field[td->scantime_index];
|
||||
scantime = field->value[td->scantime_val_index];
|
||||
}
|
||||
if (td->cc_index >= 0) {
|
||||
struct hid_field *field = report->field[td->cc_index];
|
||||
int value = field->value[td->cc_value_index];
|
||||
if (value)
|
||||
|
||||
/*
|
||||
* For Win8 PTPs the first packet (td->num_received == 0) may
|
||||
* have a contactcount of 0 if there only is a button event.
|
||||
* We double check that this is not a continuation packet
|
||||
* of a possible multi-packet frame be checking that the
|
||||
* timestamp has changed.
|
||||
*/
|
||||
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
||||
td->num_received == 0 && td->prev_scantime != scantime)
|
||||
td->num_expected = value;
|
||||
/* A non 0 contact count always indicates a first packet */
|
||||
else if (value)
|
||||
td->num_expected = value;
|
||||
}
|
||||
td->prev_scantime = scantime;
|
||||
|
||||
first_packet = td->num_received == 0;
|
||||
for (r = 0; r < report->maxfield; r++) {
|
||||
field = report->field[r];
|
||||
count = field->report_count;
|
||||
@ -883,7 +987,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
||||
|
||||
for (n = 0; n < count; n++)
|
||||
mt_process_mt_event(hid, field, &field->usage[n],
|
||||
field->value[n]);
|
||||
field->value[n], first_packet);
|
||||
}
|
||||
|
||||
if (td->num_received >= td->num_expected)
|
||||
@ -1329,6 +1433,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
td->maxcontact_report_id = -1;
|
||||
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
|
||||
td->cc_index = -1;
|
||||
td->scantime_index = -1;
|
||||
td->mt_report_id = -1;
|
||||
hid_set_drvdata(hdev, td);
|
||||
|
||||
@ -1649,14 +1754,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
|
||||
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
|
||||
|
||||
/* Panasonic panels */
|
||||
{ .driver_data = MT_CLS_PANASONIC,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
||||
USB_DEVICE_ID_PANABOARD_UBT780) },
|
||||
{ .driver_data = MT_CLS_PANASONIC,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
||||
USB_DEVICE_ID_PANABOARD_UBT880) },
|
||||
|
||||
/* Novatek Panel */
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
|
||||
@ -1667,6 +1764,14 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_NTRIG, 0x1b05) },
|
||||
|
||||
/* Panasonic panels */
|
||||
{ .driver_data = MT_CLS_PANASONIC,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
||||
USB_DEVICE_ID_PANABOARD_UBT780) },
|
||||
{ .driver_data = MT_CLS_PANASONIC,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
||||
USB_DEVICE_ID_PANABOARD_UBT880) },
|
||||
|
||||
/* PixArt optical touch screen */
|
||||
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
|
||||
|
1276
drivers/hid/hid-quirks.c
Normal file
1276
drivers/hid/hid-quirks.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -731,6 +731,7 @@ static const struct hid_device_id rmi_id[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14),
|
||||
.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_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
|
||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
|
||||
{ }
|
||||
};
|
||||
|
@ -37,6 +37,8 @@ static uint kovaplus_convert_event_cpi(uint value)
|
||||
static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
|
||||
uint new_profile_index)
|
||||
{
|
||||
if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings))
|
||||
return;
|
||||
kovaplus->actual_profile = new_profile_index;
|
||||
kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
|
||||
kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
|
||||
|
@ -473,6 +473,7 @@ struct motion_output_report_02 {
|
||||
#define DS4_FEATURE_REPORT_0x02_SIZE 37
|
||||
#define DS4_FEATURE_REPORT_0x05_SIZE 41
|
||||
#define DS4_FEATURE_REPORT_0x81_SIZE 7
|
||||
#define DS4_FEATURE_REPORT_0xA3_SIZE 49
|
||||
#define DS4_INPUT_REPORT_0x11_SIZE 78
|
||||
#define DS4_OUTPUT_REPORT_0x05_SIZE 32
|
||||
#define DS4_OUTPUT_REPORT_0x11_SIZE 78
|
||||
@ -544,6 +545,8 @@ struct sony_sc {
|
||||
struct power_supply *battery;
|
||||
struct power_supply_desc battery_desc;
|
||||
int device_id;
|
||||
unsigned fw_version;
|
||||
unsigned hw_version;
|
||||
u8 *output_report_dmabuf;
|
||||
|
||||
#ifdef CONFIG_SONY_FF
|
||||
@ -627,6 +630,29 @@ static ssize_t ds4_store_poll_interval(struct device *dev,
|
||||
static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval,
|
||||
ds4_store_poll_interval);
|
||||
|
||||
static ssize_t sony_show_firmware_version(struct device *dev,
|
||||
struct device_attribute
|
||||
*attr, char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->fw_version);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(firmware_version, 0444, sony_show_firmware_version, NULL);
|
||||
|
||||
static ssize_t sony_show_hardware_version(struct device *dev,
|
||||
struct device_attribute
|
||||
*attr, char *buf)
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->hw_version);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(hardware_version, 0444, sony_show_hardware_version, NULL);
|
||||
|
||||
static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
@ -1646,6 +1672,31 @@ static void dualshock4_calibration_work(struct work_struct *work)
|
||||
spin_unlock_irqrestore(&sc->lock, flags);
|
||||
}
|
||||
|
||||
static int dualshock4_get_version_info(struct sony_sc *sc)
|
||||
{
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmalloc(DS4_FEATURE_REPORT_0xA3_SIZE, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_hw_raw_request(sc->hdev, 0xA3, buf,
|
||||
DS4_FEATURE_REPORT_0xA3_SIZE,
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
if (ret < 0) {
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sc->hw_version = get_unaligned_le16(&buf[35]);
|
||||
sc->fw_version = get_unaligned_le16(&buf[41]);
|
||||
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sixaxis_set_leds_from_id(struct sony_sc *sc)
|
||||
{
|
||||
static const u8 sixaxis_leds[10][4] = {
|
||||
@ -2399,10 +2450,7 @@ static int sony_check_add(struct sony_sc *sc)
|
||||
memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address));
|
||||
|
||||
snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq),
|
||||
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
sc->mac_address[5], sc->mac_address[4],
|
||||
sc->mac_address[3], sc->mac_address[2],
|
||||
sc->mac_address[1], sc->mac_address[0]);
|
||||
"%pMR", sc->mac_address);
|
||||
} else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
|
||||
(sc->quirks & NAVIGATION_CONTROLLER_USB)) {
|
||||
buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL);
|
||||
@ -2432,10 +2480,7 @@ static int sony_check_add(struct sony_sc *sc)
|
||||
sc->mac_address[5-n] = buf[4+n];
|
||||
|
||||
snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq),
|
||||
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||
sc->mac_address[5], sc->mac_address[4],
|
||||
sc->mac_address[3], sc->mac_address[2],
|
||||
sc->mac_address[1], sc->mac_address[0]);
|
||||
"%pMR", sc->mac_address);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -2619,6 +2664,28 @@ static int sony_input_configured(struct hid_device *hdev,
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
ret = dualshock4_get_version_info(sc);
|
||||
if (ret < 0) {
|
||||
hid_err(sc->hdev, "Failed to get version data from Dualshock 4\n");
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
if (ret) {
|
||||
/* Make zero for cleanup reasons of sysfs entries. */
|
||||
sc->fw_version = 0;
|
||||
sc->hw_version = 0;
|
||||
hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret);
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
if (ret) {
|
||||
sc->hw_version = 0;
|
||||
hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret);
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Dualshock 4 touchpad supports 2 touches and has a
|
||||
* resolution of 1920x942 (44.86 dots/mm).
|
||||
@ -2695,6 +2762,10 @@ err_stop:
|
||||
*/
|
||||
if (sc->ds4_bt_poll_interval)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
|
||||
if (sc->fw_version)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
if (sc->hw_version)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
if (sc->quirks & SONY_LED_SUPPORT)
|
||||
sony_leds_remove(sc);
|
||||
if (sc->quirks & SONY_BATTERY_SUPPORT)
|
||||
@ -2796,6 +2867,12 @@ static void sony_remove(struct hid_device *hdev)
|
||||
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
|
||||
|
||||
if (sc->fw_version)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
|
||||
|
||||
if (sc->hw_version)
|
||||
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
|
||||
|
||||
sony_cancel_work_sync(sc);
|
||||
|
||||
kfree(sc->output_report_dmabuf);
|
||||
|
@ -934,11 +934,6 @@ static int i2c_hid_of_probe(struct i2c_client *client,
|
||||
}
|
||||
pdata->hid_descriptor_address = val;
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "post-power-on-delay-ms",
|
||||
&val);
|
||||
if (!ret)
|
||||
pdata->post_power_delay_ms = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -955,6 +950,16 @@ static inline int i2c_hid_of_probe(struct i2c_client *client,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void i2c_hid_fwnode_probe(struct i2c_client *client,
|
||||
struct i2c_hid_platform_data *pdata)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!device_property_read_u32(&client->dev, "post-power-on-delay-ms",
|
||||
&val))
|
||||
pdata->post_power_delay_ms = val;
|
||||
}
|
||||
|
||||
static int i2c_hid_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
@ -998,6 +1003,9 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
ihid->pdata = *platform_data;
|
||||
}
|
||||
|
||||
/* Parse platform agnostic common properties from ACPI / device tree */
|
||||
i2c_hid_fwnode_probe(client, &ihid->pdata);
|
||||
|
||||
ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(ihid->pdata.supply)) {
|
||||
ret = PTR_ERR(ihid->pdata.supply);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define SPT_Ax_DEVICE_ID 0x9D35
|
||||
#define CNL_Ax_DEVICE_ID 0x9DFC
|
||||
#define GLK_Ax_DEVICE_ID 0x31A2
|
||||
#define CNL_H_DEVICE_ID 0xA37C
|
||||
|
||||
#define REVISION_ID_CHT_A0 0x6
|
||||
#define REVISION_ID_CHT_Ax_SI 0x0
|
||||
|
@ -37,6 +37,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)},
|
||||
{0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Makefile for the USB input drivers
|
||||
#
|
||||
|
||||
usbhid-y := hid-core.o hid-quirks.o
|
||||
usbhid-y := hid-core.o
|
||||
usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o
|
||||
usbhid-$(CONFIG_HID_PID) += hid-pidff.o
|
||||
|
||||
|
@ -978,8 +978,7 @@ static int usbhid_parse(struct hid_device *hid)
|
||||
int num_descriptors;
|
||||
size_t offset = offsetof(struct hid_descriptor, desc);
|
||||
|
||||
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
|
||||
le16_to_cpu(dev->descriptor.idProduct));
|
||||
quirks = hid_lookup_quirk(hid);
|
||||
|
||||
if (quirks & HID_QUIRK_IGNORE)
|
||||
return -ENODEV;
|
||||
@ -1328,8 +1327,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
hid->bus = BUS_USB;
|
||||
hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
|
||||
hid->product = le16_to_cpu(dev->descriptor.idProduct);
|
||||
hid->version = le16_to_cpu(dev->descriptor.bcdDevice);
|
||||
hid->name[0] = 0;
|
||||
hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol ==
|
||||
USB_INTERFACE_PROTOCOL_MOUSE)
|
||||
hid->type = HID_TYPE_USBMOUSE;
|
||||
@ -1641,7 +1640,7 @@ static int __init hid_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
retval = usbhid_quirks_init(quirks_param);
|
||||
retval = hid_quirks_init(quirks_param, BUS_USB, MAX_USBHID_BOOT_QUIRKS);
|
||||
if (retval)
|
||||
goto usbhid_quirks_init_fail;
|
||||
retval = usb_register(&hid_driver);
|
||||
@ -1651,7 +1650,7 @@ static int __init hid_init(void)
|
||||
|
||||
return 0;
|
||||
usb_register_fail:
|
||||
usbhid_quirks_exit();
|
||||
hid_quirks_exit(BUS_USB);
|
||||
usbhid_quirks_init_fail:
|
||||
return retval;
|
||||
}
|
||||
@ -1659,7 +1658,7 @@ usbhid_quirks_init_fail:
|
||||
static void __exit hid_exit(void)
|
||||
{
|
||||
usb_deregister(&hid_driver);
|
||||
usbhid_quirks_exit();
|
||||
hid_quirks_exit(BUS_USB);
|
||||
}
|
||||
|
||||
module_init(hid_init);
|
||||
|
@ -1,402 +0,0 @@
|
||||
/*
|
||||
* USB HID quirks support for Linux
|
||||
*
|
||||
* Copyright (c) 1999 Andreas Gal
|
||||
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
|
||||
* Copyright (c) 2006-2007 Jiri Kosina
|
||||
* Copyright (c) 2007 Paul Walmsley
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../hid-ids.h"
|
||||
|
||||
/*
|
||||
* Alphabetically sorted blacklist by quirk type.
|
||||
*/
|
||||
|
||||
static const struct hid_blacklist {
|
||||
__u16 idVendor;
|
||||
__u16 idProduct;
|
||||
__u32 quirks;
|
||||
} hid_blacklist[] = {
|
||||
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN, HID_QUIRK_MULTI_INPUT},
|
||||
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
|
||||
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
|
||||
|
||||
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
|
||||
|
||||
{ USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
|
||||
{ USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS1758, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB, HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22, HID_QUIRK_ALWAYS_POLL },
|
||||
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
|
||||
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
|
||||
|
||||
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_REPORTS },
|
||||
{ USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT },
|
||||
{ USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK, HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
/* Dynamic HID quirks list - specified at runtime */
|
||||
struct quirks_list_struct {
|
||||
struct hid_blacklist hid_bl_item;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static LIST_HEAD(dquirks_list);
|
||||
static DECLARE_RWSEM(dquirks_rwsem);
|
||||
|
||||
/* Runtime ("dynamic") quirks manipulation functions */
|
||||
|
||||
/**
|
||||
* usbhid_exists_dquirk: find any dynamic quirks for a USB HID device
|
||||
* @idVendor: the 16-bit USB vendor ID, in native byteorder
|
||||
* @idProduct: the 16-bit USB product ID, in native byteorder
|
||||
*
|
||||
* Description:
|
||||
* Scans dquirks_list for a matching dynamic quirk and returns
|
||||
* the pointer to the relevant struct hid_blacklist if found.
|
||||
* Must be called with a read lock held on dquirks_rwsem.
|
||||
*
|
||||
* Returns: NULL if no quirk found, struct hid_blacklist * if found.
|
||||
*/
|
||||
static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
|
||||
const u16 idProduct)
|
||||
{
|
||||
struct quirks_list_struct *q;
|
||||
struct hid_blacklist *bl_entry = NULL;
|
||||
|
||||
list_for_each_entry(q, &dquirks_list, node) {
|
||||
if (q->hid_bl_item.idVendor == idVendor &&
|
||||
q->hid_bl_item.idProduct == idProduct) {
|
||||
bl_entry = &q->hid_bl_item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bl_entry != NULL)
|
||||
dbg_hid("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
|
||||
bl_entry->quirks, bl_entry->idVendor,
|
||||
bl_entry->idProduct);
|
||||
|
||||
return bl_entry;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* usbhid_modify_dquirk: add/replace a HID quirk
|
||||
* @idVendor: the 16-bit USB vendor ID, in native byteorder
|
||||
* @idProduct: the 16-bit USB product ID, in native byteorder
|
||||
* @quirks: the u32 quirks value to add/replace
|
||||
*
|
||||
* Description:
|
||||
* If an dynamic quirk exists in memory for this (idVendor,
|
||||
* idProduct) pair, replace its quirks value with what was
|
||||
* provided. Otherwise, add the quirk to the dynamic quirks list.
|
||||
*
|
||||
* Returns: 0 OK, -error on failure.
|
||||
*/
|
||||
static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
|
||||
const u32 quirks)
|
||||
{
|
||||
struct quirks_list_struct *q_new, *q;
|
||||
int list_edited = 0;
|
||||
|
||||
if (!idVendor) {
|
||||
dbg_hid("Cannot add a quirk with idVendor = 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
|
||||
if (!q_new)
|
||||
return -ENOMEM;
|
||||
|
||||
q_new->hid_bl_item.idVendor = idVendor;
|
||||
q_new->hid_bl_item.idProduct = idProduct;
|
||||
q_new->hid_bl_item.quirks = quirks;
|
||||
|
||||
down_write(&dquirks_rwsem);
|
||||
|
||||
list_for_each_entry(q, &dquirks_list, node) {
|
||||
|
||||
if (q->hid_bl_item.idVendor == idVendor &&
|
||||
q->hid_bl_item.idProduct == idProduct) {
|
||||
|
||||
list_replace(&q->node, &q_new->node);
|
||||
kfree(q);
|
||||
list_edited = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!list_edited)
|
||||
list_add_tail(&q_new->node, &dquirks_list);
|
||||
|
||||
up_write(&dquirks_rwsem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* usbhid_remove_all_dquirks: remove all runtime HID quirks from memory
|
||||
*
|
||||
* Description:
|
||||
* Free all memory associated with dynamic quirks - called before
|
||||
* module unload.
|
||||
*
|
||||
*/
|
||||
static void usbhid_remove_all_dquirks(void)
|
||||
{
|
||||
struct quirks_list_struct *q, *temp;
|
||||
|
||||
down_write(&dquirks_rwsem);
|
||||
list_for_each_entry_safe(q, temp, &dquirks_list, node) {
|
||||
list_del(&q->node);
|
||||
kfree(q);
|
||||
}
|
||||
up_write(&dquirks_rwsem);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* usbhid_quirks_init: apply USB HID quirks specified at module load time
|
||||
*/
|
||||
int usbhid_quirks_init(char **quirks_param)
|
||||
{
|
||||
u16 idVendor, idProduct;
|
||||
u32 quirks;
|
||||
int n = 0, m;
|
||||
|
||||
for (; n < MAX_USBHID_BOOT_QUIRKS && quirks_param[n]; n++) {
|
||||
|
||||
m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
|
||||
&idVendor, &idProduct, &quirks);
|
||||
|
||||
if (m != 3 ||
|
||||
usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
|
||||
pr_warn("Could not parse HID quirk module param %s\n",
|
||||
quirks_param[n]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* usbhid_quirks_exit: release memory associated with dynamic_quirks
|
||||
*
|
||||
* Description:
|
||||
* Release all memory associated with dynamic quirks. Called upon
|
||||
* module unload.
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
void usbhid_quirks_exit(void)
|
||||
{
|
||||
usbhid_remove_all_dquirks();
|
||||
}
|
||||
|
||||
/**
|
||||
* usbhid_exists_squirk: return any static quirks for a USB HID device
|
||||
* @idVendor: the 16-bit USB vendor ID, in native byteorder
|
||||
* @idProduct: the 16-bit USB product ID, in native byteorder
|
||||
*
|
||||
* Description:
|
||||
* Given a USB vendor ID and product ID, return a pointer to
|
||||
* the hid_blacklist entry associated with that device.
|
||||
*
|
||||
* Returns: pointer if quirk found, or NULL if no quirks found.
|
||||
*/
|
||||
static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
|
||||
const u16 idProduct)
|
||||
{
|
||||
const struct hid_blacklist *bl_entry = NULL;
|
||||
int n = 0;
|
||||
|
||||
for (; hid_blacklist[n].idVendor; n++)
|
||||
if (hid_blacklist[n].idVendor == idVendor &&
|
||||
(hid_blacklist[n].idProduct == (__u16) HID_ANY_ID ||
|
||||
hid_blacklist[n].idProduct == idProduct))
|
||||
bl_entry = &hid_blacklist[n];
|
||||
|
||||
if (bl_entry != NULL)
|
||||
dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
|
||||
bl_entry->quirks, bl_entry->idVendor,
|
||||
bl_entry->idProduct);
|
||||
return bl_entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* usbhid_lookup_quirk: return any quirks associated with a USB HID device
|
||||
* @idVendor: the 16-bit USB vendor ID, in native byteorder
|
||||
* @idProduct: the 16-bit USB product ID, in native byteorder
|
||||
*
|
||||
* Description:
|
||||
* Given a USB vendor ID and product ID, return any quirks associated
|
||||
* with that device.
|
||||
*
|
||||
* Returns: a u32 quirks value.
|
||||
*/
|
||||
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
|
||||
{
|
||||
u32 quirks = 0;
|
||||
const struct hid_blacklist *bl_entry = NULL;
|
||||
|
||||
/* NCR devices must not be queried for reports */
|
||||
if (idVendor == USB_VENDOR_ID_NCR &&
|
||||
idProduct >= USB_DEVICE_ID_NCR_FIRST &&
|
||||
idProduct <= USB_DEVICE_ID_NCR_LAST)
|
||||
return HID_QUIRK_NO_INIT_REPORTS;
|
||||
|
||||
down_read(&dquirks_rwsem);
|
||||
bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
|
||||
if (!bl_entry)
|
||||
bl_entry = usbhid_exists_squirk(idVendor, idProduct);
|
||||
if (bl_entry)
|
||||
quirks = bl_entry->quirks;
|
||||
up_read(&dquirks_rwsem);
|
||||
|
||||
return quirks;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
|
@ -56,6 +56,107 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf,
|
||||
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,
|
||||
u8 *raw_data, int size)
|
||||
{
|
||||
@ -64,6 +165,9 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
if (size > WACOM_PKGLEN_MAX)
|
||||
return 1;
|
||||
|
||||
if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size))
|
||||
return -1;
|
||||
|
||||
memcpy(wacom->wacom_wac.data, raw_data, size);
|
||||
|
||||
wacom_wac_irq(&wacom->wacom_wac, size);
|
||||
@ -2347,23 +2451,23 @@ static void wacom_remote_destroy_one(struct wacom *wacom, unsigned int index)
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
remote->remotes[index].registered = false;
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
|
||||
if (remote->remotes[index].battery.battery)
|
||||
devres_release_group(&wacom->hdev->dev,
|
||||
&remote->remotes[index].battery.bat_desc);
|
||||
|
||||
if (remote->remotes[index].group.name)
|
||||
devres_release_group(&wacom->hdev->dev,
|
||||
&remote->remotes[index]);
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
if (remote->remotes[i].serial == serial) {
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
remote->remotes[i].registered = false;
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
|
||||
if (remote->remotes[i].battery.battery)
|
||||
devres_release_group(&wacom->hdev->dev,
|
||||
&remote->remotes[i].battery.bat_desc);
|
||||
|
||||
if (remote->remotes[i].group.name)
|
||||
devres_release_group(&wacom->hdev->dev,
|
||||
&remote->remotes[i]);
|
||||
|
||||
remote->remotes[i].serial = 0;
|
||||
remote->remotes[i].group.name = NULL;
|
||||
remote->remotes[i].registered = false;
|
||||
remote->remotes[i].battery.battery = NULL;
|
||||
wacom->led.groups[i].select = WACOM_STATUS_UNKNOWN;
|
||||
}
|
||||
@ -2580,6 +2684,10 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
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->mode_report = -1;
|
||||
|
||||
@ -2643,6 +2751,8 @@ static void wacom_remove(struct hid_device *hdev)
|
||||
if (wacom->wacom_wac.features.type != REMOTE)
|
||||
wacom_release_resources(wacom);
|
||||
|
||||
kfifo_free(&wacom_wac->pen_fifo);
|
||||
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
||||
int i;
|
||||
bool is_touch_on = value;
|
||||
bool do_report = false;
|
||||
|
||||
/*
|
||||
@ -1969,16 +1968,17 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
||||
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) {
|
||||
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,
|
||||
SW_MUTE_DEVICE, !is_touch_on);
|
||||
SW_MUTE_DEVICE, !(*is_touch_on));
|
||||
input_sync(wacom_wac->shared->touch_input);
|
||||
}
|
||||
break;
|
||||
@ -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);
|
||||
break;
|
||||
case HID_DG_TOOLSERIALNUMBER:
|
||||
features->quirks |= WACOM_QUIRK_TOOLSERIAL;
|
||||
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;
|
||||
case WACOM_HID_WD_SENSE:
|
||||
features->quirks |= WACOM_QUIRK_SENSE;
|
||||
@ -2093,15 +2115,18 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
|
||||
break;
|
||||
case WACOM_HID_WD_SERIALHI:
|
||||
wacom_map_usage(input, usage, field, EV_ABS, ABS_MISC, 0);
|
||||
set_bit(EV_KEY, input->evbit);
|
||||
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_BRUSH);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
||||
if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
|
||||
|
||||
if (!(features->quirks & WACOM_QUIRK_AESPEN)) {
|
||||
set_bit(EV_KEY, input->evbit);
|
||||
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_BRUSH);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_PENCIL);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_AIRBRUSH);
|
||||
if (!(features->device_type & WACOM_DEVICETYPE_DIRECT)) {
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_MOUSE);
|
||||
input_set_capability(input, EV_KEY, BTN_TOOL_LENS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WACOM_HID_WD_FINGERWHEEL:
|
||||
@ -4390,6 +4415,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_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 =
|
||||
{ "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID };
|
||||
@ -4558,6 +4589,8 @@ const struct hid_device_id wacom_ids[] = {
|
||||
{ USB_DEVICE_WACOM(0x343) },
|
||||
{ BT_DEVICE_WACOM(0x360) },
|
||||
{ BT_DEVICE_WACOM(0x361) },
|
||||
{ USB_DEVICE_WACOM(0x37A) },
|
||||
{ USB_DEVICE_WACOM(0x37B) },
|
||||
{ USB_DEVICE_WACOM(0x4001) },
|
||||
{ USB_DEVICE_WACOM(0x4004) },
|
||||
{ USB_DEVICE_WACOM(0x5000) },
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
/* maximum packet length for USB/BT devices */
|
||||
#define WACOM_PKGLEN_MAX 361
|
||||
@ -86,7 +87,9 @@
|
||||
/* device quirks */
|
||||
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
|
||||
#define WACOM_QUIRK_SENSE 0x0002
|
||||
#define WACOM_QUIRK_AESPEN 0x0004
|
||||
#define WACOM_QUIRK_BATTERY 0x0008
|
||||
#define WACOM_QUIRK_TOOLSERIAL 0x0010
|
||||
|
||||
/* device types */
|
||||
#define WACOM_DEVICETYPE_NONE 0x0000
|
||||
@ -107,6 +110,7 @@
|
||||
#define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02)
|
||||
#define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36)
|
||||
#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_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
|
||||
#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
|
||||
@ -150,6 +154,7 @@
|
||||
#define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04)
|
||||
#define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05)
|
||||
#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_Y (WACOM_HID_UP_WACOMTOUCH | 0x131)
|
||||
|
||||
@ -336,6 +341,7 @@ struct wacom_wac {
|
||||
struct input_dev *pen_input;
|
||||
struct input_dev *touch_input;
|
||||
struct input_dev *pad_input;
|
||||
struct kfifo_rec_ptr_2 pen_fifo;
|
||||
int pid;
|
||||
int num_contacts_left;
|
||||
u8 bt_features;
|
||||
|
@ -281,6 +281,7 @@ struct hid_item {
|
||||
|
||||
#define HID_DG_DEVICECONFIG 0x000d000e
|
||||
#define HID_DG_DEVICESETTINGS 0x000d0023
|
||||
#define HID_DG_AZIMUTH 0x000d003f
|
||||
#define HID_DG_CONFIDENCE 0x000d0047
|
||||
#define HID_DG_WIDTH 0x000d0048
|
||||
#define HID_DG_HEIGHT 0x000d0049
|
||||
@ -342,6 +343,7 @@ struct hid_item {
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
|
||||
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000
|
||||
#define HID_QUIRK_HAVE_SPECIAL_DRIVER 0x00080000
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
|
||||
#define HID_QUIRK_NO_IGNORE 0x40000000
|
||||
@ -671,6 +673,7 @@ struct hid_usage_id {
|
||||
* to be called)
|
||||
* @dyn_list: list of dynamically added device ids
|
||||
* @dyn_lock: lock protecting @dyn_list
|
||||
* @match: check if the given device is handled by this driver
|
||||
* @probe: new device inserted
|
||||
* @remove: device removed (NULL if not a hot-plug capable driver)
|
||||
* @report_table: on which reports to call raw_event (NULL means all)
|
||||
@ -683,6 +686,8 @@ struct hid_usage_id {
|
||||
* @input_mapped: invoked on input registering after mapping an usage
|
||||
* @input_configured: invoked just before the device is registered
|
||||
* @feature_mapping: invoked on feature registering
|
||||
* @bus_add_driver: invoked when a HID driver is about to be added
|
||||
* @bus_removed_driver: invoked when a HID driver has been removed
|
||||
* @suspend: invoked on suspend (NULL means nop)
|
||||
* @resume: invoked on resume if device was not reset (NULL means nop)
|
||||
* @reset_resume: invoked on resume if device was reset (NULL means nop)
|
||||
@ -711,6 +716,7 @@ struct hid_driver {
|
||||
struct list_head dyn_list;
|
||||
spinlock_t dyn_lock;
|
||||
|
||||
bool (*match)(struct hid_device *dev, bool ignore_special_driver);
|
||||
int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
|
||||
void (*remove)(struct hid_device *dev);
|
||||
|
||||
@ -736,6 +742,8 @@ struct hid_driver {
|
||||
void (*feature_mapping)(struct hid_device *hdev,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage);
|
||||
void (*bus_add_driver)(struct hid_driver *driver);
|
||||
void (*bus_removed_driver)(struct hid_driver *driver);
|
||||
#ifdef CONFIG_PM
|
||||
int (*suspend)(struct hid_device *hdev, pm_message_t message);
|
||||
int (*resume)(struct hid_device *hdev);
|
||||
@ -814,6 +822,8 @@ extern bool hid_ignore(struct hid_device *);
|
||||
extern int hid_add_device(struct hid_device *);
|
||||
extern void hid_destroy_device(struct hid_device *);
|
||||
|
||||
extern struct bus_type hid_bus_type;
|
||||
|
||||
extern int __must_check __hid_register_driver(struct hid_driver *,
|
||||
struct module *, const char *mod_name);
|
||||
|
||||
@ -860,8 +870,12 @@ int hid_open_report(struct hid_device *device);
|
||||
int hid_check_keys_pressed(struct hid_device *hid);
|
||||
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
|
||||
void hid_disconnect(struct hid_device *hid);
|
||||
const struct hid_device_id *hid_match_id(struct hid_device *hdev,
|
||||
bool hid_match_one_id(const struct hid_device *hdev,
|
||||
const struct hid_device_id *id);
|
||||
const struct hid_device_id *hid_match_id(const struct hid_device *hdev,
|
||||
const struct hid_device_id *id);
|
||||
const struct hid_device_id *hid_match_device(struct hid_device *hdev,
|
||||
struct hid_driver *hdrv);
|
||||
s32 hid_snto32(__u32 value, unsigned n);
|
||||
__u32 hid_field_extract(const struct hid_device *hid, __u8 *report,
|
||||
unsigned offset, unsigned n);
|
||||
@ -1098,9 +1112,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int interrupt);
|
||||
|
||||
/* HID quirks API */
|
||||
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
|
||||
int usbhid_quirks_init(char **quirks_param);
|
||||
void usbhid_quirks_exit(void);
|
||||
unsigned long hid_lookup_quirk(const struct hid_device *hdev);
|
||||
int hid_quirks_init(char **quirks_param, __u16 bus, int count);
|
||||
void hid_quirks_exit(__u16 bus);
|
||||
|
||||
#ifdef CONFIG_HID_PID
|
||||
int hid_pidff_init(struct hid_device *hid);
|
||||
|
@ -789,7 +789,7 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
hid->dev.parent = &session->conn->hcon->dev;
|
||||
hid->ll_driver = &hidp_hid_driver;
|
||||
|
||||
/* True if device is blacklisted in drivers/hid/hid-core.c */
|
||||
/* True if device is blacklisted in drivers/hid/hid-quirks.c */
|
||||
if (hid_ignore(hid)) {
|
||||
hid_destroy_device(session->hid);
|
||||
session->hid = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user