Commit c6400e5c 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 updates from Jiri Kosina:

 - support for Pro Pen slim, from Jason Gerecke

 - power management improvements to Intel-ISH driver, from Song Hongyan

 - UCLogic driver revamp in order to be able to support wider range of
   Huion tablets, from Nikolai Kondrashov

 - Asus Transbook support, from NOGUCHI Hiroshi

 - other assorted small bugfixes / cleanups and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (46 commits)
  HID: Remove Waltop tablets from hid_have_special_driver
  HID: Remove KYE tablets from hid_have_special_driver
  HID: Remove hid-uclogic entries from hid_have_special_driver
  HID: uclogic: Do not initialize non-USB devices
  HID: uclogic: Add support for Ugee G5
  HID: uclogic: Support Gray-coded rotary encoders
  HID: uclogic: Support faking Wacom pad device ID
  HID: uclogic: Add support for XP-Pen Deco 01
  HID: uclogic: Add support for XP-Pen Star G640
  HID: uclogic: Add support for XP-Pen Star G540
  HID: uclogic: Add support for Ugee EX07S frame controls
  HID: uclogic: Add support for Ugee M540
  HID: uclogic: Add support for Ugee 2150
  HID: uclogic: Support v2 protocol
  HID: uclogic: Support fragmented high-res reports
  HID: uclogic: Support in-range reporting emulation
  HID: uclogic: Designate current protocol v1
  HID: uclogic: Re-initialize tablets on resume
  HID: uclogic: Extract tablet parameter discovery into a module
  HID: uclogic: Extract report descriptors to a module
  ...
