Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - Valve Steam Controller support from Rodrigo Rivas Costa - Redragon Asura support from Robert Munteanu - improvement of duplicate usage handling in generic hid-input from Benjamin Tissoires - Win 8.1 precisioun touchpad spec implementation from Benjamin Tissoires - Support for "In Range" flag for Wacom Intuos/Bamboo devices from Jason Gerecke - other various assorted smaller fixes and improvements * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (27 commits) HID: rmi: use HID_QUIRK_NO_INPUT_SYNC HID: multitouch: fix calculation of last slot field in multi-touch reports HID: quirks: remove Delcom Visual Signal Indicator from hid_have_special_driver[] HID: steam: select CONFIG_POWER_SUPPLY HID: i2c-hid: remove i2c_hid_open_mut HID: wacom: Support "in range" for Intuos/Bamboo tablets where possible HID: core: fix hid_hw_open() comment HID: hid-plantronics: Re-resend Update to map button for PTT products HID: multitouch: fix types returned from mt_need_to_apply_feature() HID: i2c-hid: check if device is there before really probing HID: steam: add missing fields in client initialization HID: steam: add battery device. HID: add driver for Valve Steam Controller HID: alps: Fix some style in 't4_read_write_register()' HID: alps: Check errors returned by 't4_read_write_register()' HID: alps: Save a memory allocation in 't4_read_write_register()' when writing data HID: alps: Report an error if we receive invalid data in 't4_read_write_register()' HID: multitouch: implement precision touchpad latency and switches HID: multitouch: simplify the settings of the various features HID: multitouch: make use of HID_QUIRK_INPUT_PER_APP ...
This commit is contained in:
commit
fdea70d26a
|
@ -575,6 +575,13 @@ config HID_MAYFLASH
|
|||
Say Y here if you have HJZ Mayflash PS3 game controller adapters
|
||||
and want to enable force feedback support.
|
||||
|
||||
config HID_REDRAGON
|
||||
tristate "Redragon keyboards"
|
||||
depends on HID
|
||||
default !EXPERT
|
||||
---help---
|
||||
Support for Redragon keyboards that need fix-ups to work properly.
|
||||
|
||||
config HID_MICROSOFT
|
||||
tristate "Microsoft non-fully HID-compliant devices"
|
||||
depends on HID
|
||||
|
@ -838,6 +845,15 @@ config HID_SPEEDLINK
|
|||
---help---
|
||||
Support for Speedlink Vicious and Divine Cezanne mouse.
|
||||
|
||||
config HID_STEAM
|
||||
tristate "Steam Controller support"
|
||||
depends on HID
|
||||
select POWER_SUPPLY
|
||||
---help---
|
||||
Say Y here if you have a Steam Controller if you want to use it
|
||||
without running the Steam Client. It supports both the wired and
|
||||
the wireless adaptor.
|
||||
|
||||
config HID_STEELSERIES
|
||||
tristate "Steelseries SRW-S1 steering wheel support"
|
||||
depends on HID
|
||||
|
|
|
@ -86,6 +86,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
|
|||
|
||||
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
|
||||
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
|
||||
obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o
|
||||
obj-$(CONFIG_HID_RETRODE) += hid-retrode.o
|
||||
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
|
||||
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
|
||||
|
@ -97,6 +98,7 @@ obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
|
|||
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
|
||||
obj-$(CONFIG_HID_SONY) += hid-sony.o
|
||||
obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
|
||||
obj-$(CONFIG_HID_STEAM) += hid-steam.o
|
||||
obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o
|
||||
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
|
||||
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
|
||||
|
|
|
@ -171,7 +171,7 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address,
|
|||
int ret;
|
||||
u16 check_sum;
|
||||
u8 *input;
|
||||
u8 *readbuf;
|
||||
u8 *readbuf = NULL;
|
||||
|
||||
input = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL);
|
||||
if (!input)
|
||||
|
@ -204,8 +204,8 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL);
|
||||
if (read_flag) {
|
||||
readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL);
|
||||
if (!readbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
|
@ -219,22 +219,24 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address,
|
|||
goto exit_readbuf;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
if (*(u32 *)&readbuf[6] != address) {
|
||||
dev_err(&hdev->dev, "read register address error (%x,%x)\n",
|
||||
*(u32 *)&readbuf[6], address);
|
||||
*(u32 *)&readbuf[6], address);
|
||||
goto exit_readbuf;
|
||||
}
|
||||
|
||||
if (*(u16 *)&readbuf[10] != 1) {
|
||||
dev_err(&hdev->dev, "read register size error (%x)\n",
|
||||
*(u16 *)&readbuf[10]);
|
||||
*(u16 *)&readbuf[10]);
|
||||
goto exit_readbuf;
|
||||
}
|
||||
|
||||
check_sum = t4_calc_check_sum(readbuf, 6, 7);
|
||||
if (*(u16 *)&readbuf[13] != check_sum) {
|
||||
dev_err(&hdev->dev, "read register checksum error (%x,%x)\n",
|
||||
*(u16 *)&readbuf[13], check_sum);
|
||||
*(u16 *)&readbuf[13], check_sum);
|
||||
goto exit_readbuf;
|
||||
}
|
||||
|
||||
|
@ -458,17 +460,35 @@ static int __maybe_unused alps_post_reset(struct hid_device *hdev)
|
|||
case T4:
|
||||
ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1,
|
||||
NULL, T4_I2C_ABS, false);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4,
|
||||
NULL, T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
case U1:
|
||||
ret = u1_read_write_register(hdev,
|
||||
ADDRESS_U1_DEV_CTRL_1, NULL,
|
||||
U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
|
||||
if (ret < 0) {
|
||||
dev_err(&hdev->dev, "failed to change TP mode (%d)\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
|
|||
* Register a new report for a device.
|
||||
*/
|
||||
|
||||
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
|
||||
struct hid_report *hid_register_report(struct hid_device *device,
|
||||
unsigned int type, unsigned int id,
|
||||
unsigned int application)
|
||||
{
|
||||
struct hid_report_enum *report_enum = device->report_enum + type;
|
||||
struct hid_report *report;
|
||||
|
@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
|
|||
report->type = type;
|
||||
report->size = 0;
|
||||
report->device = device;
|
||||
report->application = application;
|
||||
report_enum->report_id_hash[id] = report;
|
||||
|
||||
list_add_tail(&report->list, &report_enum->report_list);
|
||||
|
@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
|||
{
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
unsigned usages;
|
||||
unsigned offset;
|
||||
unsigned i;
|
||||
unsigned int usages;
|
||||
unsigned int offset;
|
||||
unsigned int i;
|
||||
unsigned int application;
|
||||
|
||||
report = hid_register_report(parser->device, report_type, parser->global.report_id);
|
||||
application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
|
||||
|
||||
report = hid_register_report(parser->device, report_type,
|
||||
parser->global.report_id, application);
|
||||
if (!report) {
|
||||
hid_err(parser->device, "hid_register_report failed\n");
|
||||
return -1;
|
||||
|
@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
|
|||
|
||||
field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
|
||||
field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
|
||||
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
|
||||
field->application = application;
|
||||
|
||||
for (i = 0; i < usages; i++) {
|
||||
unsigned j = i;
|
||||
|
@ -1798,7 +1805,7 @@ EXPORT_SYMBOL_GPL(hid_hw_stop);
|
|||
*
|
||||
* Tell underlying HW to start delivering events from the device.
|
||||
* This function should be called sometime after successful call
|
||||
* to hid_hiw_start().
|
||||
* to hid_hw_start().
|
||||
*/
|
||||
int hid_hw_open(struct hid_device *hdev)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev,
|
|||
return true;
|
||||
}
|
||||
|
||||
static int hid_generic_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
}
|
||||
|
||||
static const struct hid_device_id hid_table[] = {
|
||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
|
||||
{ }
|
||||
|
@ -66,6 +80,7 @@ static struct hid_driver hid_generic = {
|
|||
.name = "hid-generic",
|
||||
.id_table = hid_table,
|
||||
.match = hid_generic_match,
|
||||
.probe = hid_generic_probe,
|
||||
};
|
||||
module_hid_driver(hid_generic);
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
* those reports reach gfrm_raw_event() from hid_input_report().
|
||||
*/
|
||||
if (!hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
GFRM100_SEARCH_KEY_REPORT_ID)) {
|
||||
GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -615,6 +615,7 @@
|
|||
#define USB_VENDOR_ID_JESS 0x0c45
|
||||
#define USB_DEVICE_ID_JESS_YUREX 0x1010
|
||||
#define USB_DEVICE_ID_ASUS_MD_5112 0x5112
|
||||
#define USB_DEVICE_ID_REDRAGON_ASURA 0x760b
|
||||
|
||||
#define USB_VENDOR_ID_JESS2 0x0f30
|
||||
#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111
|
||||
|
@ -1012,6 +1013,10 @@
|
|||
#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403
|
||||
#define USB_DEVICE_ID_MTP_SITRONIX 0x5001
|
||||
|
||||
#define USB_VENDOR_ID_VALVE 0x28de
|
||||
#define USB_DEVICE_ID_STEAM_CONTROLLER 0x1102
|
||||
#define USB_DEVICE_ID_STEAM_CONTROLLER_WIRELESS 0x1142
|
||||
|
||||
#define USB_VENDOR_ID_STEELSERIES 0x1038
|
||||
#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410
|
||||
|
||||
|
|
|
@ -1110,8 +1110,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|||
|
||||
set_bit(usage->type, input->evbit);
|
||||
|
||||
while (usage->code <= max && test_and_set_bit(usage->code, bit))
|
||||
usage->code = find_next_zero_bit(bit, max + 1, usage->code);
|
||||
/*
|
||||
* This part is *really* controversial:
|
||||
* - HID aims at being generic so we should do our best to export
|
||||
* all incoming events
|
||||
* - HID describes what events are, so there is no reason for ABS_X
|
||||
* to be mapped to ABS_Y
|
||||
* - HID is using *_MISC+N as a default value, but nothing prevents
|
||||
* *_MISC+N to overwrite a legitimate even, which confuses userspace
|
||||
* (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different
|
||||
* processing)
|
||||
*
|
||||
* If devices still want to use this (at their own risk), they will
|
||||
* have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but
|
||||
* the default should be a reliable mapping.
|
||||
*/
|
||||
while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
|
||||
if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) {
|
||||
usage->code = find_next_zero_bit(bit,
|
||||
max + 1,
|
||||
usage->code);
|
||||
} else {
|
||||
device->status |= HID_STAT_DUP_DETECTED;
|
||||
goto ignore;
|
||||
}
|
||||
}
|
||||
|
||||
if (usage->code > max)
|
||||
goto ignore;
|
||||
|
@ -1487,15 +1510,56 @@ static void report_features(struct hid_device *hid)
|
|||
}
|
||||
}
|
||||
|
||||
static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
||||
static struct hid_input *hidinput_allocate(struct hid_device *hid,
|
||||
unsigned int application)
|
||||
{
|
||||
struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
|
||||
struct input_dev *input_dev = input_allocate_device();
|
||||
if (!hidinput || !input_dev) {
|
||||
kfree(hidinput);
|
||||
input_free_device(input_dev);
|
||||
hid_err(hid, "Out of memory during hid input probe\n");
|
||||
return NULL;
|
||||
const char *suffix = NULL;
|
||||
|
||||
if (!hidinput || !input_dev)
|
||||
goto fail;
|
||||
|
||||
if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) &&
|
||||
hid->maxapplication > 1) {
|
||||
switch (application) {
|
||||
case HID_GD_KEYBOARD:
|
||||
suffix = "Keyboard";
|
||||
break;
|
||||
case HID_GD_KEYPAD:
|
||||
suffix = "Keypad";
|
||||
break;
|
||||
case HID_GD_MOUSE:
|
||||
suffix = "Mouse";
|
||||
break;
|
||||
case HID_DG_STYLUS:
|
||||
suffix = "Pen";
|
||||
break;
|
||||
case HID_DG_TOUCHSCREEN:
|
||||
suffix = "Touchscreen";
|
||||
break;
|
||||
case HID_DG_TOUCHPAD:
|
||||
suffix = "Touchpad";
|
||||
break;
|
||||
case HID_GD_SYSTEM_CONTROL:
|
||||
suffix = "System Control";
|
||||
break;
|
||||
case HID_CP_CONSUMER_CONTROL:
|
||||
suffix = "Consumer Control";
|
||||
break;
|
||||
case HID_GD_WIRELESS_RADIO_CTLS:
|
||||
suffix = "Wireless Radio Control";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix) {
|
||||
hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
|
||||
hid->name, suffix);
|
||||
if (!hidinput->name)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
input_set_drvdata(input_dev, hid);
|
||||
|
@ -1505,7 +1569,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
|||
input_dev->setkeycode = hidinput_setkeycode;
|
||||
input_dev->getkeycode = hidinput_getkeycode;
|
||||
|
||||
input_dev->name = hid->name;
|
||||
input_dev->name = hidinput->name ? hidinput->name : hid->name;
|
||||
input_dev->phys = hid->phys;
|
||||
input_dev->uniq = hid->uniq;
|
||||
input_dev->id.bustype = hid->bus;
|
||||
|
@ -1513,10 +1577,19 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
|||
input_dev->id.product = hid->product;
|
||||
input_dev->id.version = hid->version;
|
||||
input_dev->dev.parent = &hid->dev;
|
||||
|
||||
hidinput->input = input_dev;
|
||||
list_add_tail(&hidinput->list, &hid->inputs);
|
||||
|
||||
INIT_LIST_HEAD(&hidinput->reports);
|
||||
|
||||
return hidinput;
|
||||
|
||||
fail:
|
||||
kfree(hidinput);
|
||||
input_free_device(input_dev);
|
||||
hid_err(hid, "Out of memory during hid input probe\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hidinput_has_been_populated(struct hid_input *hidinput)
|
||||
|
@ -1562,6 +1635,7 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
|
|||
|
||||
list_del(&hidinput->list);
|
||||
input_free_device(hidinput->input);
|
||||
kfree(hidinput->name);
|
||||
|
||||
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
|
||||
if (k == HID_OUTPUT_REPORT &&
|
||||
|
@ -1594,6 +1668,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct hid_input *hidinput_match_application(struct hid_report *report)
|
||||
{
|
||||
struct hid_device *hid = report->device;
|
||||
struct hid_input *hidinput;
|
||||
|
||||
list_for_each_entry(hidinput, &hid->inputs, list) {
|
||||
if (hidinput->report &&
|
||||
hidinput->report->application == report->application)
|
||||
return hidinput;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void hidinput_configure_usages(struct hid_input *hidinput,
|
||||
struct hid_report *report)
|
||||
{
|
||||
|
@ -1616,11 +1704,14 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
struct hid_driver *drv = hid->driver;
|
||||
struct hid_report *report;
|
||||
struct hid_input *next, *hidinput = NULL;
|
||||
unsigned int application;
|
||||
int i, k;
|
||||
|
||||
INIT_LIST_HEAD(&hid->inputs);
|
||||
INIT_WORK(&hid->led_work, hidinput_led_worker);
|
||||
|
||||
hid->status &= ~HID_STAT_DUP_DETECTED;
|
||||
|
||||
if (!force) {
|
||||
for (i = 0; i < hid->maxcollection; i++) {
|
||||
struct hid_collection *col = &hid->collection[i];
|
||||
|
@ -1646,15 +1737,20 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
if (!report->maxfield)
|
||||
continue;
|
||||
|
||||
application = report->application;
|
||||
|
||||
/*
|
||||
* Find the previous hidinput report attached
|
||||
* to this report id.
|
||||
*/
|
||||
if (hid->quirks & HID_QUIRK_MULTI_INPUT)
|
||||
hidinput = hidinput_match(report);
|
||||
else if (hid->maxapplication > 1 &&
|
||||
(hid->quirks & HID_QUIRK_INPUT_PER_APP))
|
||||
hidinput = hidinput_match_application(report);
|
||||
|
||||
if (!hidinput) {
|
||||
hidinput = hidinput_allocate(hid);
|
||||
hidinput = hidinput_allocate(hid, application);
|
||||
if (!hidinput)
|
||||
goto out_unwind;
|
||||
}
|
||||
|
@ -1663,6 +1759,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
|
||||
if (hid->quirks & HID_QUIRK_MULTI_INPUT)
|
||||
hidinput->report = report;
|
||||
|
||||
list_add_tail(&report->hidinput_list,
|
||||
&hidinput->reports);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1687,6 +1786,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
|||
goto out_unwind;
|
||||
}
|
||||
|
||||
if (hid->status & HID_STAT_DUP_DETECTED)
|
||||
hid_dbg(hid,
|
||||
"Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is legitimate.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_unwind:
|
||||
|
|
|
@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev,
|
|||
|
||||
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
MOUSE_REPORT_ID);
|
||||
MOUSE_REPORT_ID, 0);
|
||||
else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
TRACKPAD_REPORT_ID);
|
||||
TRACKPAD_REPORT_ID, 0);
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
DOUBLE_REPORT_ID);
|
||||
DOUBLE_REPORT_ID, 0);
|
||||
}
|
||||
|
||||
if (!report) {
|
||||
|
|
|
@ -81,6 +81,11 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define MT_BUTTONTYPE_CLICKPAD 0
|
||||
|
||||
enum latency_mode {
|
||||
HID_LATENCY_NORMAL = 0,
|
||||
HID_LATENCY_HIGH = 1,
|
||||
};
|
||||
|
||||
#define MT_IO_FLAGS_RUNNING 0
|
||||
#define MT_IO_FLAGS_ACTIVE_SLOTS 1
|
||||
#define MT_IO_FLAGS_PENDING_SLOTS 2
|
||||
|
@ -127,11 +132,7 @@ struct mt_device {
|
|||
int left_button_state; /* left button state */
|
||||
unsigned last_slot_field; /* the last field of a slot */
|
||||
unsigned mt_report_id; /* the report ID of the multitouch device */
|
||||
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||||
__s16 inputmode_index; /* InputMode HID feature index in the report */
|
||||
__s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
||||
-1 if non-existent */
|
||||
__u8 inputmode_value; /* InputMode HID feature value */
|
||||
__u8 inputmode_value; /* InputMode HID feature value */
|
||||
__u8 num_received; /* how many contacts we received */
|
||||
__u8 num_expected; /* expected last contact index */
|
||||
__u8 maxcontacts;
|
||||
|
@ -415,32 +416,9 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
|||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
|
||||
switch (usage->hid) {
|
||||
case HID_DG_INPUTMODE:
|
||||
/* Ignore if value index is out of bounds. */
|
||||
if (usage->usage_index >= field->report_count) {
|
||||
dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (td->inputmode < 0) {
|
||||
td->inputmode = field->report->id;
|
||||
td->inputmode_index = usage->usage_index;
|
||||
} else {
|
||||
/*
|
||||
* Some elan panels wrongly declare 2 input mode
|
||||
* features, and silently ignore when we set the
|
||||
* value in the second field. Skip the second feature
|
||||
* and hope for the best.
|
||||
*/
|
||||
dev_info(&hdev->dev,
|
||||
"Ignoring the extra HID_DG_INPUTMODE\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case HID_DG_CONTACTMAX:
|
||||
mt_get_feature(hdev, field->report);
|
||||
|
||||
td->maxcontact_report_id = field->report->id;
|
||||
td->maxcontacts = field->value[0];
|
||||
if (!td->maxcontacts &&
|
||||
field->logical_maximum <= MT_MAX_MAXCONTACT)
|
||||
|
@ -620,13 +598,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
hid_map_usage(hi, usage, bit, max,
|
||||
EV_MSC, MSC_TIMESTAMP);
|
||||
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
|
||||
mt_store_field(usage, td, hi);
|
||||
/* Ignore if indexes are out of bounds. */
|
||||
if (field->index >= field->report->maxfield ||
|
||||
usage->usage_index >= field->report_count)
|
||||
return 1;
|
||||
td->scantime_index = field->index;
|
||||
td->scantime_val_index = usage->usage_index;
|
||||
/*
|
||||
* We don't set td->last_slot_field as scan time is
|
||||
* global to the report.
|
||||
*/
|
||||
return 1;
|
||||
case HID_DG_CONTACTCOUNT:
|
||||
/* Ignore if indexes are out of bounds. */
|
||||
|
@ -1181,61 +1162,100 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
|
|||
input_sync(field->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_set_input_mode(struct hid_device *hdev)
|
||||
static bool mt_need_to_apply_feature(struct hid_device *hdev,
|
||||
struct hid_field *field,
|
||||
struct hid_usage *usage,
|
||||
enum latency_mode latency,
|
||||
bool surface_switch,
|
||||
bool button_switch)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct hid_report *r;
|
||||
struct hid_report_enum *re;
|
||||
struct mt_class *cls = &td->mtclass;
|
||||
struct hid_report *report = field->report;
|
||||
unsigned int index = usage->usage_index;
|
||||
char *buf;
|
||||
u32 report_len;
|
||||
int max;
|
||||
|
||||
if (td->inputmode < 0)
|
||||
return;
|
||||
|
||||
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
||||
r = re->report_id_hash[td->inputmode];
|
||||
if (r) {
|
||||
switch (usage->hid) {
|
||||
case HID_DG_INPUTMODE:
|
||||
if (cls->quirks & MT_QUIRK_FORCE_GET_FEATURE) {
|
||||
report_len = hid_report_len(r);
|
||||
buf = hid_alloc_report_buf(r, GFP_KERNEL);
|
||||
report_len = hid_report_len(report);
|
||||
buf = hid_alloc_report_buf(report, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
hid_err(hdev, "failed to allocate buffer for report\n");
|
||||
return;
|
||||
hid_err(hdev,
|
||||
"failed to allocate buffer for report\n");
|
||||
return false;
|
||||
}
|
||||
hid_hw_raw_request(hdev, r->id, buf, report_len,
|
||||
hid_hw_raw_request(hdev, report->id, buf, report_len,
|
||||
HID_FEATURE_REPORT,
|
||||
HID_REQ_GET_REPORT);
|
||||
kfree(buf);
|
||||
}
|
||||
r->field[0]->value[td->inputmode_index] = td->inputmode_value;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
|
||||
field->value[index] = td->inputmode_value;
|
||||
return true;
|
||||
|
||||
case HID_DG_CONTACTMAX:
|
||||
if (td->mtclass.maxcontacts) {
|
||||
max = min_t(int, field->logical_maximum,
|
||||
td->mtclass.maxcontacts);
|
||||
if (field->value[index] != max) {
|
||||
field->value[index] = max;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_DG_LATENCYMODE:
|
||||
field->value[index] = latency;
|
||||
return true;
|
||||
|
||||
case HID_DG_SURFACESWITCH:
|
||||
field->value[index] = surface_switch;
|
||||
return true;
|
||||
|
||||
case HID_DG_BUTTONSWITCH:
|
||||
field->value[index] = button_switch;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; /* no need to update the report */
|
||||
}
|
||||
|
||||
static void mt_set_maxcontacts(struct hid_device *hdev)
|
||||
static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
|
||||
bool surface_switch, bool button_switch)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
struct hid_report *r;
|
||||
struct hid_report_enum *re;
|
||||
int fieldmax, max;
|
||||
struct hid_report_enum *rep_enum;
|
||||
struct hid_report *rep;
|
||||
struct hid_usage *usage;
|
||||
int i, j;
|
||||
bool update_report;
|
||||
|
||||
if (td->maxcontact_report_id < 0)
|
||||
return;
|
||||
rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
|
||||
list_for_each_entry(rep, &rep_enum->report_list, list) {
|
||||
update_report = false;
|
||||
|
||||
if (!td->mtclass.maxcontacts)
|
||||
return;
|
||||
for (i = 0; i < rep->maxfield; i++) {
|
||||
/* Ignore if report count is out of bounds. */
|
||||
if (rep->field[i]->report_count < 1)
|
||||
continue;
|
||||
|
||||
re = &hdev->report_enum[HID_FEATURE_REPORT];
|
||||
r = re->report_id_hash[td->maxcontact_report_id];
|
||||
if (r) {
|
||||
max = td->mtclass.maxcontacts;
|
||||
fieldmax = r->field[0]->logical_maximum;
|
||||
max = min(fieldmax, max);
|
||||
if (r->field[0]->value[0] != max) {
|
||||
r->field[0]->value[0] = max;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
for (j = 0; j < rep->field[i]->maxusage; j++) {
|
||||
usage = &rep->field[i]->usage[j];
|
||||
|
||||
if (mt_need_to_apply_feature(hdev,
|
||||
rep->field[i],
|
||||
usage,
|
||||
latency,
|
||||
surface_switch,
|
||||
button_switch))
|
||||
update_report = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_report)
|
||||
hid_hw_request(hdev, rep, HID_REQ_SET_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,54 +1294,48 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
char *name;
|
||||
const char *suffix = NULL;
|
||||
struct hid_field *field = hi->report->field[0];
|
||||
unsigned int application = 0;
|
||||
struct hid_report *report;
|
||||
int ret;
|
||||
|
||||
if (hi->report->id == td->mt_report_id) {
|
||||
ret = mt_touch_input_configured(hdev, hi);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
list_for_each_entry(report, &hi->reports, hidinput_list) {
|
||||
application = report->application;
|
||||
if (report->id == td->mt_report_id) {
|
||||
ret = mt_touch_input_configured(hdev, hi);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
|
||||
* for the stylus. Check this first, and then rely on the application
|
||||
* field.
|
||||
*/
|
||||
if (hi->report->field[0]->physical == HID_DG_STYLUS) {
|
||||
suffix = "Pen";
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
} else {
|
||||
switch (field->application) {
|
||||
case HID_GD_KEYBOARD:
|
||||
suffix = "Keyboard";
|
||||
break;
|
||||
case HID_GD_KEYPAD:
|
||||
suffix = "Keypad";
|
||||
break;
|
||||
case HID_GD_MOUSE:
|
||||
suffix = "Mouse";
|
||||
break;
|
||||
case HID_DG_STYLUS:
|
||||
/*
|
||||
* some egalax touchscreens have "application == DG_TOUCHSCREEN"
|
||||
* for the stylus. Check this first, and then rely on
|
||||
* the application field.
|
||||
*/
|
||||
if (report->field[0]->physical == HID_DG_STYLUS) {
|
||||
suffix = "Pen";
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
}
|
||||
}
|
||||
|
||||
if (!suffix) {
|
||||
switch (application) {
|
||||
case HID_GD_KEYBOARD:
|
||||
case HID_GD_KEYPAD:
|
||||
case HID_GD_MOUSE:
|
||||
case HID_DG_TOUCHPAD:
|
||||
case HID_GD_SYSTEM_CONTROL:
|
||||
case HID_CP_CONSUMER_CONTROL:
|
||||
case HID_GD_WIRELESS_RADIO_CTLS:
|
||||
/* already handled by hid core */
|
||||
break;
|
||||
case HID_DG_TOUCHSCREEN:
|
||||
/* we do not set suffix = "Touchscreen" */
|
||||
hi->input->name = hdev->name;
|
||||
break;
|
||||
case HID_DG_TOUCHPAD:
|
||||
suffix = "Touchpad";
|
||||
break;
|
||||
case HID_GD_SYSTEM_CONTROL:
|
||||
suffix = "System Control";
|
||||
break;
|
||||
case HID_CP_CONSUMER_CONTROL:
|
||||
suffix = "Consumer Control";
|
||||
break;
|
||||
case HID_GD_WIRELESS_RADIO_CTLS:
|
||||
suffix = "Wireless Radio Control";
|
||||
case HID_DG_STYLUS:
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
break;
|
||||
case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
|
||||
suffix = "Custom Media Keys";
|
||||
|
@ -1434,8 +1448,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
}
|
||||
td->hdev = hdev;
|
||||
td->mtclass = *mtclass;
|
||||
td->inputmode = -1;
|
||||
td->maxcontact_report_id = -1;
|
||||
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
|
||||
td->cc_index = -1;
|
||||
td->scantime_index = -1;
|
||||
|
@ -1459,10 +1471,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
|
||||
/*
|
||||
* This allows the driver to handle different input sensors
|
||||
* that emits events through different reports on the same HID
|
||||
* that emits events through different applications on the same HID
|
||||
* device.
|
||||
*/
|
||||
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
|
||||
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
|
||||
|
||||
timer_setup(&td->release_timer, mt_expired_timeout, 0);
|
||||
|
||||
|
@ -1482,8 +1494,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n",
|
||||
hdev->name);
|
||||
|
||||
mt_set_maxcontacts(hdev);
|
||||
mt_set_input_mode(hdev);
|
||||
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
|
||||
|
||||
/* release .fields memory as it is not used anymore */
|
||||
devm_kfree(&hdev->dev, td->fields);
|
||||
|
@ -1496,8 +1507,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
static int mt_reset_resume(struct hid_device *hdev)
|
||||
{
|
||||
mt_release_contacts(hdev);
|
||||
mt_set_maxcontacts(hdev);
|
||||
mt_set_input_mode(hdev);
|
||||
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Plantronics USB HID Driver
|
||||
*
|
||||
* Copyright (c) 2014 JD Cole <jd.cole@plantronics.com>
|
||||
* Copyright (c) 2015 Terry Junge <terry.junge@plantronics.com>
|
||||
* Copyright (c) 2015-2018 Terry Junge <terry.junge@plantronics.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -48,6 +48,10 @@ static int plantronics_input_mapping(struct hid_device *hdev,
|
|||
unsigned short mapped_key;
|
||||
unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
|
||||
|
||||
/* special case for PTT products */
|
||||
if (field->application == HID_GD_JOYSTICK)
|
||||
goto defaulted;
|
||||
|
||||
/* handle volume up/down mapping */
|
||||
/* non-standard types or multi-HID interfaces - plt_type is PID */
|
||||
if (!(plt_type & HID_USAGE_PAGE)) {
|
||||
|
|
|
@ -416,7 +416,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_LED)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) },
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* HID driver for Redragon keyboards
|
||||
*
|
||||
* Copyright (c) 2017 Robert Munteanu
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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"
|
||||
|
||||
|
||||
/*
|
||||
* The Redragon Asura keyboard sends an incorrect HID descriptor.
|
||||
* At byte 100 it contains
|
||||
*
|
||||
* 0x81, 0x00
|
||||
*
|
||||
* which is Input (Data, Arr, Abs), but it should be
|
||||
*
|
||||
* 0x81, 0x02
|
||||
*
|
||||
* which is Input (Data, Var, Abs), which is consistent with the way
|
||||
* key codes are generated.
|
||||
*/
|
||||
|
||||
static __u8 *redragon_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 102 && rdesc[100] == 0x81 && rdesc[101] == 0x00) {
|
||||
dev_info(&hdev->dev, "Fixing Redragon ASURA report descriptor.\n");
|
||||
rdesc[101] = 0x02;
|
||||
}
|
||||
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static int redragon_probe(struct hid_device *dev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hid_parse(dev);
|
||||
if (ret) {
|
||||
hid_err(dev, "parse failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* do not register unused input device */
|
||||
if (dev->maxapplication == 1)
|
||||
return 0;
|
||||
|
||||
ret = hid_hw_start(dev, HID_CONNECT_DEFAULT);
|
||||
if (ret) {
|
||||
hid_err(dev, "hw start failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct hid_device_id redragon_devices[] = {
|
||||
{HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_REDRAGON_ASURA)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(hid, redragon_devices);
|
||||
|
||||
static struct hid_driver redragon_driver = {
|
||||
.name = "redragon",
|
||||
.id_table = redragon_devices,
|
||||
.report_fixup = redragon_report_fixup,
|
||||
.probe = redragon_probe
|
||||
};
|
||||
|
||||
module_hid_driver(redragon_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -413,6 +413,24 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct hid_field *field = report->field[0];
|
||||
|
||||
if (!(hid->claimed & HID_CLAIMED_INPUT))
|
||||
return;
|
||||
|
||||
switch (report->id) {
|
||||
case RMI_READ_DATA_REPORT_ID:
|
||||
/* fall-through */
|
||||
case RMI_ATTN_REPORT_ID:
|
||||
return;
|
||||
}
|
||||
|
||||
if (field && field->hidinput && field->hidinput->input)
|
||||
input_sync(field->hidinput->input);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rmi_suspend(struct hid_device *hdev, pm_message_t message)
|
||||
{
|
||||
|
@ -637,6 +655,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
hid_set_drvdata(hdev, data);
|
||||
|
||||
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
|
||||
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
|
@ -744,6 +763,7 @@ static struct hid_driver rmi_driver = {
|
|||
.remove = rmi_remove,
|
||||
.event = rmi_event,
|
||||
.raw_event = rmi_raw_event,
|
||||
.report = rmi_report,
|
||||
.input_mapping = rmi_input_mapping,
|
||||
.input_configured = rmi_input_configured,
|
||||
#ifdef CONFIG_PM
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -131,8 +131,6 @@ static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 };
|
|||
* static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) };
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(i2c_hid_open_mut);
|
||||
|
||||
/* The main device structure */
|
||||
struct i2c_hid {
|
||||
struct i2c_client *client; /* i2c client */
|
||||
|
@ -868,6 +866,15 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id i2c_hid_acpi_blacklist[] = {
|
||||
/*
|
||||
* The CHPN0001 ACPI device, which is used to describe the Chipone
|
||||
* ICN8505 controller, has a _CID of PNP0C50 but is not HID compatible.
|
||||
*/
|
||||
{"CHPN0001", 0 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int i2c_hid_acpi_pdata(struct i2c_client *client,
|
||||
struct i2c_hid_platform_data *pdata)
|
||||
{
|
||||
|
@ -879,13 +886,18 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
|
|||
acpi_handle handle;
|
||||
|
||||
handle = ACPI_HANDLE(&client->dev);
|
||||
if (!handle || acpi_bus_get_device(handle, &adev))
|
||||
if (!handle || acpi_bus_get_device(handle, &adev)) {
|
||||
dev_err(&client->dev, "Error could not get ACPI device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (acpi_match_device_ids(adev, i2c_hid_acpi_blacklist) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (!obj) {
|
||||
dev_err(&client->dev, "device _DSM execution failed\n");
|
||||
dev_err(&client->dev, "Error _DSM call to get HID descriptor address failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -1000,11 +1012,8 @@ static int i2c_hid_probe(struct i2c_client *client,
|
|||
goto err;
|
||||
} else if (!platform_data) {
|
||||
ret = i2c_hid_acpi_pdata(client, &ihid->pdata);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"HID register address not provided\n");
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ihid->pdata = *platform_data;
|
||||
}
|
||||
|
@ -1054,6 +1063,14 @@ static int i2c_hid_probe(struct i2c_client *client,
|
|||
pm_runtime_enable(&client->dev);
|
||||
device_enable_async_suspend(&client->dev);
|
||||
|
||||
/* Make sure there is something at this address */
|
||||
ret = i2c_smbus_read_byte(client);
|
||||
if (ret < 0) {
|
||||
dev_dbg(&client->dev, "nothing at this address: %d\n", ret);
|
||||
ret = -ENXIO;
|
||||
goto err_pm;
|
||||
}
|
||||
|
||||
ret = i2c_hid_fetch_hid_descriptor(ihid);
|
||||
if (ret < 0)
|
||||
goto err_pm;
|
||||
|
|
|
@ -2894,24 +2894,31 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
|||
struct wacom_features *features = &wacom->features;
|
||||
struct input_dev *input = wacom->pen_input;
|
||||
unsigned char *data = wacom->data;
|
||||
int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0;
|
||||
int x = 0, y = 0, p = 0, d = 0;
|
||||
bool pen = false, btn1 = false, btn2 = false;
|
||||
bool range, prox, rdy;
|
||||
|
||||
if (data[0] != WACOM_REPORT_PENABLED)
|
||||
return 0;
|
||||
|
||||
prox = (data[1] & 0x20) == 0x20;
|
||||
range = (data[1] & 0x80) == 0x80;
|
||||
prox = (data[1] & 0x40) == 0x40;
|
||||
rdy = (data[1] & 0x20) == 0x20;
|
||||
|
||||
wacom->shared->stylus_in_proximity = range;
|
||||
if (delay_pen_events(wacom))
|
||||
return 0;
|
||||
|
||||
if (rdy) {
|
||||
p = le16_to_cpup((__le16 *)&data[6]);
|
||||
pen = data[1] & 0x01;
|
||||
btn1 = data[1] & 0x02;
|
||||
btn2 = data[1] & 0x04;
|
||||
}
|
||||
if (prox) {
|
||||
x = le16_to_cpup((__le16 *)&data[2]);
|
||||
y = le16_to_cpup((__le16 *)&data[4]);
|
||||
|
||||
/*
|
||||
* All reports shared between PEN and RUBBER tool must be
|
||||
* forced to a known starting value (zero) when transitioning to
|
||||
* out-of-prox.
|
||||
*
|
||||
* If not reset then, to userspace, it will look like lost events
|
||||
* if new tool comes in-prox with same values as previous tool sent.
|
||||
*
|
||||
* Hardware does report zero in most out-of-prox cases but not all.
|
||||
*/
|
||||
if (!wacom->shared->stylus_in_proximity) {
|
||||
if (data[1] & 0x08) {
|
||||
wacom->tool[0] = BTN_TOOL_RUBBER;
|
||||
wacom->id[0] = ERASER_DEVICE_ID;
|
||||
|
@ -2919,16 +2926,9 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
|||
wacom->tool[0] = BTN_TOOL_PEN;
|
||||
wacom->id[0] = STYLUS_DEVICE_ID;
|
||||
}
|
||||
wacom->reporting_data = true;
|
||||
}
|
||||
|
||||
wacom->shared->stylus_in_proximity = prox;
|
||||
if (delay_pen_events(wacom))
|
||||
return 0;
|
||||
|
||||
if (prox) {
|
||||
x = le16_to_cpup((__le16 *)&data[2]);
|
||||
y = le16_to_cpup((__le16 *)&data[4]);
|
||||
p = le16_to_cpup((__le16 *)&data[6]);
|
||||
if (range) {
|
||||
/*
|
||||
* Convert distance from out prox to distance from tablet.
|
||||
* distance will be greater than distance_max once
|
||||
|
@ -2937,25 +2937,29 @@ static int wacom_bpt_pen(struct wacom_wac *wacom)
|
|||
*/
|
||||
if (data[8] <= features->distance_max)
|
||||
d = features->distance_max - data[8];
|
||||
|
||||
pen = data[1] & 0x01;
|
||||
btn1 = data[1] & 0x02;
|
||||
btn2 = data[1] & 0x04;
|
||||
} else {
|
||||
wacom->id[0] = 0;
|
||||
}
|
||||
|
||||
input_report_key(input, BTN_TOUCH, pen);
|
||||
input_report_key(input, BTN_STYLUS, btn1);
|
||||
input_report_key(input, BTN_STYLUS2, btn2);
|
||||
if (wacom->reporting_data) {
|
||||
input_report_key(input, BTN_TOUCH, pen);
|
||||
input_report_key(input, BTN_STYLUS, btn1);
|
||||
input_report_key(input, BTN_STYLUS2, btn2);
|
||||
|
||||
input_report_abs(input, ABS_X, x);
|
||||
input_report_abs(input, ABS_Y, y);
|
||||
input_report_abs(input, ABS_PRESSURE, p);
|
||||
input_report_abs(input, ABS_DISTANCE, d);
|
||||
if (prox || !range) {
|
||||
input_report_abs(input, ABS_X, x);
|
||||
input_report_abs(input, ABS_Y, y);
|
||||
}
|
||||
input_report_abs(input, ABS_PRESSURE, p);
|
||||
input_report_abs(input, ABS_DISTANCE, d);
|
||||
|
||||
input_report_key(input, wacom->tool[0], prox); /* PEN or RUBBER */
|
||||
input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
|
||||
input_report_key(input, wacom->tool[0], range); /* PEN or RUBBER */
|
||||
input_report_abs(input, ABS_MISC, wacom->id[0]); /* TOOL ID */
|
||||
}
|
||||
|
||||
if (!range) {
|
||||
wacom->reporting_data = false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -292,9 +292,12 @@ struct hid_item {
|
|||
#define HID_DG_CONTACTCOUNT 0x000d0054
|
||||
#define HID_DG_CONTACTMAX 0x000d0055
|
||||
#define HID_DG_SCANTIME 0x000d0056
|
||||
#define HID_DG_SURFACESWITCH 0x000d0057
|
||||
#define HID_DG_BUTTONSWITCH 0x000d0058
|
||||
#define HID_DG_BUTTONTYPE 0x000d0059
|
||||
#define HID_DG_BARRELSWITCH2 0x000d005a
|
||||
#define HID_DG_TOOLSERIALNUMBER 0x000d005b
|
||||
#define HID_DG_LATENCYMODE 0x000d0060
|
||||
|
||||
#define HID_VD_ASUS_CUSTOM_MEDIA_KEYS 0xff310076
|
||||
/*
|
||||
|
@ -341,10 +344,12 @@ struct hid_item {
|
|||
/* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */
|
||||
/* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
|
||||
#define HID_QUIRK_ALWAYS_POLL BIT(10)
|
||||
#define HID_QUIRK_INPUT_PER_APP BIT(11)
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16)
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17)
|
||||
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
|
||||
#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19)
|
||||
#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
|
||||
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
|
||||
#define HID_QUIRK_NO_IGNORE BIT(30)
|
||||
|
@ -367,6 +372,7 @@ struct hid_item {
|
|||
#define HID_GROUP_RMI 0x0100
|
||||
#define HID_GROUP_WACOM 0x0101
|
||||
#define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102
|
||||
#define HID_GROUP_STEAM 0x0103
|
||||
|
||||
/*
|
||||
* HID protocol status
|
||||
|
@ -463,8 +469,10 @@ struct hid_field {
|
|||
|
||||
struct hid_report {
|
||||
struct list_head list;
|
||||
unsigned id; /* id of this report */
|
||||
unsigned type; /* report type */
|
||||
struct list_head hidinput_list;
|
||||
unsigned int id; /* id of this report */
|
||||
unsigned int type; /* report type */
|
||||
unsigned int application; /* application usage for this report */
|
||||
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
|
||||
unsigned maxfield; /* maximum valid field index */
|
||||
unsigned size; /* size of the report (bits) */
|
||||
|
@ -502,12 +510,15 @@ struct hid_output_fifo {
|
|||
|
||||
#define HID_STAT_ADDED BIT(0)
|
||||
#define HID_STAT_PARSED BIT(1)
|
||||
#define HID_STAT_DUP_DETECTED BIT(2)
|
||||
|
||||
struct hid_input {
|
||||
struct list_head list;
|
||||
struct hid_report *report;
|
||||
struct input_dev *input;
|
||||
const char *name;
|
||||
bool registered;
|
||||
struct list_head reports; /* the list of reports */
|
||||
};
|
||||
|
||||
enum hid_type {
|
||||
|
@ -864,7 +875,9 @@ void hid_output_report(struct hid_report *report, __u8 *data);
|
|||
void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
|
||||
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
|
||||
struct hid_device *hid_allocate_device(void);
|
||||
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
|
||||
struct hid_report *hid_register_report(struct hid_device *device,
|
||||
unsigned int type, unsigned int id,
|
||||
unsigned int application);
|
||||
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
|
||||
struct hid_report *hid_validate_values(struct hid_device *hid,
|
||||
unsigned int type, unsigned int id,
|
||||
|
|
Loading…
Reference in New Issue