Commit 96f2f66a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:

 - rumble support for Xbox One S, from Andrey Smirnov

 - high-resolution support for Logitech mice, from Harry Cutts

 - support for recent devices requiring the HID parse to be able to cope
   with tag report sizes > 256

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (35 commits)
  HID: usbhid: Add quirk for Redragon/Dragonrise Seymur 2
  HID: wacom: Work around HID descriptor bug in DTK-2451 and DTH-2452
  HID: google: add dependency on Cros EC for Hammer
  HID: elan: fix spelling mistake "registred" -> "registered"
  HID: google: drop superfluous const before SIMPLE_DEV_PM_OPS()
  HID: google: add support tablet mode switch for Whiskers
  mfd: cros: add "base attached" MKBP switch definition
  Input: reserve 2 events code because of HID
  HID: magicmouse: add support for Apple Magic Trackpad 2
  HID: i2c-hid: override HID descriptors for certain devices
  HID: hid-bigbenff: driver for BigBen Interactive PS3OFMINIPAD gamepad
  HID: logitech: fix a used uninitialized GCC warning
  HID: intel-ish-hid: using list_head for ipc write queue
  HID: intel-ish-hid: use resource-managed api
  HID: intel_ish-hid: Enhance API to get ring buffer sizes
  HID: intel-ish-hid: use helper function to search client id
  HID: intel-ish-hid: ishtp: add helper function for client search
  HID: intel-ish-hid: use helper function to access client buffer
  HID: intel-ish-hid: ishtp: add helper functions for client buffer operation
  HID: intel-ish-hid: use helper function for private driver data set/get
  ...
parents 3f2dcb64 46011e97
......@@ -190,7 +190,16 @@ A few EV_REL codes have special meanings:
* REL_WHEEL, REL_HWHEEL:
- These codes are used for vertical and horizontal scroll wheels,
respectively.
respectively. The value is the number of "notches" moved on the wheel, the
physical size of which varies by device. For high-resolution wheels (which
report multiple events for each notch of movement, or do not have notches)
this may be an approximation based on the high-resolution scroll events.
* REL_WHEEL_HI_RES:
- If a vertical scroll wheel supports high-resolution scrolling, this code
will be emitted in addition to REL_WHEEL. The value is the (approximate)
distance travelled by the user's finger, in microns.
EV_ABS
------
......
......@@ -182,6 +182,19 @@ config HID_BETOP_FF
Currently the following devices are known to be supported:
- BETOP 2185 PC & BFM MODE
config HID_BIGBEN_FF
tristate "BigBen Interactive Kids' gamepad support"
depends on USB_HID
depends on NEW_LEDS
depends on LEDS_CLASS
select INPUT_FF_MEMLESS
default !EXPERT
help
Support for the "Kid-friendly Wired Controller" PS3OFMINIPAD
gamepad made by BigBen Interactive, originally sold as a PS3
accessory. This driver fixes input mapping and adds support for
force feedback effects and LEDs on the device.
config HID_CHERRY
tristate "Cherry Cymotion keyboard"
depends on HID
......@@ -351,7 +364,7 @@ config HOLTEK_FF
config HID_GOOGLE_HAMMER
tristate "Google Hammer Keyboard"
depends on USB_HID && LEDS_CLASS
depends on USB_HID && LEDS_CLASS && MFD_CROS_EC
---help---
Say Y here if you have a Google Hammer device.
......@@ -596,6 +609,7 @@ config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices"
depends on HID
default !EXPERT
select INPUT_FF_MEMLESS
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_ASUS) += hid-asus.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_BIGBEN_FF) += hid-bigbenff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o
......
This diff is collapsed.
......@@ -406,7 +406,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
parser->global.report_size = item_udata(item);
if (parser->global.report_size > 128) {
if (parser->global.report_size > 256) {
hid_err(parser->device, "invalid report_size %d\n",
parser->global.report_size);
return -1;
......
......@@ -7,6 +7,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/printk.h>
#include "hid-ids.h"
......@@ -15,11 +16,9 @@ MODULE_DESCRIPTION("Cougar 500k Gaming Keyboard");
MODULE_LICENSE("GPL");
MODULE_INFO(key_mappings, "G1-G6 are mapped to F13-F18");
static int cougar_g6_is_space = 1;
module_param_named(g6_is_space, cougar_g6_is_space, int, 0600);
static bool g6_is_space = true;
MODULE_PARM_DESC(g6_is_space,
"If set, G6 programmable key sends SPACE instead of F18 (0=off, 1=on) (default=1)");
"If true, G6 programmable key sends SPACE instead of F18 (default=true)");
#define COUGAR_VENDOR_USAGE 0xff00ff00
......@@ -82,20 +81,23 @@ struct cougar {
static LIST_HEAD(cougar_udev_list);
static DEFINE_MUTEX(cougar_udev_list_lock);
static void cougar_fix_g6_mapping(struct hid_device *hdev)
/**
* cougar_fix_g6_mapping - configure the mapping for key G6/Spacebar
*/
static void cougar_fix_g6_mapping(void)
{
int i;
for (i = 0; cougar_mapping[i][0]; i++) {
if (cougar_mapping[i][0] == COUGAR_KEY_G6) {
cougar_mapping[i][1] =
cougar_g6_is_space ? KEY_SPACE : KEY_F18;
hid_info(hdev, "G6 mapped to %s\n",
cougar_g6_is_space ? "space" : "F18");
g6_is_space ? KEY_SPACE : KEY_F18;
pr_info("cougar: G6 mapped to %s\n",
g6_is_space ? "space" : "F18");
return;
}
}
hid_warn(hdev, "no mapping defined for G6/spacebar");
pr_warn("cougar: no mappings defined for G6/spacebar");
}
/*
......@@ -154,7 +156,8 @@ static void cougar_remove_shared_data(void *resource)
* Bind the device group's shared data to this cougar struct.
* If no shared data exists for this group, create and initialize it.
*/
static int cougar_bind_shared_data(struct hid_device *hdev, struct cougar *cougar)
static int cougar_bind_shared_data(struct hid_device *hdev,
struct cougar *cougar)
{
struct cougar_shared *shared;
int error = 0;
......@@ -228,7 +231,6 @@ static int cougar_probe(struct hid_device *hdev,
* to it.
*/
if (hdev->collection->usage == HID_GD_KEYBOARD) {
cougar_fix_g6_mapping(hdev);
list_for_each_entry_safe(hidinput, next, &hdev->inputs, list) {
if (hidinput->registered && hidinput->input != NULL) {
cougar->shared->input = hidinput->input;
......@@ -237,6 +239,8 @@ static int cougar_probe(struct hid_device *hdev,
}
}
} else if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
/* Preinit the mapping table */
cougar_fix_g6_mapping();
error = hid_hw_open(hdev);
if (error)
goto fail_stop_and_cleanup;
......@@ -257,26 +261,32 @@ static int cougar_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct cougar *cougar;
struct cougar_shared *shared;
unsigned char code, action;
int i;
cougar = hid_get_drvdata(hdev);
if (!cougar->special_intf || !cougar->shared ||
!cougar->shared->input || !cougar->shared->enabled)
shared = cougar->shared;
if (!cougar->special_intf || !shared)
return 0;
if (!shared->enabled || !shared->input)
return -EPERM;
code = data[COUGAR_FIELD_CODE];
action = data[COUGAR_FIELD_ACTION];
for (i = 0; cougar_mapping[i][0]; i++) {
if (code == cougar_mapping[i][0]) {
input_event(cougar->shared->input, EV_KEY,
input_event(shared->input, EV_KEY,
cougar_mapping[i][1], action);
input_sync(cougar->shared->input);
return 0;
input_sync(shared->input);
return -EPERM;
}
}
hid_warn(hdev, "unmapped special key code %x: ignoring\n", code);
return 0;
/* Avoid warnings on the same unmapped key twice */
if (action != 0)
hid_warn(hdev, "unmapped special key code %0x: ignoring\n", code);
return -EPERM;
}
static void cougar_remove(struct hid_device *hdev)
......@@ -293,6 +303,26 @@ static void cougar_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
}
static int cougar_param_set_g6_is_space(const char *val,
const struct kernel_param *kp)
{
int ret;
ret = param_set_bool(val, kp);
if (ret)
return ret;
cougar_fix_g6_mapping();
return 0;
}
static const struct kernel_param_ops cougar_g6_is_space_ops = {
.set = cougar_param_set_g6_is_space,
.get = param_get_bool,
};
module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
static struct hid_device_id cougar_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
......
......@@ -497,7 +497,7 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
if (!drvdata->input) {
hid_err(hdev, "Input device is not registred\n");
hid_err(hdev, "Input device is not registered\n");
ret = -ENAVAIL;
goto err;
}
......
This diff is collapsed.
......@@ -92,6 +92,7 @@
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
......@@ -229,6 +230,9 @@
#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
#define USB_VENDOR_ID_BIGBEN 0x146b
#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
......@@ -342,6 +346,7 @@
#define USB_DEVICE_ID_DMI_ENC 0x5fab
#define USB_VENDOR_ID_DRAGONRISE 0x0079
#define USB_DEVICE_ID_REDRAGON_SEYMUR2 0x0006
#define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800
#define USB_DEVICE_ID_DRAGONRISE_PS3 0x1801
#define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803
......@@ -799,6 +804,7 @@
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da
#define USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER 0x02fd
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
......
......@@ -758,6 +758,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case HID_UP_DIGITIZER:
if ((field->application & 0xff) == 0x01) /* Digitizer */
__set_bit(INPUT_PROP_POINTER, input->propbit);
else if ((field->application & 0xff) == 0x02) /* Pen */
__set_bit(INPUT_PROP_DIRECT, input->propbit);
switch (usage->hid & 0xff) {
case 0x00: /* Undefined */
goto ignore;
......@@ -1516,6 +1521,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
struct input_dev *input_dev = input_allocate_device();
const char *suffix = NULL;
size_t suffix_len, name_len;
if (!hidinput || !input_dev)
goto fail;
......@@ -1559,10 +1565,15 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
}
if (suffix) {
hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
hid->name, suffix);
if (!hidinput->name)
goto fail;
name_len = strlen(hid->name);
suffix_len = strlen(suffix);
if ((name_len < suffix_len) ||
strcmp(hid->name + name_len - suffix_len, suffix)) {
hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
hid->name, suffix);
if (!hidinput->name)
goto fail;
}
}
input_set_drvdata(input_dev, hid);
......@@ -1827,3 +1838,48 @@ void hidinput_disconnect(struct hid_device *hid)
}
EXPORT_SYMBOL_GPL(hidinput_disconnect);
/**
* hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
* events given a high-resolution wheel
* movement.
* @counter: a hid_scroll_counter struct describing the wheel.
* @hi_res_value: the movement of the wheel, in the mouse's high-resolution
* units.
*
* Given a high-resolution movement, this function converts the movement into
* microns and emits high-resolution scroll events for the input device. It also
* uses the multiplier from &struct hid_scroll_counter to emit low-resolution
* scroll events when appropriate for backwards-compatibility with userspace
* input libraries.
*/
void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
int hi_res_value)
{
int low_res_scroll_amount;
/* Some wheels will rest 7/8ths of a notch from the previous notch
* after slow movement, so we want the threshold for low-res events to
* be in the middle of the notches (e.g. after 4/8ths) as opposed to on
* the notches themselves (8/8ths).
*/
int threshold = counter->resolution_multiplier / 2;
input_report_rel(counter->dev, REL_WHEEL_HI_RES,
hi_res_value * counter->microns_per_hi_res_unit);
counter->remainder += hi_res_value;
if (abs(counter->remainder) >= threshold) {
/* Add (or subtract) 1 because we want to trigger when the wheel
* is half-way to the next notch (i.e. scroll 1 notch after a
* 1/2 notch movement, 2 notches after a 1 1/2 notch movement,
* etc.).
*/
low_res_scroll_amount =
counter->remainder / counter->resolution_multiplier
+ (hi_res_value > 0 ? 1 : -1);
input_report_rel(counter->dev, REL_WHEEL,
low_res_scroll_amount);
counter->remainder -=
low_res_scroll_amount * counter->resolution_multiplier;
}
}
EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);
This diff is collapsed.
This diff is collapsed.
......@@ -29,11 +29,41 @@
#define MS_NOGET BIT(4)
#define MS_DUPLICATE_USAGES BIT(5)
#define MS_SURFACE_DIAL BIT(6)
#define MS_QUIRK_FF BIT(7)
struct ms_data {
unsigned long quirks;
struct hid_device *hdev;
struct work_struct ff_worker;
__u8 strong;
__u8 weak;
void *output_report_dmabuf;
};
#define XB1S_FF_REPORT 3
#define ENABLE_WEAK BIT(0)
#define ENABLE_STRONG BIT(1)
enum {
MAGNITUDE_STRONG = 2,
MAGNITUDE_WEAK,
MAGNITUDE_NUM
};
struct xb1s_ff_report {
__u8 report_id;
__u8 enable;
__u8 magnitude[MAGNITUDE_NUM];
__u8 duration_10ms;
__u8 start_delay_10ms;
__u8 loop_count;
} __packed;
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct ms_data *ms = hid_get_drvdata(hdev);
unsigned long quirks = ms->quirks;
/*
* Microsoft Wireless Desktop Receiver (Model 1028) has
......@@ -159,7 +189,8 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct ms_data *ms = hid_get_drvdata(hdev);
unsigned long quirks = ms->quirks;
if (quirks & MS_ERGONOMY) {
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
......@@ -185,7 +216,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct ms_data *ms = hid_get_drvdata(hdev);
unsigned long quirks = ms->quirks;
if (quirks & MS_DUPLICATE_USAGES)
clear_bit(usage->code, *bit);
......@@ -196,7 +228,8 @@ static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int ms_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct ms_data *ms = hid_get_drvdata(hdev);
unsigned long quirks = ms->quirks;
struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
......@@ -251,12 +284,97 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
return 0;
}
static void ms_ff_worker(struct work_struct *work)
{
struct ms_data *ms = container_of(work, struct ms_data, ff_worker);
struct hid_device *hdev = ms->hdev;
struct xb1s_ff_report *r = ms->output_report_dmabuf;
int ret;
memset(r, 0, sizeof(*r));
r->report_id = XB1S_FF_REPORT;
r->enable = ENABLE_WEAK | ENABLE_STRONG;
/*
* Specifying maximum duration and maximum loop count should
* cover maximum duration of a single effect, which is 65536
* ms
*/
r->duration_10ms = U8_MAX;
r->loop_count = U8_MAX;
r->magnitude[MAGNITUDE_STRONG] = ms->strong; /* left actuator */
r->magnitude[MAGNITUDE_WEAK] = ms->weak; /* right actuator */
ret = hid_hw_output_report(hdev, (__u8 *)r, sizeof(*r));
if (ret)
hid_warn(hdev, "failed to send FF report\n");
}
static int ms_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct ms_data *ms = hid_get_drvdata(hid);
if (effect->type != FF_RUMBLE)
return 0;
/*
* Magnitude is 0..100 so scale the 16-bit input here
*/
ms->strong = ((u32) effect->u.rumble.strong_magnitude * 100) / U16_MAX;
ms->weak = ((u32) effect->u.rumble.weak_magnitude * 100) / U16_MAX;
schedule_work(&ms->ff_worker);
return 0;
}
static int ms_init_ff(struct hid_device *hdev)
{
struct hid_input *hidinput = list_entry(hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
struct ms_data *ms = hid_get_drvdata(hdev);
if (!(ms->quirks & MS_QUIRK_FF))
return 0;
ms->hdev = hdev;
INIT_WORK(&ms->ff_worker, ms_ff_worker);
ms->output_report_dmabuf = devm_kzalloc(&hdev->dev,
sizeof(struct xb1s_ff_report),
GFP_KERNEL);
if (ms->output_report_dmabuf == NULL)
return -ENOMEM;
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
return input_ff_create_memless(input_dev, NULL, ms_play_effect);
}
static void ms_remove_ff(struct hid_device *hdev)
{
struct ms_data *ms = hid_get_drvdata(hdev);
if (!(ms->quirks & MS_QUIRK_FF))
return;
cancel_work_sync(&ms->ff_worker);
}
static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
unsigned long quirks = id->driver_data;
struct ms_data *ms;
int ret;
hid_set_drvdata(hdev, (void *)quirks);
ms = devm_kzalloc(&hdev->dev, sizeof(*ms), GFP_KERNEL);
if (ms == NULL)
return -ENOMEM;
ms->quirks = quirks;
hid_set_drvdata(hdev, ms);
if (quirks & MS_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
......@@ -277,11 +395,21 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
ret = ms_init_ff(hdev);
if (ret)
hid_err(hdev, "could not initialize ff, continuing anyway");
return 0;
err_free:
return ret;
}
static void ms_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
ms_remove_ff(hdev);
}
static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
.driver_data = MS_HIDINPUT },
......@@ -318,6 +446,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_PRESENTER },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
.driver_data = MS_SURFACE_DIAL },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_XBOX_ONE_S_CONTROLLER),
.driver_data = MS_QUIRK_FF },
{ }
};
MODULE_DEVICE_TABLE(hid, ms_devices);
......@@ -330,6 +460,7 @@ static struct hid_driver ms_driver = {
.input_mapped = ms_input_mapped,
.event = ms_event,
.probe = ms_probe,
.remove = ms_remove,
};
module_hid_driver(ms_driver);
......
......@@ -1319,6 +1319,13 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
/*
* some egalax touchscreens have "application == DG_TOUCHSCREEN"
* for the stylus. Overwrite the hid_input application
*/
if (field->physical == HID_DG_STYLUS)
hi->application = HID_DG_STYLUS;
/* let hid-core decide for the others */
return 0;
}
......@@ -1507,14 +1514,12 @@ 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;
unsigned int application = 0;
struct mt_report_data *rdata;
struct mt_application *mt_application = NULL;
struct hid_report *report;
int ret;
list_for_each_entry(report, &hi->reports, hidinput_list) {
application = report->application;
rdata = mt_find_report_data(td, report);
if (!rdata) {
hid_err(hdev, "failed to allocate data for report\n");
......@@ -1529,46 +1534,33 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret)
return ret;
}
/*
* 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:
case HID_GD_SYSTEM_MULTIAXIS:
/* 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_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";
break;
default:
suffix = "UNKNOWN";
break;
}
switch (hi->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:
case HID_GD_SYSTEM_MULTIAXIS:
/* 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_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";
break;
default:
suffix = "UNKNOWN";
break;
}
if (suffix) {
......
......@@ -70,6 +70,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
......
......@@ -3,3 +3,6 @@
#
obj-$(CONFIG_I2C_HID) += i2c-hid.o
i2c-hid-objs = i2c-hid-core.o
i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o
......@@ -43,6 +43,7 @@
#include <linux/platform_data/i2c-hid.h>
#include "../hid-ids.h"
#include "i2c-hid.h"
/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
......@@ -668,6 +669,7 @@ static int i2c_hid_parse(struct hid_device *hid)
char *rdesc;
int ret;
int tries = 3;
char *use_override;
i2c_hid_dbg(ihid, "entering %s\n", __func__);
......@@ -686,26 +688,37 @@ static int i2c_hid_parse(struct hid_device *hid)
if (ret)
return ret;
rdesc = kzalloc(rsize, GFP_KERNEL);
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
&rsize);
if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory\n");
return -ENOMEM;
}
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
ret = i2c_hid_command(client, &hid_report_descr_cmd, rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
return -EIO;
if (use_override) {
rdesc = use_override;
i2c_hid_dbg(ihid, "Using a HID report descriptor override\n");
} else {
rdesc = kzalloc(rsize, GFP_KERNEL);
if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory\n");
return -ENOMEM;
}
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
ret = i2c_hid_command(client, &hid_report_descr_cmd,
rdesc, rsize);