parents b7af27bf 49374f00
...@@ -412,6 +412,12 @@ config HID_WALTOP ...@@ -412,6 +412,12 @@ config HID_WALTOP
---help--- ---help---
Support for Waltop tablets. Support for Waltop tablets.
config HID_VIEWSONIC
tristate "ViewSonic/Signotec"
depends on HID
help
Support for ViewSonic/Signotec PD1011 signature pad.
config HID_GYRATION config HID_GYRATION
tristate "Gyration remote control" tristate "Gyration remote control"
depends on HID depends on HID
...@@ -590,6 +596,13 @@ config HID_MAGICMOUSE ...@@ -590,6 +596,13 @@ config HID_MAGICMOUSE
Say Y here if you want support for the multi-touch features of the Say Y here if you want support for the multi-touch features of the
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
config HID_MALTRON
tristate "Maltron L90 keyboard"
depends on HID
---help---
Adds support for the volume up, volume down, mute, and play/pause buttons
of the Maltron L90 keyboard.
config HID_MAYFLASH config HID_MAYFLASH
tristate "Mayflash game controller adapter force feedback" tristate "Mayflash game controller adapter force feedback"
depends on HID depends on HID
......
...@@ -66,6 +66,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o ...@@ -66,6 +66,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
...@@ -108,12 +109,16 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o ...@@ -108,12 +109,16 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TIVO) += hid-tivo.o obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
hid-uclogic-objs := hid-uclogic-core.o \
hid-uclogic-rdesc.o \
hid-uclogic-params.o
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o
obj-$(CONFIG_HID_LED) += hid-led.o obj-$(CONFIG_HID_LED) += hid-led.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
obj-$(CONFIG_HID_VIEWSONIC) += hid-viewsonic.o
wacom-objs := wacom_wac.o wacom_sys.o wacom-objs := wacom_wac.o wacom_sys.o
obj-$(CONFIG_HID_WACOM) += wacom.o obj-$(CONFIG_HID_WACOM) += wacom.o
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/platform_data/x86/asus-wmi.h> #include <linux/platform_data/x86/asus-wmi.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */ #include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
#include <linux/power_supply.h>
#include "hid-ids.h" #include "hid-ids.h"
...@@ -61,6 +62,13 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); ...@@ -61,6 +62,13 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define CONTACT_TOUCH_MAJOR_MASK 0x07 #define CONTACT_TOUCH_MAJOR_MASK 0x07
#define CONTACT_PRESSURE_MASK 0x7f #define CONTACT_PRESSURE_MASK 0x7f
#define BATTERY_REPORT_ID (0x03)
#define BATTERY_REPORT_SIZE (1 + 8)
#define BATTERY_LEVEL_MAX ((u8)255)
#define BATTERY_STAT_DISCONNECT (0)
#define BATTERY_STAT_CHARGING (1)
#define BATTERY_STAT_FULL (2)
#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0) #define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
#define QUIRK_NO_INIT_REPORTS BIT(1) #define QUIRK_NO_INIT_REPORTS BIT(1)
#define QUIRK_SKIP_INPUT_MAPPING BIT(2) #define QUIRK_SKIP_INPUT_MAPPING BIT(2)
...@@ -71,6 +79,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); ...@@ -71,6 +79,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define QUIRK_T100CHI BIT(7) #define QUIRK_T100CHI BIT(7)
#define QUIRK_G752_KEYBOARD BIT(8) #define QUIRK_G752_KEYBOARD BIT(8)
#define QUIRK_T101HA_DOCK BIT(9) #define QUIRK_T101HA_DOCK BIT(9)
#define QUIRK_T90CHI BIT(10)
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
QUIRK_NO_INIT_REPORTS | \ QUIRK_NO_INIT_REPORTS | \
...@@ -100,12 +109,21 @@ struct asus_touchpad_info { ...@@ -100,12 +109,21 @@ struct asus_touchpad_info {
struct asus_drvdata { struct asus_drvdata {
unsigned long quirks; unsigned long quirks;
struct hid_device *hdev;
struct input_dev *input; struct input_dev *input;
struct asus_kbd_leds *kbd_backlight; struct asus_kbd_leds *kbd_backlight;
const struct asus_touchpad_info *tp; const struct asus_touchpad_info *tp;
bool enable_backlight; bool enable_backlight;
struct power_supply *battery;
struct power_supply_desc battery_desc;
int battery_capacity;
int battery_stat;
bool battery_in_query;
unsigned long battery_next_query;
}; };
static int asus_report_battery(struct asus_drvdata *, u8 *, int);
static const struct asus_touchpad_info asus_i2c_tp = { static const struct asus_touchpad_info asus_i2c_tp = {
.max_x = 2794, .max_x = 2794,
.max_y = 1758, .max_y = 1758,
...@@ -259,6 +277,9 @@ static int asus_raw_event(struct hid_device *hdev, ...@@ -259,6 +277,9 @@ static int asus_raw_event(struct hid_device *hdev,
{ {
struct asus_drvdata *drvdata = hid_get_drvdata(hdev); struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->battery && data[0] == BATTERY_REPORT_ID)
return asus_report_battery(drvdata, data, size);
if (drvdata->tp && data[0] == INPUT_REPORT_ID) if (drvdata->tp && data[0] == INPUT_REPORT_ID)
return asus_report_input(drvdata, data, size); return asus_report_input(drvdata, data, size);
...@@ -428,6 +449,164 @@ static int asus_kbd_register_leds(struct hid_device *hdev) ...@@ -428,6 +449,164 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
return ret; return ret;
} }
/*
* [0] REPORT_ID (same value defined in report descriptor)
* [1] rest battery level. range [0..255]
* [2]..[7] Bluetooth hardware address (MAC address)
* [8] charging status
* = 0 : AC offline / discharging
* = 1 : AC online / charging
* = 2 : AC online / fully charged
*/
static int asus_parse_battery(struct asus_drvdata *drvdata, u8 *data, int size)
{
u8 sts;
u8 lvl;
int val;
lvl = data[1];
sts = data[8];
drvdata->battery_capacity = ((int)lvl * 100) / (int)BATTERY_LEVEL_MAX;
switch (sts) {
case BATTERY_STAT_CHARGING:
val = POWER_SUPPLY_STATUS_CHARGING;
break;
case BATTERY_STAT_FULL:
val = POWER_SUPPLY_STATUS_FULL;
break;
case BATTERY_STAT_DISCONNECT:
default:
val = POWER_SUPPLY_STATUS_DISCHARGING;
break;
}
drvdata->battery_stat = val;
return 0;
}
static int asus_report_battery(struct asus_drvdata *drvdata, u8 *data, int size)
{
/* notify only the autonomous event by device */
if ((drvdata->battery_in_query == false) &&
(size == BATTERY_REPORT_SIZE))
power_supply_changed(drvdata->battery);
return 0;
}
static int asus_battery_query(struct asus_drvdata *drvdata)
{
u8 *buf;
int ret = 0;
buf = kmalloc(BATTERY_REPORT_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
drvdata->battery_in_query = true;
ret = hid_hw_raw_request(drvdata->hdev, BATTERY_REPORT_ID,
buf, BATTERY_REPORT_SIZE,
HID_INPUT_REPORT, HID_REQ_GET_REPORT);
drvdata->battery_in_query = false;
if (ret == BATTERY_REPORT_SIZE)
ret = asus_parse_battery(drvdata, buf, BATTERY_REPORT_SIZE);
else
ret = -ENODATA;
kfree(buf);
return ret;
}
static enum power_supply_property asus_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_SCOPE,
POWER_SUPPLY_PROP_MODEL_NAME,
};
#define QUERY_MIN_INTERVAL (60 * HZ) /* 60[sec] */
static int asus_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct asus_drvdata *drvdata = power_supply_get_drvdata(psy);
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
case POWER_SUPPLY_PROP_CAPACITY:
if (time_before(drvdata->battery_next_query, jiffies)) {
drvdata->battery_next_query =
jiffies + QUERY_MIN_INTERVAL;
ret = asus_battery_query(drvdata);
if (ret)
return ret;
}
if (psp == POWER_SUPPLY_PROP_STATUS)
val->intval = drvdata->battery_stat;
else
val->intval = drvdata->battery_capacity;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = 1;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = drvdata->hdev->name;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int asus_battery_probe(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
struct power_supply_config pscfg = { .drv_data = drvdata };
int ret = 0;
drvdata->battery_capacity = 0;
drvdata->battery_stat = POWER_SUPPLY_STATUS_UNKNOWN;
drvdata->battery_in_query = false;
drvdata->battery_desc.properties = asus_battery_props;
drvdata->battery_desc.num_properties = ARRAY_SIZE(asus_battery_props);
drvdata->battery_desc.get_property = asus_battery_get_property;
drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
drvdata->battery_desc.use_for_apm = 0;
drvdata->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
"asus-keyboard-%s-battery",
strlen(hdev->uniq) ?
hdev->uniq : dev_name(&hdev->dev));
if (!drvdata->battery_desc.name)
return -ENOMEM;
drvdata->battery_next_query = jiffies;
drvdata->battery = devm_power_supply_register(&hdev->dev,
&(drvdata->battery_desc), &pscfg);
if (IS_ERR(drvdata->battery)) {
ret = PTR_ERR(drvdata->battery);
drvdata->battery = NULL;
hid_err(hdev, "Unable to register battery device\n");
return ret;
}
power_supply_powers(drvdata->battery, &hdev->dev);
return ret;
}
static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
{ {
struct input_dev *input = hi->input; struct input_dev *input = hi->input;
...@@ -500,7 +679,7 @@ static int asus_input_mapping(struct hid_device *hdev, ...@@ -500,7 +679,7 @@ static int asus_input_mapping(struct hid_device *hdev,
* This avoids a bunch of non-functional hid_input devices getting * This avoids a bunch of non-functional hid_input devices getting
* created because of the T100CHI using HID_QUIRK_MULTI_INPUT. * created because of the T100CHI using HID_QUIRK_MULTI_INPUT.
*/ */
if (drvdata->quirks & QUIRK_T100CHI) { if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
if (field->application == (HID_UP_GENDESK | 0x0080) || if (field->application == (HID_UP_GENDESK | 0x0080) ||
usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
...@@ -660,6 +839,15 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -660,6 +839,15 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
drvdata->quirks = id->driver_data; drvdata->quirks = id->driver_data;
/*
* T90CHI's keyboard dock returns same ID values as T100CHI's dock.
* Thus, identify T90CHI dock with product name string.
*/
if (strstr(hdev->name, "T90CHI")) {
drvdata->quirks &= ~QUIRK_T100CHI;
drvdata->quirks |= QUIRK_T90CHI;
}
if (drvdata->quirks & QUIRK_IS_MULTITOUCH) if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
drvdata->tp = &asus_i2c_tp; drvdata->tp = &asus_i2c_tp;
...@@ -694,6 +882,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -694,6 +882,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
drvdata->hdev = hdev;
if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
ret = asus_battery_probe(hdev);
if (ret) {
hid_err(hdev,
"Asus hid battery_probe failed: %d\n", ret);
return ret;
}
}
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret) { if (ret) {
hid_err(hdev, "Asus hid parse failed: %d\n", ret); hid_err(hdev, "Asus hid parse failed: %d\n", ret);
...@@ -769,28 +968,44 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -769,28 +968,44 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n"); hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT; rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
} }
/* For the T100CHI keyboard dock */ /* For the T100CHI/T90CHI keyboard dock */
if (drvdata->quirks & QUIRK_T100CHI && if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
*rsize == 403 && rdesc[388] == 0x09 && rdesc[389] == 0x76) { int rsize_orig;
int offs;
if (drvdata->quirks & QUIRK_T100CHI) {
rsize_orig = 403;
offs = 388;
} else {
rsize_orig = 306;
offs = 291;
}
/* /*
* Change Usage (76h) to Usage Minimum (00h), Usage Maximum * Change Usage (76h) to Usage Minimum (00h), Usage Maximum
* (FFh) and clear the flags in the Input() byte. * (FFh) and clear the flags in the Input() byte.
* Note the descriptor has a bogus 0 byte at the end so we * Note the descriptor has a bogus 0 byte at the end so we
* only need 1 extra byte. * only need 1 extra byte.
*/ */
*rsize = 404; if (*rsize == rsize_orig &&
rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
*rsize = rsize_orig + 1;
rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL); rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
if (!rdesc) if (!rdesc)
return NULL; return NULL;
hid_info(hdev, "Fixing up T100CHI keyb report descriptor\n"); hid_info(hdev, "Fixing up %s keyb report descriptor\n",
memmove(rdesc + 392, rdesc + 390, 12); drvdata->quirks & QUIRK_T100CHI ?
rdesc[388] = 0x19; "T100CHI" : "T90CHI");
rdesc[389] = 0x00; memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
rdesc[390] = 0x29; rdesc[offs] = 0x19;
rdesc[391] = 0xff; rdesc[offs + 1] = 0x00;
rdesc[402] = 0x00; rdesc[offs + 2] = 0x29;
rdesc[offs + 3] = 0xff;
rdesc[offs + 14] = 0x00;
} }
}
if (drvdata->quirks & QUIRK_G752_KEYBOARD && if (drvdata->quirks & QUIRK_G752_KEYBOARD &&
*rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) { *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) {
/* report is missing usage mninum and maximum */ /* report is missing usage mninum and maximum */
......
...@@ -393,7 +393,7 @@ static int elan_start_multitouch(struct hid_device *hdev) ...@@ -393,7 +393,7 @@ static int elan_start_multitouch(struct hid_device *hdev)
* This byte sequence will enable multitouch mode and disable * This byte sequence will enable multitouch mode and disable
* mouse emulation * mouse emulation
*/ */
const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 }; static const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 };
unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL); unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
if (!dmabuf) if (!dmabuf)
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
#define USB_VENDOR_ID_ALCOR 0x058f #define USB_VENDOR_ID_ALCOR 0x058f
#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
#define USB_DEVICE_ID_ALCOR_MALTRON_KB 0x9410
#define USB_VENDOR_ID_ALPS 0x0433 #define USB_VENDOR_ID_ALPS 0x0433
#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
...@@ -273,6 +274,7 @@ ...@@ -273,6 +274,7 @@
#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
#define USB_DEVICE_ID_ASUS_AK1D 0x1125 #define USB_DEVICE_ID_ASUS_AK1D 0x1125
#define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408
#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421 #define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421
#define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_VENDOR_ID_CHUNGHWAT 0x2247
...@@ -661,6 +663,7 @@ ...@@ -661,6 +663,7 @@
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501a #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501a
#define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 #define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013
#define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015 #define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015
#define USB_DEVICE_ID_KYE_EASYPEN_M406XE 0x5019
#define USB_VENDOR_ID_LABTEC 0x1020 #define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
...@@ -714,6 +717,7 @@ ...@@ -714,6 +717,7 @@
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3 #define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
#define USB_VENDOR_ID_LG 0x1fd2 #define USB_VENDOR_ID_LG 0x1fd2
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
...@@ -744,6 +748,7 @@ ...@@ -744,6 +748,7 @@
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FG 0xc20e
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
...@@ -1134,11 +1139,16 @@ ...@@ -1134,11 +1139,16 @@
#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 #define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781 #define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781
#define USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 0x3031 #define USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 0x3031
#define USB_DEVICE_ID_UGEE_TABLET_81 0x0081 #define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81 0x0081
#define USB_DEVICE_ID_UGEE_TABLET_45 0x0045 #define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45 0x0045
#define USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47 0x0047
#define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d #define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d
#define USB_VENDOR_ID_UGEE 0x28bd #define USB_VENDOR_ID_UGEE 0x28bd
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
#define USB_VENDOR_ID_UNITEC 0x227d #define USB_VENDOR_ID_UNITEC 0x227d
...@@ -1240,4 +1250,10 @@ ...@@ -1240,4 +1250,10 @@
#define USB_VENDOR_ID_UGTIZER 0x2179 #define USB_VENDOR_ID_UGTIZER 0x2179
#define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 #define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053
#define USB_VENDOR_ID_VIEWSONIC 0x0543
#define USB_DEVICE_ID_VIEWSONIC_PD1011 0xe621
#define USB_VENDOR_ID_SIGNOTEC 0x2133
#define USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011 0x0018
#endif #endif
...@@ -328,6 +328,9 @@ static const struct hid_device_id hid_battery_quirks[] = { ...@@ -328,6 +328,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL,
USB_DEVICE_ID_SYMBOL_SCANNER_3), USB_DEVICE_ID_SYMBOL_SCANNER_3),
HID_BATTERY_QUIRK_IGNORE }, HID_BATTERY_QUIRK_IGNORE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD),
HID_BATTERY_QUIRK_IGNORE },
{} {}
}; };
......
...@@ -483,6 +483,80 @@ static __u8 pensketch_m912_rdesc_fixed[] = { ...@@ -483,6 +483,80 @@ static __u8 pensketch_m912_rdesc_fixed[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
/* Original EasyPen M406XE report descriptor size */
#define EASYPEN_M406XE_RDESC_ORIG_SIZE 476
/* Fixed EasyPen M406XE report descriptor */
static __u8 easypen_m406xe_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x01, /* Usage (01h), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x05, /* Report ID (5), */
0x09, 0x01, /* Usage (01h), */
0x15, 0x80, /* Logical Minimum (-128), */
0x25, 0x7F, /* Logical Maximum (127), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x07, /* Report Count (7), */
0xB1, 0x02, /* Feature (Variable), */
0xC0, /* End Collection, */
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x10, /* Report ID (16), */
0x09, 0x20, /* Usage (Stylus), */
0xA0, /* Collection (Physical), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x09, 0x42, /* Usage (Tip Switch), */
0x09, 0x44, /* Usage (Barrel Switch), */
0x09, 0x46, /* Usage (Tablet Pick), */
0x95, 0x03, /* Report Count (3), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x04, /* Report Count (4), */
0x81, 0x03, /* Input (Constant, Variable), */
0x09, 0x32, /* Usage (In Range), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x02, /* Input (Variable), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0xA4, /* Push, */
0x05, 0x01, /* Usage Page (Desktop), */
0x55, 0xFD, /* Unit Exponent (-3), */
0x65, 0x13, /* Unit (Inch), */
0x34, /* Physical Minimum (0), */
0x09, 0x30, /* Usage (X), */
0x46, 0x70, 0x17, /* Physical Maximum (6000), */
0x26, 0x00, 0x3C, /* Logical Maximum (15360), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x31, /* Usage (Y), */
0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
0x26, 0x00, 0x28, /* Logical Maximum (10240), */
0x81, 0x02, /* Input (Variable), */
0xB4, /* Pop, */
0x09, 0x30, /* Usage (Tip Pressure), */
0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xC0, /* End Collection */
0x05, 0x0C, /* Usage Page (Consumer), */
0x09, 0x01, /* Usage (Consumer Control), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x12, /* Report ID (18), */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x04, /* Report Count (4), */
0x0A, 0x79, 0x02, /* Usage (AC Redo Or Repeat), */
0x0A, 0x1A, 0x02, /* Usage (AC Undo), */
0x0A, 0x2D, 0x02, /* Usage (AC Zoom In), */
0x0A, 0x2E, 0x02, /* Usage (AC Zoom Out), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x34, /* Report Count (52), */
0x81, 0x03, /* Input (Constant, Variable), */
0xC0 /* End Collection */
};
static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize, int offset, const char *device_name) { unsigned int *rsize, int offset, const char *device_name) {
/* /*
...@@ -555,6 +629,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -555,6 +629,12 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(easypen_m610x_rdesc_fixed); *rsize = sizeof(easypen_m610x_rdesc_fixed);
} }
break; break;
case USB_DEVICE_ID_KYE_EASYPEN_M406XE:
if (*rsize == EASYPEN_M406XE_RDESC_ORIG_SIZE) {
rdesc = easypen_m406xe_rdesc_fixed;
*rsize = sizeof(easypen_m406xe_rdesc_fixed);
}
break;
case USB_DEVICE_ID_KYE_PENSKETCH_M912: case USB_DEVICE_ID_KYE_PENSKETCH_M912:
if (*rsize == PENSKETCH_M912_RDESC_ORIG_SIZE) { if (*rsize == PENSKETCH_M912_RDESC_ORIG_SIZE) {
rdesc = pensketch_m912_rdesc_fixed; rdesc = pensketch_m912_rdesc_fixed;
...@@ -644,6 +724,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -644,6 +724,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)
case USB_DEVICE_ID_KYE_MOUSEPEN_I608X: case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2: case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
case USB_DEVICE_ID_KYE_EASYPEN_M610X: case USB_DEVICE_ID_KYE_EASYPEN_M610X:
case USB_DEVICE_ID_KYE_EASYPEN_M406XE:
case USB_DEVICE_ID_KYE_PENSKETCH_M912: case USB_DEVICE_ID_KYE_PENSKETCH_M912:
ret = kye_tablet_enable(hdev); ret = kye_tablet_enable(hdev);
if (ret) { if (ret) {
...@@ -678,6 +759,8 @@ static const struct hid_device_id kye_devices[] = { ...@@ -678,6 +759,8 @@ static const struct hid_device_id kye_devices[] = {
USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) }, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_KYE_EASYPEN_M610X) }, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_KYE_EASYPEN_M406XE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define MOMO_RDESC_ORIG_SIZE 87 #define MOMO_RDESC_ORIG_SIZE 87
#define MOMO2_RDESC_ORIG_SIZE 87 #define MOMO2_RDESC_ORIG_SIZE 87
#define FFG_RDESC_ORIG_SIZE 85 #define FFG_RDESC_ORIG_SIZE 85
#define FG_RDESC_ORIG_SIZE 82
/* Fixed report descriptors for Logitech Driving Force (and Pro) /* Fixed report descriptors for Logitech Driving Force (and Pro)
* wheel controllers * wheel controllers
...@@ -381,6 +382,49 @@ static __u8 ffg_rdesc_fixed[] = { ...@@ -381,6 +382,49 @@ static __u8 ffg_rdesc_fixed[] = {
0xC0 /* End Collection */ 0xC0 /* End Collection */
}; };
static __u8 fg_rdesc_fixed[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x04, /* Usage (Joystik), */
0xA1, 0x01, /* Collection (Application), */
0xA1, 0x02, /* Collection (Logical), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x35, 0x00, /* Physical Minimum (0), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x01, /* Report Count (1), */
0x09, 0x30, /* Usage (X), */
0x81, 0x02, /* Input (Variable), */
0xA4, /* Push, */
0x25, 0x01, /* Logical Maximum (1), */
0x45, 0x01, /* Physical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x01, /* Input (Constant), */
0x95, 0x06, /* Report Count (6), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x06, /* Usage Maximum (06h), */
0x81, 0x02, /* Input (Variable), */
0x05, 0x01, /* Usage Page (Desktop), */
0xB4, /* Pop, */
0x81, 0x02, /* Input (Constant), */
0x09, 0x31, /* Usage (Y), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x32, /* Usage (Z), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xA1, 0x02, /* Collection (Logical), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x46, 0xFF, 0x00, /* Physical Maximum (255), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x04, /* Report Count (4), */
0x09, 0x02, /* Usage (02h), */
0xB1, 0x02, /* Feature (Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection, */
};
/* /*
* Certain Logitech keyboards send in report #3 keys which are far * Certain Logitech keyboards send in report #3 keys which are far
* above the logical maximum described in descriptor. This extends * above the logical maximum described in descriptor. This extends
...@@ -408,6 +452,19 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -408,6 +452,19 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
switch (hdev->product) { switch (hdev->product) {
case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
if (*rsize == FG_RDESC_ORIG_SIZE) {
hid_info(hdev,
"fixing up Logitech Wingman Formula GP report descriptor\n");
rdesc = fg_rdesc_fixed;
*rsize = sizeof(fg_rdesc_fixed);
} else {
hid_info(hdev,
"rdesc size test failed for formula gp\n");
}
break;
case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
if (*rsize == FFG_RDESC_ORIG_SIZE) { if (*rsize == FFG_RDESC_ORIG_SIZE) {
hid_info(hdev, hid_info(hdev,
...@@ -664,6 +721,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi, ...@@ -664,6 +721,7 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
usage->code == ABS_RZ)) { usage->code == ABS_RZ)) {
switch (hdev->product) { switch (hdev->product) {
case USB_DEVICE_ID_LOGITECH_G29_WHEEL: case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
case USB_DEVICE_ID_LOGITECH_WHEEL: case USB_DEVICE_ID_LOGITECH_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
...@@ -871,6 +929,8 @@ static const struct hid_device_id lg_devices[] = { ...@@ -871,6 +929,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_NOGET | LG_FF4 }, .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 }, .driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
.driver_data = LG_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
.driver_data = LG_NOGET | LG_FF4 }, .driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
......
...@@ -103,6 +103,10 @@ static const signed short lg4ff_wheel_effects[] = { ...@@ -103,6 +103,10 @@ static const signed short lg4ff_wheel_effects[] = {
-1 -1
}; };
static const signed short no_wheel_effects[] = {
-1
};
struct lg4ff_wheel { struct lg4ff_wheel {
const u32 product_id; const u32 product_id;
const signed short *ff_effects; const signed short *ff_effects;
...@@ -137,6 +141,7 @@ struct lg4ff_alternate_mode { ...@@ -137,6 +141,7 @@ struct lg4ff_alternate_mode {
}; };
static const struct lg4ff_wheel lg4ff_devices[] = { static const struct lg4ff_wheel lg4ff_devices[] = {
{USB_DEVICE_ID_LOGITECH_WINGMAN_FG, no_wheel_effects, 40, 180, NULL},
{USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, lg4ff_wheel_effects, 40, 180, NULL}, {USB_DEVICE_ID_LOGITECH_WINGMAN_FFG, lg4ff_wheel_effects, 40, 180, NULL},
{USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
{USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL},
...@@ -346,6 +351,7 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -346,6 +351,7 @@ int lg4ff_raw_event(struct hid_device *hdev, struct hid_report *report,
rd[5] = rd[3]; rd[5] = rd[3];
rd[6] = 0x7F; rd[6] = 0x7F;
return 1; return 1;
case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG: case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
......
// SPDX-License-Identifier: GPL-2.0
/*
* HID driver for Maltron L90
*
* 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) 2008 Jiri Slaby
* Copyright (c) 2012 David Dillow <dave@thedillows.org>
* Copyright (c) 2006-2013 Jiri Kosina
* Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
* Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
* Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
* Copyright (c) 2018 William Whistler <wtbw@wtbw.co.uk>
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
/* The original buggy USB descriptor */
static u8 maltron_rdesc_o[] = {
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x80, /* Usage (Sys Control) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x02, /* Report ID (2) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x01, /* Report Count (1) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x09, 0x82, /* Usage (Sys Sleep) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x09, 0x82, /* Usage (Sys Sleep) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x09, 0x83, /* Usage (Sys Wake Up) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x75, 0x05, /* Report Size (5) */
0x81, 0x01, /* Input (Const,Array,Abs) */
0xC0, /* End Collection */
0x05, 0x0C, /* Usage Page (Consumer) */
0x09, 0x01, /* Usage (Consumer Control) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x03, /* Report ID (3) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x10, /* Report Size (16) */
0x19, 0x00, /* Usage Minimum (Unassigned) */
0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */
0x81, 0x00, /* Input (Data,Array,Abs) */
0xC0, /* End Collection */
0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */
0x09, 0x01, /* Usage (0x01) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x04, /* Report ID (4) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x10, /* Report Size (16) */
0x19, 0x00, /* Usage Minimum (0x00) */
0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */
0x81, 0x00, /* Input (Data,Array,Abs) */
0x75, 0x02, /* Report Size (2) */
0x25, 0x02, /* Logical Maximum (2) */
0x09, 0x90, /* Usage (0x90) */
0xB1, 0x02, /* Feature (Data,Var,Abs) */
0x75, 0x06, /* Report Size (6) */
0xB1, 0x01, /* Feature (Const,Array,Abs) */
0x75, 0x01, /* Report Size (1) */
0x25, 0x01, /* Logical Maximum (1) */
0x05, 0x08, /* Usage Page (LEDs) */
0x09, 0x2A, /* Usage (On-Line) */
0x91, 0x02, /* Output (Data,Var,Abs) */
0x09, 0x4B, /* Usage (Generic Indicator) */
0x91, 0x02, /* Output (Data,Var,Abs) */
0x75, 0x06, /* Report Size (6) */
0x95, 0x01, /* Report Count (1) */
0x91, 0x01, /* Output (Const,Array,Abs) */
0xC0 /* End Collection */
};
/* The patched descriptor, allowing media key events to be accepted as valid */
static u8 maltron_rdesc[] = {
0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
0x09, 0x80, /* Usage (Sys Control) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x02, /* Report ID (2) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x01, /* Report Count (1) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x09, 0x82, /* Usage (Sys Sleep) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x09, 0x82, /* Usage (Sys Sleep) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x09, 0x83, /* Usage (Sys Wake Up) */
0x81, 0x06, /* Input (Data,Var,Rel) */
0x75, 0x05, /* Report Size (5) */
0x81, 0x01, /* Input (Const,Array,Abs) */
0xC0, /* End Collection */
0x05, 0x0C, /* Usage Page (Consumer) */
0x09, 0x01, /* Usage (Consumer Control) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x03, /* Report ID (3) */
0x15, 0x00, /* Logical Minimum (0) - changed */
0x26, 0xFF, 0x7F, /* Logical Maximum (32767) - changed */
0x95, 0x01, /* Report Count (1) */
0x75, 0x10, /* Report Size (16) */
0x19, 0x00, /* Usage Minimum (Unassigned) */
0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */
0x81, 0x00, /* Input (Data,Array,Abs) */
0xC0, /* End Collection */
0x06, 0x7F, 0xFF, /* Usage Page (Vendor Defined 0xFF7F) */
0x09, 0x01, /* Usage (0x01) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x04, /* Report ID (4) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x10, /* Report Size (16) */
0x19, 0x00, /* Usage Minimum (0x00) */
0x2A, 0xFF, 0x7F, /* Usage Maximum (0x7FFF) */
0x81, 0x00, /* Input (Data,Array,Abs) */
0x75, 0x02, /* Report Size (2) */
0x25, 0x02, /* Logical Maximum (2) */
0x09, 0x90, /* Usage (0x90) */
0xB1, 0x02, /* Feature (Data,Var,Abs) */
0x75, 0x06, /* Report Size (6) */
0xB1, 0x01, /* Feature (Const,Array,Abs) */
0x75, 0x01, /* Report Size (1) */
0x25, 0x01, /* Logical Maximum (1) */
0x05, 0x08, /* Usage Page (LEDs) */
0x09, 0x2A, /* Usage (On-Line) */
0x91, 0x02, /* Output (Data,Var,Abs) */
0x09, 0x4B, /* Usage (Generic Indicator) */
0x91, 0x02, /* Output (Data,Var,Abs) */
0x75, 0x06, /* Report Size (6) */
0x95, 0x01, /* Report Count (1) */
0x91, 0x01, /* Output (Const,Array,Abs) */
0xC0 /* End Collection */
};
static __u8 *maltron_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize == sizeof(maltron_rdesc_o) &&
!memcmp(maltron_rdesc_o, rdesc, sizeof(maltron_rdesc_o))) {
hid_info(hdev, "Replacing Maltron L90 keyboard report descriptor\n");
*rsize = sizeof(maltron_rdesc);
return maltron_rdesc;
}
return rdesc;
}
static const struct hid_device_id maltron_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_MALTRON_KB)},
{ }
};
MODULE_DEVICE_TABLE(hid, maltron_devices);
static struct hid_driver maltron_driver = {
.name = "maltron",
.id_table = maltron_devices,
.report_fixup = maltron_report_fixup
};
module_hid_driver(maltron_driver);
MODULE_LICENSE("GPL");
...@@ -1780,6 +1780,12 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1780,6 +1780,12 @@ static const struct hid_device_id mt_devices[] = {
USB_VENDOR_ID_LENOVO, USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X1_TAB) }, USB_DEVICE_ID_LENOVO_X1_TAB) },
/* Lenovo X1 TAB Gen 3 */
{ .driver_data = MT_CLS_WIN_8_DUAL,
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X1_TAB3) },
/* Anton devices */ /* Anton devices */
{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS, { .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
MT_USB_DEVICE(USB_VENDOR_ID_ANTON, MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
......
...@@ -99,6 +99,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -99,6 +99,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
...@@ -411,11 +412,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -411,11 +412,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_LCPOWER) #if IS_ENABLED(CONFIG_HID_LCPOWER)
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
...@@ -451,6 +447,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -451,6 +447,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
...@@ -673,35 +670,9 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -673,35 +670,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_TWINHAN) #if IS_ENABLED(CONFIG_HID_TWINHAN)
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_UCLOGIC)
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
#endif
#if IS_ENABLED(CONFIG_HID_UDRAW_PS3) #if IS_ENABLED(CONFIG_HID_UDRAW_PS3)
{ HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) }, { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_WALTOP)
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
#endif
#if IS_ENABLED(CONFIG_HID_XINMO) #if IS_ENABLED(CONFIG_HID_XINMO)
{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) },
......
...@@ -783,6 +783,7 @@ static void kone_keep_values_up_to_date(struct kone_device *kone, ...@@ -783,6 +783,7 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
case kone_mouse_event_switch_profile: case kone_mouse_event_switch_profile:
kone->actual_dpi = kone->profiles[event->value - 1]. kone->actual_dpi = kone->profiles[event->value - 1].
startup_dpi; startup_dpi;
/* fall through */
case kone_mouse_event_osd_profile: case kone_mouse_event_osd_profile:
kone->actual_profile = event->value; kone->actual_profile = event->value;
break; break;
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#define FUTUREMAX_DANCE_MAT BIT(13) #define FUTUREMAX_DANCE_MAT BIT(13)
#define NSG_MR5U_REMOTE_BT BIT(14) #define NSG_MR5U_REMOTE_BT BIT(14)
#define NSG_MR7U_REMOTE_BT BIT(15) #define NSG_MR7U_REMOTE_BT BIT(15)
#define SHANWAN_GAMEPAD BIT(16)
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
...@@ -1490,6 +1491,7 @@ static int sony_register_sensors(struct sony_sc *sc) ...@@ -1490,6 +1491,7 @@ static int sony_register_sensors(struct sony_sc *sc)
*/ */
static int sixaxis_set_operational_usb(struct hid_device *hdev) static int sixaxis_set_operational_usb(struct hid_device *hdev)
{ {
struct sony_sc *sc = hid_get_drvdata(hdev);
const int buf_size = const int buf_size =
max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE); max(SIXAXIS_REPORT_0xF2_SIZE, SIXAXIS_REPORT_0xF5_SIZE);
u8 *buf; u8 *buf;
...@@ -1519,15 +1521,16 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) ...@@ -1519,15 +1521,16 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
/* /*
* But the USB interrupt would cause SHANWAN controllers to * But the USB interrupt would cause SHANWAN controllers to
* start rumbling non-stop. * start rumbling non-stop, so skip step 3 for these controllers.
*/ */
if (strcmp(hdev->name, "SHANWAN PS3 GamePad")) { if (sc->quirks & SHANWAN_GAMEPAD)
goto out;
ret = hid_hw_output_report(hdev, buf, 1); ret = hid_hw_output_report(hdev, buf, 1);
if (ret < 0) { if (ret < 0) {
hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); hid_info(hdev, "can't set operational mode: step 3, ignoring\n");
ret = 0; ret = 0;
} }
}
out: out:
kfree(buf); kfree(buf);
...@@ -2097,6 +2100,11 @@ static void sixaxis_send_output_report(struct sony_sc *sc) ...@@ -2097,6 +2100,11 @@ static void sixaxis_send_output_report(struct sony_sc *sc)
} }
} }
/* SHANWAN controllers require output reports via intr channel */
if (sc->quirks & SHANWAN_GAMEPAD)
hid_hw_output_report(sc->hdev, (u8 *)report,
sizeof(struct sixaxis_output_report));
else
hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report, hid_hw_raw_request(sc->hdev, report->report_id, (u8 *)report,
sizeof(struct sixaxis_output_report), sizeof(struct sixaxis_output_report),
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
...@@ -2811,6 +2819,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -2811,6 +2819,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!strcmp(hdev->name, "FutureMax Dance Mat")) if (!strcmp(hdev->name, "FutureMax Dance Mat"))
quirks |= FUTUREMAX_DANCE_MAT; quirks |= FUTUREMAX_DANCE_MAT;
if (!strcmp(hdev->name, "SHANWAN PS3 GamePad"))
quirks |= SHANWAN_GAMEPAD;
sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
if (sc == NULL) { if (sc == NULL) {
hid_err(hdev, "can't alloc sony descriptor\n"); hid_err(hdev, "can't alloc sony descriptor\n");
......
...@@ -283,11 +283,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) ...@@ -283,11 +283,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
static int steam_input_open(struct input_dev *dev) static int steam_input_open(struct input_dev *dev)
{ {
struct steam_device *steam = input_get_drvdata(dev); struct steam_device *steam = input_get_drvdata(dev);
int ret;
ret = hid_hw_open(steam->hdev);
if (ret)
return ret;
mutex_lock(&steam->mutex); mutex_lock(&steam->mutex);
if (!steam->client_opened && lizard_mode) if (!steam->client_opened && lizard_mode)
...@@ -304,8 +299,6 @@ static void steam_input_close(struct input_dev *dev) ...@@ -304,8 +299,6 @@ static void steam_input_close(struct input_dev *dev)
if (!steam->client_opened && lizard_mode) if (!steam->client_opened && lizard_mode)
steam_set_lizard_mode(steam, true); steam_set_lizard_mode(steam, true);
mutex_unlock(&steam->mutex); mutex_unlock(&steam->mutex);
hid_hw_close(steam->hdev);
} }
static enum power_supply_property steam_battery_props[] = { static enum power_supply_property steam_battery_props[] = {
...@@ -623,11 +616,6 @@ static void steam_client_ll_stop(struct hid_device *hdev) ...@@ -623,11 +616,6 @@ static void steam_client_ll_stop(struct hid_device *hdev)
static int steam_client_ll_open(struct hid_device *hdev) static int steam_client_ll_open(struct hid_device *hdev)
{ {
struct steam_device *steam = hdev->driver_data; struct steam_device *steam = hdev->driver_data;
int ret;
ret = hid_hw_open(steam->hdev);
if (ret)
return ret;
mutex_lock(&steam->mutex); mutex_lock(&steam->mutex);
steam->client_opened = true; steam->client_opened = true;
...@@ -635,7 +623,7 @@ static int steam_client_ll_open(struct hid_device *hdev) ...@@ -635,7 +623,7 @@ static int steam_client_ll_open(struct hid_device *hdev)
steam_input_unregister(steam); steam_input_unregister(steam);
return ret; return 0;
} }
static void steam_client_ll_close(struct hid_device *hdev) static void steam_client_ll_close(struct hid_device *hdev)
...@@ -646,7 +634,6 @@ static void steam_client_ll_close(struct hid_device *hdev) ...@@ -646,7 +634,6 @@ static void steam_client_ll_close(struct hid_device *hdev)
steam->client_opened = false; steam->client_opened = false;
mutex_unlock(&steam->mutex); mutex_unlock(&steam->mutex);
hid_hw_close(steam->hdev);
if (steam->connected) { if (steam->connected) {
steam_set_lizard_mode(steam, lizard_mode); steam_set_lizard_mode(steam, lizard_mode);
steam_input_register(steam); steam_input_register(steam);
...@@ -759,14 +746,15 @@ static int steam_probe(struct hid_device *hdev, ...@@ -759,14 +746,15 @@ static int steam_probe(struct hid_device *hdev,
if (ret) if (ret)
goto client_hdev_add_fail; goto client_hdev_add_fail;
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
ret = hid_hw_open(hdev); ret = hid_hw_open(hdev);
if (ret) { if (ret) {
hid_err(hdev, hid_err(hdev,
"%s:hid_hw_open for wireless\n", "%s:hid_hw_open\n",
__func__); __func__);
goto hid_hw_open_fail; goto hid_hw_open_fail;
} }
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
hid_info(hdev, "Steam wireless receiver connected"); hid_info(hdev, "Steam wireless receiver connected");
steam_request_conn_status(steam); steam_request_conn_status(steam);
} else { } else {
...@@ -781,8 +769,8 @@ static int steam_probe(struct hid_device *hdev, ...@@ -781,8 +769,8 @@ static int steam_probe(struct hid_device *hdev,
return 0; return 0;
hid_hw_open_fail:
input_register_fail: input_register_fail:
hid_hw_open_fail:
client_hdev_add_fail: client_hdev_add_fail:
hid_hw_stop(hdev); hid_hw_stop(hdev);
hid_hw_start_fail: hid_hw_start_fail:
...@@ -809,8 +797,8 @@ static void steam_remove(struct hid_device *hdev) ...@@ -809,8 +797,8 @@ static void steam_remove(struct hid_device *hdev)
cancel_work_sync(&steam->work_connect); cancel_work_sync(&steam->work_connect);
if (steam->quirks & STEAM_QUIRK_WIRELESS) { if (steam->quirks & STEAM_QUIRK_WIRELESS) {
hid_info(hdev, "Steam wireless receiver disconnected"); hid_info(hdev, "Steam wireless receiver disconnected");
hid_hw_close(hdev);
} }
hid_hw_close(hdev);
hid_hw_stop(hdev); hid_hw_stop(hdev);
steam_unregister(steam); steam_unregister(steam);
} }
......
...@@ -34,7 +34,9 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -34,7 +34,9 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0; return 0;
switch (usage->hid & HID_USAGE) { switch (usage->hid & HID_USAGE) {
case 0x00c: ts_map_key_clear(KEY_WLAN); break;
case 0x00d: ts_map_key_clear(KEY_MEDIA); break; case 0x00d: ts_map_key_clear(KEY_MEDIA); break;
case 0x010: ts_map_key_clear(KEY_ZOOM); break;
case 0x024: ts_map_key_clear(KEY_MENU); break; case 0x024: ts_map_key_clear(KEY_MENU); break;
case 0x025: ts_map_key_clear(KEY_TV); break; case 0x025: ts_map_key_clear(KEY_TV); break;
case 0x027: ts_map_key_clear(KEY_MODE); break; case 0x027: ts_map_key_clear(KEY_MODE); break;
...@@ -67,6 +69,7 @@ static const struct hid_device_id ts_devices[] = { ...@@ -67,6 +69,7 @@ static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, ts_devices); MODULE_DEVICE_TABLE(hid, ts_devices);
......
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* HID driver for UC-Logic devices not fully compliant with HID standard
* - tablet initialization and parameter retrieval
*
* Copyright (c) 2018 Nikolai Kondrashov
*/
/*
* 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.
*/
#ifndef _HID_UCLOGIC_PARAMS_H
#define _HID_UCLOGIC_PARAMS_H
#include <linux/usb.h>
#include <linux/hid.h>
/* Types of pen in-range reporting */
enum uclogic_params_pen_inrange {
/* Normal reports: zero - out of proximity, one - in proximity */
UCLOGIC_PARAMS_PEN_INRANGE_NORMAL = 0,
/* Inverted reports: zero - in proximity, one - out of proximity */
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED,
/* No reports */
UCLOGIC_PARAMS_PEN_INRANGE_NONE,
};
/* Convert a pen in-range reporting type to a string */
extern const char *uclogic_params_pen_inrange_to_str(
enum uclogic_params_pen_inrange inrange);
/*
* Tablet interface's pen input parameters.
*
* Must use declarative (descriptive) language, not imperative, to simplify
* understanding and maintain consistency.
*
* Noop (preserving functionality) when filled with zeroes.
*/
struct uclogic_params_pen {
/*
* Pointer to report descriptor describing the inputs.
* Allocated with kmalloc.
*/
__u8 *desc_ptr;
/*
* Size of the report descriptor.
* Only valid, if "desc_ptr" is not NULL.
*/
unsigned int desc_size;
/* Report ID, if reports should be tweaked, zero if not */
unsigned int id;
/* Type of in-range reporting, only valid if "id" is not zero */
enum uclogic_params_pen_inrange inrange;
/*
* True, if reports include fragmented high resolution coords, with
* high-order X and then Y bytes following the pressure field.
* Only valid if "id" is not zero.
*/
bool fragmented_hires;
};
/*
* Parameters of frame control inputs of a tablet interface.
*
* Must use declarative (descriptive) language, not imperative, to simplify
* understanding and maintain consistency.
*
* Noop (preserving functionality) when filled with zeroes.
*/
struct uclogic_params_frame {
/*
* Pointer to report descriptor describing the inputs.
* Allocated with kmalloc.
*/
__u8 *desc_ptr;
/*
* Size of the report descriptor.
* Only valid, if "desc_ptr" is not NULL.
*/
unsigned int desc_size;
/*
* Report ID, if reports should be tweaked, zero if not.
*/
unsigned int id;
/*
* Number of the least-significant bit of the 2-bit state of a rotary
* encoder, in the report. Cannot point to a 2-bit field crossing a
* byte boundary. Zero if not present. Only valid if "id" is not zero.
*/
unsigned int re_lsb;
/*
* Offset of the Wacom-style device ID byte in the report, to be set
* to pad device ID (0xf), for compatibility with Wacom drivers. Zero
* if no changes to the report should be made. Only valid if "id" is
* not zero.
*/
unsigned int dev_id_byte;
};
/*
* Tablet interface report parameters.
*
* Must use declarative (descriptive) language, not imperative, to simplify
* understanding and maintain consistency.
*
* When filled with zeros represents a "noop" configuration - passes all
* reports unchanged and lets the generic HID driver handle everything.
*
* The resulting device report descriptor is assembled from all the report
* descriptor parts referenced by the structure. No order of assembly should
* be assumed. The structure represents original device report descriptor if
* all the parts are NULL.
*/
struct uclogic_params {
/*
* True if the whole interface is invalid, false otherwise.
*/
bool invalid;
/*
* Pointer to the common part of the replacement report descriptor,
* allocated with kmalloc. NULL if no common part is needed.
* Only valid, if "invalid" is false.
*/
__u8 *desc_ptr;
/*
* Size of the common part of the replacement report descriptor.
* Only valid, if "desc_ptr" is not NULL.
*/
unsigned int desc_size;
/*
* True, if pen usage in report descriptor is invalid, when present.
* Only valid, if "invalid" is false.
*/
bool pen_unused;
/*
* Pen parameters and optional report descriptor part.
* Only valid if "pen_unused" is valid and false.
*/
struct uclogic_params_pen pen;
/*
* Frame control parameters and optional report descriptor part.
* Only valid, if "invalid" is false.
*/
struct uclogic_params_frame frame;
/*
* Bitmask matching frame controls "sub-report" flag in the second
* byte of the pen report, or zero if it's not expected.
* Only valid if both "pen" and "frame" are valid, and "frame.id" is
* not zero.
*/
__u8 pen_frame_flag;
};
/* Initialize a tablet interface and discover its parameters */
extern int uclogic_params_init(struct uclogic_params *params,
struct hid_device *hdev);
/* Tablet interface parameters *printf format string */
#define UCLOGIC_PARAMS_FMT_STR \
".invalid = %s\n" \
".desc_ptr = %p\n" \
".desc_size = %u\n" \
".pen_unused = %s\n" \
".pen.desc_ptr = %p\n" \
".pen.desc_size = %u\n" \
".pen.id = %u\n" \
".pen.inrange = %s\n" \
".pen.fragmented_hires = %s\n" \
".frame.desc_ptr = %p\n" \
".frame.desc_size = %u\n" \
".frame.id = %u\n" \
".frame.re_lsb = %u\n" \
".frame.dev_id_byte = %u\n" \
".pen_frame_flag = 0x%02x\n"
/* Tablet interface parameters *printf format arguments */
#define UCLOGIC_PARAMS_FMT_ARGS(_params) \
((_params)->invalid ? "true" : "false"), \
(_params)->desc_ptr, \
(_params)->desc_size, \
((_params)->pen_unused ? "true" : "false"), \
(_params)->pen.desc_ptr, \
(_params)->pen.desc_size, \
(_params)->pen.id, \
uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \
((_params)->pen.fragmented_hires ? "true" : "false"), \
(_params)->frame.desc_ptr, \
(_params)->frame.desc_size, \
(_params)->frame.id, \
(_params)->frame.re_lsb, \
(_params)->frame.dev_id_byte, \
(_params)->pen_frame_flag
/* Get a replacement report descriptor for a tablet's interface. */
extern int uclogic_params_get_desc(const struct uclogic_params *params,
__u8 **pdesc,
unsigned int *psize);
/* Free resources used by tablet interface's parameters */
extern void uclogic_params_cleanup(struct uclogic_params *params);
#endif /* _HID_UCLOGIC_PARAMS_H */
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* HID driver for UC-Logic devices not fully compliant with HID standard
* - original and fixed report descriptors
*
* Copyright (c) 2010-2018 Nikolai Kondrashov
* Copyright (c) 2013 Martin Rusko
*/
/*
* 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.
*/
#ifndef _HID_UCLOGIC_RDESC_H
#define _HID_UCLOGIC_RDESC_H
#include <linux/usb.h>
/* Size of the original descriptor of WPXXXXU tablets */
#define UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE 212
/* Fixed WP4030U report descriptor */
extern __u8 uclogic_rdesc_wp4030u_fixed_arr[];
extern const size_t uclogic_rdesc_wp4030u_fixed_size;
/* Fixed WP5540U report descriptor */
extern __u8 uclogic_rdesc_wp5540u_fixed_arr[];
extern const size_t uclogic_rdesc_wp5540u_fixed_size;
/* Fixed WP8060U report descriptor */
extern __u8 uclogic_rdesc_wp8060u_fixed_arr[];
extern const size_t uclogic_rdesc_wp8060u_fixed_size;
/* Size of the original descriptor of the new WP5540U tablet */
#define UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE 232
/* Size of the original descriptor of WP1062 tablet */
#define UCLOGIC_RDESC_WP1062_ORIG_SIZE 254
/* Fixed WP1062 report descriptor */
extern __u8 uclogic_rdesc_wp1062_fixed_arr[];
extern const size_t uclogic_rdesc_wp1062_fixed_size;
/* Size of the original descriptor of PF1209 tablet */
#define UCLOGIC_RDESC_PF1209_ORIG_SIZE 234
/* Fixed PF1209 report descriptor */
extern __u8 uclogic_rdesc_pf1209_fixed_arr[];
extern const size_t uclogic_rdesc_pf1209_fixed_size;
/* Size of the original descriptors of TWHL850 tablet */
#define UCLOGIC_RDESC_TWHL850_ORIG0_SIZE 182
#define UCLOGIC_RDESC_TWHL850_ORIG1_SIZE 161
#define UCLOGIC_RDESC_TWHL850_ORIG2_SIZE 92
/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
extern __u8 uclogic_rdesc_twhl850_fixed0_arr[];
extern const size_t uclogic_rdesc_twhl850_fixed0_size;
/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
extern __u8 uclogic_rdesc_twhl850_fixed1_arr[];
extern const size_t uclogic_rdesc_twhl850_fixed1_size;
/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
extern __u8 uclogic_rdesc_twhl850_fixed2_arr[];
extern const size_t uclogic_rdesc_twhl850_fixed2_size;
/* Size of the original descriptors of TWHA60 tablet */
#define UCLOGIC_RDESC_TWHA60_ORIG0_SIZE 254
#define UCLOGIC_RDESC_TWHA60_ORIG1_SIZE 139
/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
extern __u8 uclogic_rdesc_twha60_fixed0_arr[];
extern const size_t uclogic_rdesc_twha60_fixed0_size;
/* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
extern __u8 uclogic_rdesc_twha60_fixed1_arr[];
extern const size_t uclogic_rdesc_twha60_fixed1_size;
/* Report descriptor template placeholder head */
#define UCLOGIC_RDESC_PH_HEAD 0xFE, 0xED, 0x1D
/* Apply report descriptor parameters to a report descriptor template */
extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr,
size_t template_size,
const s32 *param_list,
size_t param_num);
/* Pen report descriptor template placeholder IDs */
enum uclogic_rdesc_pen_ph_id {
UCLOGIC_RDESC_PEN_PH_ID_X_LM,
UCLOGIC_RDESC_PEN_PH_ID_X_PM,
UCLOGIC_RDESC_PEN_PH_ID_Y_LM,
UCLOGIC_RDESC_PEN_PH_ID_Y_PM,
UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM,
UCLOGIC_RDESC_PEN_PH_ID_NUM
};
/* Report descriptor pen template placeholder */
#define UCLOGIC_RDESC_PEN_PH(_ID) \
UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
/* Report ID for v1 pen reports */
#define UCLOGIC_RDESC_PEN_V1_ID 0x07
/* Fixed report descriptor template for (tweaked) v1 pen reports */
extern const __u8 uclogic_rdesc_pen_v1_template_arr[];
extern const size_t uclogic_rdesc_pen_v1_template_size;
/* Report ID for v2 pen reports */
#define UCLOGIC_RDESC_PEN_V2_ID 0x08
/* Fixed report descriptor template for (tweaked) v2 pen reports */
extern const __u8 uclogic_rdesc_pen_v2_template_arr[];
extern const size_t uclogic_rdesc_pen_v2_template_size;
/* Fixed report descriptor for (tweaked) v1 buttonpad reports */
extern const __u8 uclogic_rdesc_buttonpad_v1_arr[];
extern const size_t uclogic_rdesc_buttonpad_v1_size;
/* Report ID for tweaked v1 buttonpad reports */
#define UCLOGIC_RDESC_BUTTONPAD_V1_ID 0xf7
/* Fixed report descriptor for (tweaked) v2 buttonpad reports */
extern const __u8 uclogic_rdesc_buttonpad_v2_arr[];
extern const size_t uclogic_rdesc_buttonpad_v2_size;
/* Report ID for tweaked v2 buttonpad reports */
#define UCLOGIC_RDESC_BUTTONPAD_V2_ID 0xf7
/* Fixed report descriptor for Ugee EX07 buttonpad */
extern const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[];
extern const size_t uclogic_rdesc_ugee_ex07_buttonpad_size;
/* Fixed report descriptor for XP-Pen Deco 01 frame controls */
extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[];
extern const size_t uclogic_rdesc_xppen_deco01_frame_size;
/* Fixed report descriptor for Ugee G5 frame controls */
extern const __u8 uclogic_rdesc_ugee_g5_frame_arr[];
extern const size_t uclogic_rdesc_ugee_g5_frame_size;
/* Report ID of Ugee G5 frame control reports */
#define UCLOGIC_RDESC_UGEE_G5_FRAME_ID 0x06
/* Device ID byte offset in Ugee G5 frame report */
#define UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE 0x2
/* Least-significant bit of Ugee G5 frame rotary encoder state */
#define UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB 38
#endif /* _HID_UCLOGIC_RDESC_H */
// SPDX-License-Identifier: GPL-2.0+
/*
* HID driver for ViewSonic devices not fully compliant with HID standard
*
* Copyright (c) 2017 Nikolai Kondrashov
*/
/*
* 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/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
/* Size of the original descriptor of PD1011 signature pad */
#define PD1011_RDESC_ORIG_SIZE 408
/* Fixed report descriptor of PD1011 signature pad */
static __u8 pd1011_rdesc_fixed[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x02, /* Report ID (2), */
0x09, 0x20, /* Usage (Stylus), */
0xA0, /* Collection (Physical), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0xA4, /* Push, */
0x05, 0x01, /* Usage Page (Desktop), */
0x65, 0x13, /* Unit (Inch), */
0x55, 0xFD, /* Unit Exponent (-3), */
0x34, /* Physical Minimum (0), */
0x09, 0x30, /* Usage (X), */
0x46, 0x5D, 0x21, /* Physical Maximum (8541), */
0x27, 0x80, 0xA9,
0x00, 0x00, /* Logical Maximum (43392), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x31, /* Usage (Y), */
0x46, 0xDA, 0x14, /* Physical Maximum (5338), */
0x26, 0xF0, 0x69, /* Logical Maximum (27120), */
0x81, 0x02, /* Input (Variable), */
0xB4, /* Pop, */
0x14, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x03, /* Input (Constant, Variable), */
0x09, 0x32, /* Usage (In Range), */
0x09, 0x42, /* Usage (Tip Switch), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x05, /* Report Count (5), */
0x81, 0x03, /* Input (Constant, Variable), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0x09, 0x30, /* Usage (Tip Pressure), */
0x15, 0x05, /* Logical Minimum (5), */
0x26, 0xFF, 0x07, /* Logical Maximum (2047), */
0x81, 0x02, /* Input (Variable), */
0x75, 0x10, /* Report Size (16), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x03, /* Input (Constant, Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
static __u8 *viewsonic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
switch (hdev->product) {
case USB_DEVICE_ID_VIEWSONIC_PD1011:
case USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011:
if (*rsize == PD1011_RDESC_ORIG_SIZE) {
rdesc = pd1011_rdesc_fixed;
*rsize = sizeof(pd1011_rdesc_fixed);
}
break;
}
return rdesc;
}
static const struct hid_device_id viewsonic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_VIEWSONIC,
USB_DEVICE_ID_VIEWSONIC_PD1011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SIGNOTEC,
USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011) },
{ }
};
MODULE_DEVICE_TABLE(hid, viewsonic_devices);
static struct hid_driver viewsonic_driver = {
.name = "viewsonic",
.id_table = viewsonic_devices,
.report_fixup = viewsonic_report_fixup,
};
module_hid_driver(viewsonic_driver);
MODULE_LICENSE("GPL");
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) #define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
#define I2C_HID_QUIRK_NO_RUNTIME_PM BIT(2) #define I2C_HID_QUIRK_NO_RUNTIME_PM BIT(2)
#define I2C_HID_QUIRK_DELAY_AFTER_SLEEP BIT(3) #define I2C_HID_QUIRK_DELAY_AFTER_SLEEP BIT(3)
#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4)
/* flags */ /* flags */
#define I2C_HID_STARTED 0 #define I2C_HID_STARTED 0
...@@ -181,6 +182,8 @@ static const struct i2c_hid_quirks { ...@@ -181,6 +182,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_NO_RUNTIME_PM }, I2C_HID_QUIRK_NO_RUNTIME_PM },
{ I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_01F0, { I2C_VENDOR_ID_GOODIX, I2C_DEVICE_ID_GOODIX_01F0,
I2C_HID_QUIRK_NO_RUNTIME_PM }, I2C_HID_QUIRK_NO_RUNTIME_PM },
{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
I2C_HID_QUIRK_BOGUS_IRQ },
{ 0, 0 } { 0, 0 }
}; };
...@@ -505,6 +508,12 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) ...@@ -505,6 +508,12 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
return; return;
} }
if (ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ && ret_size == 0xffff) {
dev_warn_once(&ihid->client->dev, "%s: IRQ triggered but "
"there's no data\n", __func__);
return;
}
if ((ret_size > size) || (ret_size < 2)) { if ((ret_size > size) || (ret_size < 2)) {
dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
__func__, size, ret_size); __func__, size, ret_size);
......
...@@ -91,7 +91,10 @@ static bool check_generated_interrupt(struct ishtp_device *dev) ...@@ -91,7 +91,10 @@ static bool check_generated_interrupt(struct ishtp_device *dev)
IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val); IPC_INT_FROM_ISH_TO_HOST_CHV_AB(pisr_val);
} else { } else {
pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT); pisr_val = ish_reg_read(dev, IPC_REG_PISR_BXT);
interrupt_generated = IPC_INT_FROM_ISH_TO_HOST_BXT(pisr_val); interrupt_generated = !!pisr_val;
/* only busy-clear bit is RW, others are RO */
if (pisr_val)
ish_reg_write(dev, IPC_REG_PISR_BXT, pisr_val);
} }
return interrupt_generated; return interrupt_generated;
...@@ -256,33 +259,22 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -256,33 +259,22 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
int i; int i;
void (*ipc_send_compl)(void *); void (*ipc_send_compl)(void *);
void *ipc_send_compl_prm; void *ipc_send_compl_prm;
static int out_ipc_locked;
unsigned long out_ipc_flags;
if (dev->dev_state == ISHTP_DEV_DISABLED) if (dev->dev_state == ISHTP_DEV_DISABLED)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&dev->out_ipc_spinlock, out_ipc_flags); spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
if (out_ipc_locked) {
spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
return -EBUSY;
}
out_ipc_locked = 1;
if (!ish_is_input_ready(dev)) { if (!ish_is_input_ready(dev)) {
out_ipc_locked = 0; spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
return -EBUSY; return -EBUSY;
} }
spin_unlock_irqrestore(&dev->out_ipc_spinlock, out_ipc_flags);
spin_lock_irqsave(&dev->wr_processing_spinlock, flags);
/* /*
* if tx send list is empty - return 0; * if tx send list is empty - return 0;
* may happen, as RX_COMPLETE handler doesn't check list emptiness. * may happen, as RX_COMPLETE handler doesn't check list emptiness.
*/ */
if (list_empty(&dev->wr_processing_list)) { if (list_empty(&dev->wr_processing_list)) {
spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags); spin_unlock_irqrestore(&dev->wr_processing_spinlock, flags);
out_ipc_locked = 0;
return 0; return 0;
} }
...@@ -325,6 +317,8 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -325,6 +317,8 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
memcpy(&reg, &r_buf[length >> 2], rem); memcpy(&reg, &r_buf[length >> 2], rem);
ish_reg_write(dev, reg_addr, reg); ish_reg_write(dev, reg_addr, reg);
} }
ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
/* Flush writes to msg registers and doorbell */ /* Flush writes to msg registers and doorbell */
ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS); ish_reg_read(dev, IPC_REG_ISH_HOST_FWSTS);
...@@ -332,9 +326,6 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -332,9 +326,6 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
++dev->ipc_tx_cnt; ++dev->ipc_tx_cnt;
dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val); dev->ipc_tx_bytes_cnt += IPC_HEADER_GET_LENGTH(doorbell_val);
ish_reg_write(dev, IPC_REG_HOST2ISH_DRBL, doorbell_val);
out_ipc_locked = 0;
ipc_send_compl = ipc_link->ipc_send_compl; ipc_send_compl = ipc_link->ipc_send_compl;
ipc_send_compl_prm = ipc_link->ipc_send_compl_prm; ipc_send_compl_prm = ipc_link->ipc_send_compl_prm;
list_del_init(&ipc_link->link); list_del_init(&ipc_link->link);
...@@ -839,11 +830,11 @@ int ish_hw_start(struct ishtp_device *dev) ...@@ -839,11 +830,11 @@ int ish_hw_start(struct ishtp_device *dev)
{ {
ish_set_host_rdy(dev); ish_set_host_rdy(dev);
set_host_ready(dev);
/* After that we can enable ISH DMA operation and wakeup ISHFW */ /* After that we can enable ISH DMA operation and wakeup ISHFW */
ish_wakeup(dev); ish_wakeup(dev);
set_host_ready(dev);
/* wait for FW-initiated reset flow */ /* wait for FW-initiated reset flow */
if (!dev->recvd_hw_ready) if (!dev->recvd_hw_ready)
wait_event_interruptible_timeout(dev->wait_hw_ready, wait_event_interruptible_timeout(dev->wait_hw_ready,
...@@ -914,7 +905,6 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev) ...@@ -914,7 +905,6 @@ struct ishtp_device *ish_dev_init(struct pci_dev *pdev)
init_waitqueue_head(&dev->wait_hw_ready); init_waitqueue_head(&dev->wait_hw_ready);
spin_lock_init(&dev->wr_processing_spinlock); spin_lock_init(&dev->wr_processing_spinlock);
spin_lock_init(&dev->out_ipc_spinlock);
/* Init IPC processing and free lists */ /* Init IPC processing and free lists */
INIT_LIST_HEAD(&dev->wr_processing_list); INIT_LIST_HEAD(&dev->wr_processing_list);
......
...@@ -788,8 +788,8 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) ...@@ -788,8 +788,8 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
if (!cl_device) if (!cl_device)
return -ENODEV; return -ENODEV;
if (uuid_le_cmp(hid_ishtp_guid, if (!guid_equal(&hid_ishtp_guid,
cl_device->fw_client->props.protocol_name) != 0) &cl_device->fw_client->props.protocol_name))
return -ENODEV; return -ENODEV;
client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data), client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data),
......
...@@ -206,8 +206,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, ...@@ -206,8 +206,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
hid->bus = BUS_INTEL_ISHTP; hid->bus = BUS_INTEL_ISHTP;
hid->dev.parent = &client_data->cl_device->dev; hid->dev.parent = &client_data->cl_device->dev;
hid->version = le16_to_cpu(ISH_HID_VERSION); hid->version = le16_to_cpu(ISH_HID_VERSION);
hid->vendor = le16_to_cpu(ISH_HID_VENDOR); hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid);
hid->product = le16_to_cpu(ISH_HID_PRODUCT); hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp", snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp",
hid->vendor, hid->product); hid->vendor, hid->product);
......
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
client->cl_device->ishtp_dev, __VA_ARGS__) client->cl_device->ishtp_dev, __VA_ARGS__)
/* ISH Transport protocol (ISHTP in short) GUID */ /* ISH Transport protocol (ISHTP in short) GUID */
static const uuid_le hid_ishtp_guid = UUID_LE(0x33AECD58, 0xB679, 0x4E54, static const guid_t hid_ishtp_guid =
0x9B, 0xD9, 0xA0, 0x4D, 0x34, GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
0xF0, 0xC2, 0x26); 0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26);
/* ISH HID message structure */ /* ISH HID message structure */
struct hostif_msg_hdr { struct hostif_msg_hdr {
......
...@@ -119,7 +119,7 @@ int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr, ...@@ -119,7 +119,7 @@ int ishtp_send_msg(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
* Return: This returns IPC send message status. * Return: This returns IPC send message status.
*/ */
int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr, int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
unsigned char *buf) void *buf)
{ {
return ishtp_send_msg(dev, hdr, buf, NULL, NULL); return ishtp_send_msg(dev, hdr, buf, NULL, NULL);
} }
...@@ -133,18 +133,15 @@ int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr, ...@@ -133,18 +133,15 @@ int ishtp_write_message(struct ishtp_device *dev, struct ishtp_msg_hdr *hdr,
* *
* Return: fw client index or -ENOENT if not found * Return: fw client index or -ENOENT if not found
*/ */
int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *uuid) int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *uuid)
{ {
int i, res = -ENOENT; unsigned int i;
for (i = 0; i < dev->fw_clients_num; ++i) { for (i = 0; i < dev->fw_clients_num; ++i) {
if (uuid_le_cmp(*uuid, dev->fw_clients[i].props.protocol_name) if (guid_equal(uuid, &dev->fw_clients[i].props.protocol_name))
== 0) { return i;
res = i;
break;
} }
} return -ENOENT;
return res;
} }
EXPORT_SYMBOL(ishtp_fw_cl_by_uuid); EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
...@@ -158,7 +155,7 @@ EXPORT_SYMBOL(ishtp_fw_cl_by_uuid); ...@@ -158,7 +155,7 @@ EXPORT_SYMBOL(ishtp_fw_cl_by_uuid);
* Return: pointer of client information on success, NULL on failure. * Return: pointer of client information on success, NULL on failure.
*/ */
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev, struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
const uuid_le *uuid) const guid_t *uuid)
{ {
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -401,7 +398,7 @@ static const struct device_type ishtp_cl_device_type = { ...@@ -401,7 +398,7 @@ static const struct device_type ishtp_cl_device_type = {
* Return: ishtp_cl_device pointer or NULL on failure * Return: ishtp_cl_device pointer or NULL on failure
*/ */
static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev, static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
uuid_le uuid, char *name) guid_t uuid, char *name)
{ {
struct ishtp_cl_device *device; struct ishtp_cl_device *device;
int status; int status;
...@@ -629,7 +626,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev) ...@@ -629,7 +626,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev)
int i; int i;
char *dev_name; char *dev_name;
struct ishtp_cl_device *cl_device; struct ishtp_cl_device *cl_device;
uuid_le device_uuid; guid_t device_uuid;
/* /*
* For all reported clients, create an unconnected client and add its * For all reported clients, create an unconnected client and add its
...@@ -639,7 +636,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev) ...@@ -639,7 +636,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev)
*/ */
i = dev->fw_client_presentation_num - 1; i = dev->fw_client_presentation_num - 1;
device_uuid = dev->fw_clients[i].props.protocol_name; device_uuid = dev->fw_clients[i].props.protocol_name;
dev_name = kasprintf(GFP_KERNEL, "{%pUL}", device_uuid.b); dev_name = kasprintf(GFP_KERNEL, "{%pUL}", &device_uuid);
if (!dev_name) if (!dev_name)
return -ENOMEM; return -ENOMEM;
...@@ -675,7 +672,8 @@ int ishtp_cl_device_bind(struct ishtp_cl *cl) ...@@ -675,7 +672,8 @@ int ishtp_cl_device_bind(struct ishtp_cl *cl)
spin_lock_irqsave(&cl->dev->device_list_lock, flags); spin_lock_irqsave(&cl->dev->device_list_lock, flags);
list_for_each_entry(cl_device, &cl->dev->device_list, list_for_each_entry(cl_device, &cl->dev->device_list,
device_link) { device_link) {
if (cl_device->fw_client->client_id == cl->fw_client_id) { if (cl_device->fw_client &&
cl_device->fw_client->client_id == cl->fw_client_id) {
cl->device = cl_device; cl->device = cl_device;
rv = 0; rv = 0;
break; break;
...@@ -735,6 +733,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev, ...@@ -735,6 +733,7 @@ void ishtp_bus_remove_all_clients(struct ishtp_device *ishtp_dev,
spin_lock_irqsave(&ishtp_dev->device_list_lock, flags); spin_lock_irqsave(&ishtp_dev->device_list_lock, flags);
list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list, list_for_each_entry_safe(cl_device, n, &ishtp_dev->device_list,
device_link) { device_link) {
cl_device->fw_client = NULL;
if (warm_reset && cl_device->reference_count) if (warm_reset && cl_device->reference_count)
continue; continue;
......
...@@ -85,7 +85,7 @@ int ishtp_send_msg(struct ishtp_device *dev, ...@@ -85,7 +85,7 @@ int ishtp_send_msg(struct ishtp_device *dev,
/* Write a single-fragment message */ /* Write a single-fragment message */
int ishtp_write_message(struct ishtp_device *dev, int ishtp_write_message(struct ishtp_device *dev,
struct ishtp_msg_hdr *hdr, struct ishtp_msg_hdr *hdr,
unsigned char *buf); void *buf);
/* Use DMA to send/receive messages */ /* Use DMA to send/receive messages */
int ishtp_use_dma_transfer(void); int ishtp_use_dma_transfer(void);
...@@ -112,8 +112,8 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver); ...@@ -112,8 +112,8 @@ void ishtp_cl_driver_unregister(struct ishtp_cl_driver *driver);
int ishtp_register_event_cb(struct ishtp_cl_device *device, int ishtp_register_event_cb(struct ishtp_cl_device *device,
void (*read_cb)(struct ishtp_cl_device *)); void (*read_cb)(struct ishtp_cl_device *));
int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const uuid_le *cuuid); int ishtp_fw_cl_by_uuid(struct ishtp_device *dev, const guid_t *cuuid);
struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev, struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
const uuid_le *uuid); const guid_t *uuid);
#endif /* _LINUX_ISHTP_CL_BUS_H */ #endif /* _LINUX_ISHTP_CL_BUS_H */
...@@ -126,7 +126,7 @@ struct ishtp_cl { ...@@ -126,7 +126,7 @@ struct ishtp_cl {
}; };
/* Client connection managenment internal functions */ /* Client connection managenment internal functions */
int ishtp_can_client_connect(struct ishtp_device *ishtp_dev, uuid_le *uuid); int ishtp_can_client_connect(struct ishtp_device *ishtp_dev, guid_t *uuid);
int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id); int ishtp_fw_cl_by_id(struct ishtp_device *dev, uint8_t client_id);
void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl); void ishtp_cl_send_msg(struct ishtp_device *dev, struct ishtp_cl *cl);
void recv_ishtp_cl_msg(struct ishtp_device *dev, void recv_ishtp_cl_msg(struct ishtp_device *dev,
......
...@@ -136,19 +136,14 @@ int ishtp_hbm_start_wait(struct ishtp_device *dev) ...@@ -136,19 +136,14 @@ int ishtp_hbm_start_wait(struct ishtp_device *dev)
int ishtp_hbm_start_req(struct ishtp_device *dev) int ishtp_hbm_start_req(struct ishtp_device *dev)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_host_version_request start_req = { 0 };
struct ishtp_msg_hdr *ishtp_hdr = &hdr;
struct hbm_host_version_request *start_req;
const size_t len = sizeof(struct hbm_host_version_request);
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, sizeof(start_req));
/* host start message */ /* host start message */
start_req = (struct hbm_host_version_request *)data; start_req.hbm_cmd = HOST_START_REQ_CMD;
memset(start_req, 0, len); start_req.host_version.major_version = HBM_MAJOR_VERSION;
start_req->hbm_cmd = HOST_START_REQ_CMD; start_req.host_version.minor_version = HBM_MINOR_VERSION;
start_req->host_version.major_version = HBM_MAJOR_VERSION;
start_req->host_version.minor_version = HBM_MINOR_VERSION;
/* /*
* (!) Response to HBM start may be so quick that this thread would get * (!) Response to HBM start may be so quick that this thread would get
...@@ -156,7 +151,7 @@ int ishtp_hbm_start_req(struct ishtp_device *dev) ...@@ -156,7 +151,7 @@ int ishtp_hbm_start_req(struct ishtp_device *dev)
* So set it at first, change back to ISHTP_HBM_IDLE upon failure * So set it at first, change back to ISHTP_HBM_IDLE upon failure
*/ */
dev->hbm_state = ISHTP_HBM_START; dev->hbm_state = ISHTP_HBM_START;
if (ishtp_write_message(dev, ishtp_hdr, data)) { if (ishtp_write_message(dev, &hdr, &start_req)) {
dev_err(dev->devc, "version message send failed\n"); dev_err(dev->devc, "version message send failed\n");
dev->dev_state = ISHTP_DEV_RESETTING; dev->dev_state = ISHTP_DEV_RESETTING;
dev->hbm_state = ISHTP_HBM_IDLE; dev->hbm_state = ISHTP_HBM_IDLE;
...@@ -178,19 +173,13 @@ int ishtp_hbm_start_req(struct ishtp_device *dev) ...@@ -178,19 +173,13 @@ int ishtp_hbm_start_req(struct ishtp_device *dev)
void ishtp_hbm_enum_clients_req(struct ishtp_device *dev) void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_host_enum_request enum_req = { 0 };
struct ishtp_msg_hdr *ishtp_hdr = &hdr;
struct hbm_host_enum_request *enum_req;
const size_t len = sizeof(struct hbm_host_enum_request);
/* enumerate clients */ /* enumerate clients */
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, sizeof(enum_req));
enum_req.hbm_cmd = HOST_ENUM_REQ_CMD;
enum_req = (struct hbm_host_enum_request *)data; if (ishtp_write_message(dev, &hdr, &enum_req)) {
memset(enum_req, 0, len);
enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
if (ishtp_write_message(dev, ishtp_hdr, data)) {
dev->dev_state = ISHTP_DEV_RESETTING; dev->dev_state = ISHTP_DEV_RESETTING;
dev_err(dev->devc, "enumeration request send failed\n"); dev_err(dev->devc, "enumeration request send failed\n");
ish_hw_reset(dev); ish_hw_reset(dev);
...@@ -208,12 +197,8 @@ void ishtp_hbm_enum_clients_req(struct ishtp_device *dev) ...@@ -208,12 +197,8 @@ void ishtp_hbm_enum_clients_req(struct ishtp_device *dev)
*/ */
static int ishtp_hbm_prop_req(struct ishtp_device *dev) static int ishtp_hbm_prop_req(struct ishtp_device *dev)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_props_request prop_req = { 0 };
struct ishtp_msg_hdr *ishtp_hdr = &hdr;
struct hbm_props_request *prop_req;
const size_t len = sizeof(struct hbm_props_request);
unsigned long next_client_index; unsigned long next_client_index;
uint8_t client_num; uint8_t client_num;
...@@ -237,15 +222,12 @@ static int ishtp_hbm_prop_req(struct ishtp_device *dev) ...@@ -237,15 +222,12 @@ static int ishtp_hbm_prop_req(struct ishtp_device *dev)
dev->fw_clients[client_num].client_id = next_client_index; dev->fw_clients[client_num].client_id = next_client_index;
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, sizeof(prop_req));
prop_req = (struct hbm_props_request *)data;
memset(prop_req, 0, sizeof(struct hbm_props_request)); prop_req.hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
prop_req.address = next_client_index;
prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; if (ishtp_write_message(dev, &hdr, &prop_req)) {
prop_req->address = next_client_index;
if (ishtp_write_message(dev, ishtp_hdr, data)) {
dev->dev_state = ISHTP_DEV_RESETTING; dev->dev_state = ISHTP_DEV_RESETTING;
dev_err(dev->devc, "properties request send failed\n"); dev_err(dev->devc, "properties request send failed\n");
ish_hw_reset(dev); ish_hw_reset(dev);
...@@ -266,19 +248,14 @@ static int ishtp_hbm_prop_req(struct ishtp_device *dev) ...@@ -266,19 +248,14 @@ static int ishtp_hbm_prop_req(struct ishtp_device *dev)
static void ishtp_hbm_stop_req(struct ishtp_device *dev) static void ishtp_hbm_stop_req(struct ishtp_device *dev)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_host_stop_request stop_req = { 0 } ;
struct ishtp_msg_hdr *ishtp_hdr = &hdr;
struct hbm_host_stop_request *req;
const size_t len = sizeof(struct hbm_host_stop_request);
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, sizeof(stop_req));
req = (struct hbm_host_stop_request *)data;
memset(req, 0, sizeof(struct hbm_host_stop_request)); stop_req.hbm_cmd = HOST_STOP_REQ_CMD;
req->hbm_cmd = HOST_STOP_REQ_CMD; stop_req.reason = DRIVER_STOP_REQUEST;
req->reason = DRIVER_STOP_REQUEST;
ishtp_write_message(dev, ishtp_hdr, data); ishtp_write_message(dev, &hdr, &stop_req);
} }
/** /**
...@@ -294,15 +271,15 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, ...@@ -294,15 +271,15 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
struct ishtp_cl *cl) struct ishtp_cl *cl)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_flow_control flow_ctrl;
struct ishtp_msg_hdr *ishtp_hdr = &hdr; const size_t len = sizeof(flow_ctrl);
const size_t len = sizeof(struct hbm_flow_control);
int rv; int rv;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&cl->fc_spinlock, flags); spin_lock_irqsave(&cl->fc_spinlock, flags);
ishtp_hbm_hdr(ishtp_hdr, len);
ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, data, len); ishtp_hbm_hdr(&hdr, len);
ishtp_hbm_cl_hdr(cl, ISHTP_FLOW_CONTROL_CMD, &flow_ctrl, len);
/* /*
* Sync possible race when RB recycle and packet receive paths * Sync possible race when RB recycle and packet receive paths
...@@ -315,7 +292,7 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, ...@@ -315,7 +292,7 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
cl->recv_msg_num_frags = 0; cl->recv_msg_num_frags = 0;
rv = ishtp_write_message(dev, ishtp_hdr, data); rv = ishtp_write_message(dev, &hdr, &flow_ctrl);
if (!rv) { if (!rv) {
++cl->out_flow_ctrl_creds; ++cl->out_flow_ctrl_creds;
++cl->out_flow_ctrl_cnt; ++cl->out_flow_ctrl_cnt;
...@@ -345,14 +322,13 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev, ...@@ -345,14 +322,13 @@ int ishtp_hbm_cl_flow_control_req(struct ishtp_device *dev,
int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl) int ishtp_hbm_cl_disconnect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_client_connect_request disconn_req;
struct ishtp_msg_hdr *ishtp_hdr = &hdr; const size_t len = sizeof(disconn_req);
const size_t len = sizeof(struct hbm_client_connect_request);
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, len);
ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, data, len); ishtp_hbm_cl_hdr(cl, CLIENT_DISCONNECT_REQ_CMD, &disconn_req, len);
return ishtp_write_message(dev, ishtp_hdr, data); return ishtp_write_message(dev, &hdr, &disconn_req);
} }
/** /**
...@@ -391,14 +367,13 @@ static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev, ...@@ -391,14 +367,13 @@ static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl) int ishtp_hbm_cl_connect_req(struct ishtp_device *dev, struct ishtp_cl *cl)
{ {
struct ishtp_msg_hdr hdr; struct ishtp_msg_hdr hdr;
unsigned char data[128]; struct hbm_client_connect_request conn_req;
struct ishtp_msg_hdr *ishtp_hdr = &hdr; const size_t len = sizeof(conn_req);
const size_t len = sizeof(struct hbm_client_connect_request);
ishtp_hbm_hdr(ishtp_hdr, len); ishtp_hbm_hdr(&hdr, len);
ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, data, len); ishtp_hbm_cl_hdr(cl, CLIENT_CONNECT_REQ_CMD, &conn_req, len);
return ishtp_write_message(dev, ishtp_hdr, data); return ishtp_write_message(dev, &hdr, &conn_req);
} }
/** /**
......
...@@ -149,7 +149,7 @@ struct hbm_host_enum_response { ...@@ -149,7 +149,7 @@ struct hbm_host_enum_response {
} __packed; } __packed;
struct ishtp_client_properties { struct ishtp_client_properties {
uuid_le protocol_name; guid_t protocol_name;
uint8_t protocol_version; uint8_t protocol_version;
uint8_t max_number_of_connections; uint8_t max_number_of_connections;
uint8_t fixed_address; uint8_t fixed_address;
......
...@@ -211,8 +211,6 @@ struct ishtp_device { ...@@ -211,8 +211,6 @@ struct ishtp_device {
/* For both processing list and free list */ /* For both processing list and free list */
spinlock_t wr_processing_spinlock; spinlock_t wr_processing_spinlock;
spinlock_t out_ipc_spinlock;
struct ishtp_fw_client *fw_clients; /*Note:memory has to be allocated*/ struct ishtp_fw_client *fw_clients; /*Note:memory has to be allocated*/
DECLARE_BITMAP(fw_clients_map, ISHTP_CLIENTS_MAX); DECLARE_BITMAP(fw_clients_map, ISHTP_CLIENTS_MAX);
DECLARE_BITMAP(host_clients_map, ISHTP_CLIENTS_MAX); DECLARE_BITMAP(host_clients_map, ISHTP_CLIENTS_MAX);
......
...@@ -252,6 +252,38 @@ static void wacom_hid_usage_quirk(struct hid_device *hdev, ...@@ -252,6 +252,38 @@ static void wacom_hid_usage_quirk(struct hid_device *hdev,
} }
} }
/*
* Wacom's AES devices use different vendor-defined usages to
* report serial number information compared to their branded
* hardware. The usages are also sometimes ill-defined and do
* not have the correct logical min/max values set. Lets patch
* the descriptor to use the branded usage convention and fix
* the errors.
*/
if (usage->hid == WACOM_HID_WT_SERIALNUMBER &&
field->report_size == 16 &&
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;
}
}
/* 2nd-generation Intuos Pro Large has incorrect Y maximum */ /* 2nd-generation Intuos Pro Large has incorrect Y maximum */
if (hdev->vendor == USB_VENDOR_ID_WACOM && if (hdev->vendor == USB_VENDOR_ID_WACOM &&
hdev->product == 0x0358 && hdev->product == 0x0358 &&
......
...@@ -626,6 +626,7 @@ static int wacom_intuos_get_tool_type(int tool_id) ...@@ -626,6 +626,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
case 0x8e2: /* IntuosHT2 pen */ case 0x8e2: /* IntuosHT2 pen */
case 0x022: case 0x022:
case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */
case 0x10842: /* MobileStudio Pro Pro Pen slim */
case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */
case 0x16802: /* Cintiq 13HD Pro Pen */ case 0x16802: /* Cintiq 13HD Pro Pen */
case 0x18802: /* DTH2242 Pen */ case 0x18802: /* DTH2242 Pen */
...@@ -667,6 +668,7 @@ static int wacom_intuos_get_tool_type(int tool_id) ...@@ -667,6 +668,7 @@ static int wacom_intuos_get_tool_type(int tool_id)
case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */ case 0x1480a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */ case 0x1090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */ case 0x1080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
case 0x1084a: /* MobileStudio Pro Pro Pen slim Eraser */
case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */ case 0x1680a: /* Cintiq 13HD Pro Pen Eraser */
case 0x1880a: /* DTH2242 Eraser */ case 0x1880a: /* DTH2242 Eraser */
case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */ case 0x1080a: /* Intuos4/5 13HD/24HD General Pen Eraser */
...@@ -2159,27 +2161,6 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, ...@@ -2159,27 +2161,6 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
case HID_DG_TOOLSERIALNUMBER: case HID_DG_TOOLSERIALNUMBER:
features->quirks |= WACOM_QUIRK_TOOLSERIAL; features->quirks |= WACOM_QUIRK_TOOLSERIAL;
wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0); wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0);
/* Adjust AES usages to match modern convention */
if (usage->hid == WACOM_HID_WT_SERIALNUMBER && field->report_size == 16) {
if (field->index + 2 < field->report->maxfield) {
struct hid_field *a = field->report->field[field->index + 1];
struct hid_field *b = field->report->field[field->index + 2];
if (a->maxusage > 0 && a->usage[0].hid == HID_DG_TOOLSERIALNUMBER && a->report_size == 32 &&
b->maxusage > 0 && b->usage[0].hid == 0xFF000000 && b->report_size == 8) {
features->quirks |= WACOM_QUIRK_AESPEN;
usage->hid = WACOM_HID_WD_TOOLTYPE;
field->logical_minimum = S16_MIN;
field->logical_maximum = S16_MAX;
a->logical_minimum = S32_MIN;
a->logical_maximum = S32_MAX;
b->usage[0].hid = WACOM_HID_WD_SERIALHI;
b->logical_minimum = 0;
b->logical_maximum = U8_MAX;
}
}
}
break; break;
case WACOM_HID_WD_SENSE: case WACOM_HID_WD_SENSE:
features->quirks |= WACOM_QUIRK_SENSE; features->quirks |= WACOM_QUIRK_SENSE;
...@@ -3525,6 +3506,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, ...@@ -3525,6 +3506,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev,
switch (features->type) { switch (features->type) {
case GRAPHIRE_BT: case GRAPHIRE_BT:
__clear_bit(ABS_MISC, input_dev->absbit); __clear_bit(ABS_MISC, input_dev->absbit);
/* fall through */
case WACOM_MO: case WACOM_MO:
case WACOM_G4: case WACOM_G4:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment