Commit 39520eea 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:

 - quirk for devices that need to be pulled in much more aggresive way
   than mandated, by Johan Hovold

 - robustification of sanity checking of incoming reports in RMI driver,
   by Benjamin Tissoires

 - fixes, updates, and new HW support to SONY driver, by Frank Praznik

 - port of uHID to the new transport layer layout, by David Herrmann

 - robustification of Clear-Halt/reset in USB HID, by Alan Stern

 - native support for hopefully any future HID compliant wacom tablet.
   Those found on the various laptops (ISDv4/5) already are HID
   compliant and they should work in the future without any modification
   of the kernel.  Written by Benjamin Tissoires.

 - a lot more simple fixes and device ID additions all over the place

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (45 commits)
  HID: uHID: fix excepted report type
  HID: usbhid: add another mouse that needs QUIRK_ALWAYS_POLL
  HID: wacom: implement the finger part of the HID generic handling
  HID: wacom: implement generic HID handling for pen generic devices
  HID: wacom: move allocation of inputs earlier
  HID: wacom: split out input allocation and registration
  HID: wacom: rename failN with some meaningful information
  HID: sony: Update the DualShock 4 touchpad resolution
  HID: wacom: fix timeout on probe for some wacoms
  HID: sony: Set touchpad bits in the input_configured callback
  HID: sony: Update file header and correct comments
  HID: sony: Corrections for the DualShock 4 HID descriptor
  HID: rmi: check sanity of the incoming report
  HID: wacom: make the WL connection friendly for the desktop
  HID: wacom - enable LED support for Wireless Intuos5/Pro
  HID: wacom - remove report_id from wacom_get_report interface
  HID: wacom - Clean up of sysfs
  HID: wacom - Add default permission defines for sysfs attributes
  HID: usbhid: fix PIXART optical mouse
  HID: Add Holtek USB ID 04d9:a0c2 ETEKCITY Scroll
  ...
parents 28596c97 ee5db7e4
This diff is collapsed.
...@@ -530,6 +530,17 @@ config PANTHERLORD_FF ...@@ -530,6 +530,17 @@ config PANTHERLORD_FF
Say Y here if you have a PantherLord/GreenAsia based game controller Say Y here if you have a PantherLord/GreenAsia based game controller
or adapter and want to enable force feedback support for it. or adapter and want to enable force feedback support for it.
config HID_PENMOUNT
tristate "Penmount touch device"
depends on USB_HID
---help---
This selects a driver for the PenMount 6000 touch controller.
The driver works around a problem in the report descript allowing
the userspace to touch events instead of mouse events.
Say Y here if you have a Penmount based touch controller.
config HID_PETALYNX config HID_PETALYNX
tristate "Petalynx Maxter remote control" tristate "Petalynx Maxter remote control"
depends on HID depends on HID
......
...@@ -71,6 +71,7 @@ obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o ...@@ -71,6 +71,7 @@ obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
hid-picolcd-y += hid-picolcd_core.o hid-picolcd-y += hid-picolcd_core.o
......
...@@ -52,7 +52,7 @@ EXPORT_SYMBOL_GPL(hid_debug); ...@@ -52,7 +52,7 @@ EXPORT_SYMBOL_GPL(hid_debug);
static int hid_ignore_special_drivers = 0; static int hid_ignore_special_drivers = 0;
module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600); module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600);
MODULE_PARM_DESC(debug, "Ignore any special drivers and handle all devices by generic driver"); MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver");
/* /*
* Register a new report for a device. * Register a new report for a device.
...@@ -1591,6 +1591,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1591,6 +1591,9 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
hdev->claimed |= HID_CLAIMED_HIDRAW; hdev->claimed |= HID_CLAIMED_HIDRAW;
if (connect_mask & HID_CONNECT_DRIVER)
hdev->claimed |= HID_CLAIMED_DRIVER;
/* Drivers with the ->raw_event callback set are not required to connect /* Drivers with the ->raw_event callback set are not required to connect
* to any other listener. */ * to any other listener. */
if (!hdev->claimed && !hdev->driver->raw_event) { if (!hdev->claimed && !hdev->driver->raw_event) {
...@@ -1793,6 +1796,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1793,6 +1796,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
...@@ -1880,6 +1884,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1880,6 +1884,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
#if IS_ENABLED(CONFIG_HID_ROCCAT) #if IS_ENABLED(CONFIG_HID_ROCCAT)
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
* and Zalman ZM-GM1 * and Zalman ZM-GM1
* - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse * - USB ID 04d9:a081, sold as SHARKOON DarkGlider Gaming mouse
* - USB ID 04d9:a072, sold as LEETGION Hellion Gaming Mouse * - USB ID 04d9:a072, sold as LEETGION Hellion Gaming Mouse
* - USB ID 04d9:a0c2, sold as ETEKCITY Scroll T-140 Gaming Mouse
*/ */
static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
...@@ -42,6 +43,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -42,6 +43,7 @@ static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
switch (hdev->product) { switch (hdev->product) {
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067: case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072: case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072:
case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2:
if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
&& rdesc[120] == 0xff && rdesc[121] == 0x7f) { && rdesc[120] == 0xff && rdesc[121] == 0x7f) {
hid_info(hdev, "Fixing up report descriptor\n"); hid_info(hdev, "Fixing up report descriptor\n");
...@@ -74,6 +76,8 @@ static const struct hid_device_id holtek_mouse_devices[] = { ...@@ -74,6 +76,8 @@ static const struct hid_device_id holtek_mouse_devices[] = {
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) }, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) }, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, holtek_mouse_devices); MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
......
...@@ -296,6 +296,9 @@ ...@@ -296,6 +296,9 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
#define USB_VENDOR_ID_ELAN 0x04f3
#define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089
#define USB_VENDOR_ID_ELECOM 0x056e #define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061 #define USB_DEVICE_ID_ELECOM_BM084 0x0061
...@@ -479,6 +482,7 @@ ...@@ -479,6 +482,7 @@
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070 0xa070 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070 0xa070
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081 #define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081
#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2 0xa0c2
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096 0xa096 #define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096 0xa096
#define USB_VENDOR_ID_IMATION 0x0718 #define USB_VENDOR_ID_IMATION 0x0718
...@@ -722,6 +726,7 @@ ...@@ -722,6 +726,7 @@
#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500 #define USB_DEVICE_ID_PENMOUNT_PCI 0x3500
#define USB_DEVICE_ID_PENMOUNT_1610 0x1610 #define USB_DEVICE_ID_PENMOUNT_1610 0x1610
#define USB_DEVICE_ID_PENMOUNT_1640 0x1640 #define USB_DEVICE_ID_PENMOUNT_1640 0x1640
#define USB_DEVICE_ID_PENMOUNT_6000 0x6000
#define USB_VENDOR_ID_PETALYNX 0x18b1 #define USB_VENDOR_ID_PETALYNX 0x18b1
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
...@@ -733,6 +738,8 @@ ...@@ -733,6 +738,8 @@
#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff #define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
#define USB_VENDOR_ID_PIXART 0x093a #define USB_VENDOR_ID_PIXART 0x093a
#define USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2 0x0137
#define USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE 0x2510
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN 0x8001 #define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN 0x8001
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1 0x8002 #define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1 0x8002
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2 0x8003 #define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2 0x8003
......
...@@ -599,6 +599,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -599,6 +599,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
/* These usage IDs map directly to the usage codes. */ /* These usage IDs map directly to the usage codes. */
case HID_GD_X: case HID_GD_Y: case HID_GD_Z: case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf);
else
map_abs_clear(usage->hid & 0xf);
break;
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
if (field->flags & HID_MAIN_ITEM_RELATIVE) if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf); map_rel(usage->hid & 0xf);
......
...@@ -385,18 +385,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev, ...@@ -385,18 +385,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
djdev = djrcv_dev->paired_dj_devices[dj_report->device_index]; djdev = djrcv_dev->paired_dj_devices[dj_report->device_index];
if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return;
}
memset(reportbuffer, 0, sizeof(reportbuffer)); memset(reportbuffer, 0, sizeof(reportbuffer));
for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) { for (i = 0; i < NUMBER_OF_HID_REPORTS; i++) {
...@@ -421,18 +409,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev, ...@@ -421,18 +409,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index]; dj_device = djrcv_dev->paired_dj_devices[dj_report->device_index];
if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return;
}
if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) || if ((dj_report->report_type > ARRAY_SIZE(hid_reportid_size_map) - 1) ||
(hid_reportid_size_map[dj_report->report_type] == 0)) { (hid_reportid_size_map[dj_report->report_type] == 0)) {
dbg_hid("invalid report type:%x\n", dj_report->report_type); dbg_hid("invalid report type:%x\n", dj_report->report_type);
...@@ -701,8 +677,17 @@ static int logi_dj_raw_event(struct hid_device *hdev, ...@@ -701,8 +677,17 @@ static int logi_dj_raw_event(struct hid_device *hdev,
} }
spin_lock_irqsave(&djrcv_dev->lock, flags); spin_lock_irqsave(&djrcv_dev->lock, flags);
if (!djrcv_dev->paired_dj_devices[dj_report->device_index]) {
/* received an event for an unknown device, bail out */
logi_dj_recv_queue_notification(djrcv_dev, dj_report);
goto out;
}
switch (dj_report->report_type) { switch (dj_report->report_type) {
case REPORT_TYPE_NOTIF_DEVICE_PAIRED: case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
/* pairing notifications are handled above the switch */
break;
case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED: case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
logi_dj_recv_queue_notification(djrcv_dev, dj_report); logi_dj_recv_queue_notification(djrcv_dev, dj_report);
break; break;
...@@ -715,6 +700,8 @@ static int logi_dj_raw_event(struct hid_device *hdev, ...@@ -715,6 +700,8 @@ static int logi_dj_raw_event(struct hid_device *hdev,
default: default:
logi_dj_recv_forward_report(djrcv_dev, dj_report); logi_dj_recv_forward_report(djrcv_dev, dj_report);
} }
out:
spin_unlock_irqrestore(&djrcv_dev->lock, flags); spin_unlock_irqrestore(&djrcv_dev->lock, flags);
return true; return true;
......
/*
* HID driver for PenMount touchscreens
*
* Copyright (c) 2014 Christian Gmeiner <christian.gmeiner <at> gmail.com>
*
* based on hid-penmount copyrighted by
* PenMount Touch Solutions <penmount <at> seed.net.tw>
*/
/*
* 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/module.h>
#include <linux/hid.h>
#include "hid-ids.h"
static int penmount_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
}
return 0;
}
static const struct hid_device_id penmount_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
{ }
};
MODULE_DEVICE_TABLE(hid, penmount_devices);
static struct hid_driver penmount_driver = {
.name = "hid-penmount",
.id_table = penmount_devices,
.input_mapping = penmount_input_mapping,
};
module_hid_driver(penmount_driver);
MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
MODULE_DESCRIPTION("PenMount HID TouchScreen driver");
MODULE_LICENSE("GPL");
...@@ -351,8 +351,8 @@ static int picolcd_raw_event(struct hid_device *hdev, ...@@ -351,8 +351,8 @@ static int picolcd_raw_event(struct hid_device *hdev,
return 1; return 1;
if (size > 64) { if (size > 64) {
hid_warn(hdev, "invalid size value (%d) for picolcd raw event\n", hid_warn(hdev, "invalid size value (%d) for picolcd raw event (%d)\n",
size); size, report->id);
return 0; return 0;
} }
......
...@@ -320,10 +320,7 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data, ...@@ -320,10 +320,7 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
int offset; int offset;
int i; int i;
if (size < hdata->f11.report_size) if (!(irq & hdata->f11.irq_mask) || size <= 0)
return 0;
if (!(irq & hdata->f11.irq_mask))
return 0; return 0;
offset = (hdata->max_fingers >> 2) + 1; offset = (hdata->max_fingers >> 2) + 1;
...@@ -332,9 +329,19 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data, ...@@ -332,9 +329,19 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
int fs_bit_position = (i & 0x3) << 1; int fs_bit_position = (i & 0x3) << 1;
int finger_state = (data[fs_byte_position] >> fs_bit_position) & int finger_state = (data[fs_byte_position] >> fs_bit_position) &
0x03; 0x03;
int position = offset + 5 * i;
if (position + 5 > size) {
/* partial report, go on with what we received */
printk_once(KERN_WARNING
"%s %s: Detected incomplete finger report. Finger reports may occasionally get dropped on this platform.\n",
dev_driver_string(&hdev->dev),
dev_name(&hdev->dev));
hid_dbg(hdev, "Incomplete finger report\n");
break;
}
rmi_f11_process_touch(hdata, i, finger_state, rmi_f11_process_touch(hdata, i, finger_state, &data[position]);
&data[offset + 5 * i]);
} }
input_mt_sync_frame(hdata->input); input_mt_sync_frame(hdata->input);
input_sync(hdata->input); input_sync(hdata->input);
...@@ -352,6 +359,11 @@ static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data, ...@@ -352,6 +359,11 @@ static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
if (!(irq & hdata->f30.irq_mask)) if (!(irq & hdata->f30.irq_mask))
return 0; return 0;
if (size < (int)hdata->f30.report_size) {
hid_warn(hdev, "Click Button pressed, but the click data is missing\n");
return 0;
}
for (i = 0; i < hdata->gpio_led_count; i++) { for (i = 0; i < hdata->gpio_led_count; i++) {
if (test_bit(i, &hdata->button_mask)) { if (test_bit(i, &hdata->button_mask)) {
value = (data[i / 8] >> (i & 0x07)) & BIT(0); value = (data[i / 8] >> (i & 0x07)) & BIT(0);
...@@ -412,9 +424,29 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size) ...@@ -412,9 +424,29 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
return 1; return 1;
} }
static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size)
{
int valid_size = size;
/*
* On the Dell XPS 13 9333, the bus sometimes get confused and fills
* the report with a sentinel value "ff". Synaptics told us that such
* behavior does not comes from the touchpad itself, so we filter out
* such reports here.
*/
while ((data[valid_size - 1] == 0xff) && valid_size > 0)
valid_size--;
return valid_size;
}
static int rmi_raw_event(struct hid_device *hdev, static int rmi_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size) struct hid_report *report, u8 *data, int size)
{ {
size = rmi_check_sanity(hdev, data, size);
if (size < 2)
return 0;
switch (data[0]) { switch (data[0]) {
case RMI_READ_DATA_REPORT_ID: case RMI_READ_DATA_REPORT_ID:
return rmi_read_data_event(hdev, data, size); return rmi_read_data_event(hdev, data, size);
......
...@@ -708,6 +708,9 @@ static const struct hid_device_id sensor_hub_devices[] = { ...@@ -708,6 +708,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
USB_DEVICE_ID_MS_TYPE_COVER_2), USB_DEVICE_ID_MS_TYPE_COVER_2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
USB_DEVICE_ID_STM_HID_SENSOR),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
USB_DEVICE_ID_STM_HID_SENSOR_1), USB_DEVICE_ID_STM_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
......
/* /*
* HID driver for Sony / PS2 / PS3 BD devices. * HID driver for Sony / PS2 / PS3 / PS4 BD devices.
* *
* Copyright (c) 1999 Andreas Gal * Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Copyright (c) 2012 David Dillow <dave@thedillows.org> * Copyright (c) 2012 David Dillow <dave@thedillows.org>
* Copyright (c) 2006-2013 Jiri Kosina * Copyright (c) 2006-2013 Jiri Kosina
* Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
* Copyright (c) 2014 Frank Praznik <frank.praznik@gmail.com>
*/ */
/* /*
...@@ -176,7 +177,7 @@ static u8 dualshock4_usb_rdesc[] = { ...@@ -176,7 +177,7 @@ static u8 dualshock4_usb_rdesc[] = {
0x75, 0x06, /* Report Size (6), */ 0x75, 0x06, /* Report Size (6), */
0x95, 0x01, /* Report Count (1), */ 0x95, 0x01, /* Report Count (1), */
0x15, 0x00, /* Logical Minimum (0), */ 0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x7F, /* Logical Maximum (127), */ 0x25, 0x3F, /* Logical Maximum (63), */
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x05, 0x01, /* Usage Page (Desktop), */ 0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x33, /* Usage (Rx), */ 0x09, 0x33, /* Usage (Rx), */
...@@ -200,14 +201,14 @@ static u8 dualshock4_usb_rdesc[] = { ...@@ -200,14 +201,14 @@ static u8 dualshock4_usb_rdesc[] = {
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x19, 0x43, /* Usage Minimum (43h), */ 0x19, 0x43, /* Usage Minimum (43h), */
0x29, 0x45, /* Usage Maximum (45h), */ 0x29, 0x45, /* Usage Maximum (45h), */
0x16, 0xFF, 0xBF, /* Logical Minimum (-16385), */ 0x16, 0x00, 0xE0, /* Logical Minimum (-8192), */
0x26, 0x00, 0x40, /* Logical Maximum (16384), */ 0x26, 0xFF, 0x1F, /* Logical Maximum (8191), */
0x95, 0x03, /* Report Count (3), */ 0x95, 0x03, /* Report Count (3), */
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x09, 0x21, /* Usage (21h), */ 0x09, 0x21, /* Usage (21h), */
0x15, 0x00, /* Logical Minimum (0), */ 0x15, 0x00, /* Logical Minimum (0), */
0x25, 0xFF, /* Logical Maximum (255), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x75, 0x08, /* Report Size (8), */ 0x75, 0x08, /* Report Size (8), */
0x95, 0x27, /* Report Count (39), */ 0x95, 0x27, /* Report Count (39), */
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
...@@ -395,11 +396,11 @@ static u8 dualshock4_usb_rdesc[] = { ...@@ -395,11 +396,11 @@ static u8 dualshock4_usb_rdesc[] = {
/* /*
* The default behavior of the Dualshock 4 is to send reports using report * The default behavior of the Dualshock 4 is to send reports using report
* type 1 when running over Bluetooth. However, as soon as it receives a * type 1 when running over Bluetooth. However, when feature report 2 is
* report of type 17 to set the LEDs or rumble it starts returning it's state * requested during the controller initialization it starts sending input
* in report 17 instead of 1. Since report 17 is undefined in the default HID * reports in report 17. Since report 17 is undefined in the default HID
* descriptor the button and axis definitions must be moved to report 17 or * descriptor the button and axis definitions must be moved to report 17 or
* the HID layer won't process the received input once a report is sent. * the HID layer won't process the received input.
*/ */
static u8 dualshock4_bt_rdesc[] = { static u8 dualshock4_bt_rdesc[] = {
0x05, 0x01, /* Usage Page (Desktop), */ 0x05, 0x01, /* Usage Page (Desktop), */
...@@ -509,8 +510,8 @@ static u8 dualshock4_bt_rdesc[] = { ...@@ -509,8 +510,8 @@ static u8 dualshock4_bt_rdesc[] = {
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x19, 0x43, /* Usage Minimum (43h), */ 0x19, 0x43, /* Usage Minimum (43h), */
0x29, 0x45, /* Usage Maximum (45h), */ 0x29, 0x45, /* Usage Maximum (45h), */
0x16, 0xFF, 0xBF, /* Logical Minimum (-16385), */ 0x16, 0x00, 0xE0, /* Logical Minimum (-8192), */
0x26, 0x00, 0x40, /* Logical Maximum (16384), */ 0x26, 0xFF, 0x1F, /* Logical Maximum (8191), */
0x95, 0x03, /* Report Count (3), */ 0x95, 0x03, /* Report Count (3), */
0x81, 0x02, /* Input (Variable), */ 0x81, 0x02, /* Input (Variable), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
...@@ -935,12 +936,13 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) ...@@ -935,12 +936,13 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size)
if (rd[30] >= 0xee) { if (rd[30] >= 0xee) {
battery_capacity = 100; battery_capacity = 100;
battery_charging = !(rd[30] & 0x01); battery_charging = !(rd[30] & 0x01);
cable_state = 1;
} else { } else {
__u8 index = rd[30] <= 5 ? rd[30] : 5; __u8 index = rd[30] <= 5 ? rd[30] : 5;
battery_capacity = sixaxis_battery_capacity[index]; battery_capacity = sixaxis_battery_capacity[index];
battery_charging = 0; battery_charging = 0;
cable_state = 0;
} }
cable_state = !(rd[31] & 0x04);
spin_lock_irqsave(&sc->lock, flags); spin_lock_irqsave(&sc->lock, flags);
sc->cable_state = cable_state; sc->cable_state = cable_state;
...@@ -1082,6 +1084,38 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -1082,6 +1084,38 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0; return 0;
} }
static int sony_register_touchpad(struct hid_input *hi, int touch_count,
int w, int h)
{
struct input_dev *input_dev = hi->input;
int ret;
ret = input_mt_init_slots(input_dev, touch_count, 0);
if (ret < 0)
return ret;
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0);
return 0;
}
static void sony_input_configured(struct hid_device *hdev,
struct hid_input *hidinput)
{
struct sony_sc *sc = hid_get_drvdata(hdev);
/*
* The Dualshock 4 touchpad supports 2 touches and has a
* resolution of 1920x942 (44.86 dots/mm).
*/
if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sony_register_touchpad(hidinput, 2, 1920, 942) != 0)
hid_err(sc->hdev,
"Unable to initialize multi-touch slots\n");
}
}
/* /*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any * to "operational". Without this, the ps3 controller will not report any
...@@ -1654,26 +1688,6 @@ static void sony_battery_remove(struct sony_sc *sc) ...@@ -1654,26 +1688,6 @@ static void sony_battery_remove(struct sony_sc *sc)
sc->battery.name = NULL; sc->battery.name = NULL;
} }
static int sony_register_touchpad(struct sony_sc *sc, int touch_count,
int w, int h)
{
struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
int ret;
ret = input_mt_init_slots(input_dev, touch_count, 0);
if (ret < 0) {
hid_err(sc->hdev, "Unable to initialize multi-touch slots\n");
return ret;
}
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0);
return 0;
}
/* /*
* If a controller is plugged in via USB while already connected via Bluetooth * If a controller is plugged in via USB while already connected via Bluetooth
* it will show up as two devices. A global list of connected controllers and * it will show up as two devices. A global list of connected controllers and
...@@ -1923,13 +1937,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1923,13 +1937,6 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop; goto err_stop;
} }
} }
/*
* The Dualshock 4 touchpad supports 2 touches and has a
* resolution of 1920x940.
*/
ret = sony_register_touchpad(sc, 2, 1920, 940);
if (ret < 0)
goto err_stop;
sony_init_work(sc, dualshock4_state_worker); sony_init_work(sc, dualshock4_state_worker);
} else { } else {
...@@ -2037,13 +2044,14 @@ static const struct hid_device_id sony_devices[] = { ...@@ -2037,13 +2044,14 @@ static const struct hid_device_id sony_devices[] = {
MODULE_DEVICE_TABLE(hid, sony_devices); MODULE_DEVICE_TABLE(hid, sony_devices);
static struct hid_driver sony_driver = { static struct hid_driver sony_driver = {
.name = "sony", .name = "sony",
.id_table = sony_devices, .id_table = sony_devices,
.input_mapping = sony_mapping, .input_mapping = sony_mapping,
.probe = sony_probe, .input_configured = sony_input_configured,
.remove = sony_remove, .probe = sony_probe,
.report_fixup = sony_report_fixup, .remove = sony_remove,
.raw_event = sony_raw_event .report_fixup = sony_report_fixup,
.raw_event = sony_raw_event
}; };
static int __init sony_init(void) static int __init sony_init(void)
......
...@@ -208,10 +208,10 @@ static int thingm_init_rgb(struct thingm_rgb *rgb) ...@@ -208,10 +208,10 @@ static int thingm_init_rgb(struct thingm_rgb *rgb)
static void thingm_remove_rgb(struct thingm_rgb *rgb) static void thingm_remove_rgb(struct thingm_rgb *rgb)
{ {
flush_work(&rgb->work);
led_classdev_unregister(&rgb->red.ldev); led_classdev_unregister(&rgb->red.ldev);
led_classdev_unregister(&rgb->green.ldev); led_classdev_unregister(&rgb->green.ldev);
led_classdev_unregister(&rgb->blue.ldev); led_classdev_unregister(&rgb->blue.ldev);
flush_work(&rgb->work);
} }
static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
...@@ -250,6 +250,7 @@ static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -250,6 +250,7 @@ static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!tdev->fwinfo) { if (!tdev->fwinfo) {
hid_err(hdev, "unsupported firmware %c\n", tdev->version.major); hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
err = -ENODEV;
goto stop; goto stop;
} }
...@@ -286,10 +287,10 @@ static void thingm_remove(struct hid_device *hdev) ...@@ -286,10 +287,10 @@ static void thingm_remove(struct hid_device *hdev)
struct thingm_device *tdev = hid_get_drvdata(hdev); struct thingm_device *tdev = hid_get_drvdata(hdev);
int i; int i;
hid_hw_stop(hdev);
for (i = 0; i < tdev->fwinfo->numrgb; ++i) for (i = 0; i < tdev->fwinfo->numrgb; ++i)
thingm_remove_rgb(tdev->rgb + i); thingm_remove_rgb(tdev->rgb + i);
hid_hw_stop(hdev);
} }
static const struct hid_device_id thingm_table[] = { static const struct hid_device_id thingm_table[] = {
......
This diff is collapsed.
...@@ -82,7 +82,7 @@ static int hid_start_in(struct hid_device *hid) ...@@ -82,7 +82,7 @@ static int hid_start_in(struct hid_device *hid)
struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data;
spin_lock_irqsave(&usbhid->lock, flags); spin_lock_irqsave(&usbhid->lock, flags);
if (hid->open > 0 && if ((hid->open > 0 || hid->quirks & HID_QUIRK_ALWAYS_POLL) &&
!test_bit(HID_DISCONNECTED, &usbhid->iofl) && !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
!test_bit(HID_SUSPENDED, &usbhid->iofl) && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
...@@ -116,40 +116,24 @@ static void hid_reset(struct work_struct *work) ...@@ -116,40 +116,24 @@ static void hid_reset(struct work_struct *work)
struct usbhid_device *usbhid = struct usbhid_device *usbhid =
container_of(work, struct usbhid_device, reset_work); container_of(work, struct usbhid_device, reset_work);
struct hid_device *hid = usbhid->hid; struct hid_device *hid = usbhid->hid;
int rc = 0; int rc;
if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
dev_dbg(&usbhid->intf->dev, "clear halt\n"); dev_dbg(&usbhid->intf->dev, "clear halt\n");
rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe); rc = usb_clear_halt(hid_to_usb_dev(hid), usbhid->urbin->pipe);
clear_bit(HID_CLEAR_HALT, &usbhid->iofl); clear_bit(HID_CLEAR_HALT, &usbhid->iofl);
hid_start_in(hid);
}
else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
dev_dbg(&usbhid->intf->dev, "resetting device\n");
rc = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
if (rc == 0) { if (rc == 0) {
rc = usb_reset_device(hid_to_usb_dev(hid)); hid_start_in(hid);
usb_unlock_device(hid_to_usb_dev(hid)); } else {
dev_dbg(&usbhid->intf->dev,
"clear-halt failed: %d\n", rc);
set_bit(HID_RESET_PENDING, &usbhid->iofl);
} }
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
} }
switch (rc) { if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
case 0: dev_dbg(&usbhid->intf->dev, "resetting device\n");
if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) usb_queue_reset_device(usbhid->intf);
hid_io_error(hid);
break;
default:
hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n",
hid_to_usb_dev(hid)->bus->bus_name,
hid_to_usb_dev(hid)->devpath,
usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
case -EINTR:
break;
} }
} }
...@@ -292,6 +276,8 @@ static void hid_irq_in(struct urb *urb) ...@@ -292,6 +276,8 @@ static void hid_irq_in(struct urb *urb)
case 0: /* success */ case 0: /* success */
usbhid_mark_busy(usbhid); usbhid_mark_busy(usbhid);
usbhid->retry_delay = 0; usbhid->retry_delay = 0;
if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open)
break;
hid_input_report(urb->context, HID_INPUT_REPORT, hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer, urb->transfer_buffer,
urb->actual_length, 1); urb->actual_length, 1);
...@@ -735,8 +721,10 @@ void usbhid_close(struct hid_device *hid) ...@@ -735,8 +721,10 @@ void usbhid_close(struct hid_device *hid)
if (!--hid->open) { if (!--hid->open) {
spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock);
hid_cancel_delayed_stuff(usbhid); hid_cancel_delayed_stuff(usbhid);
usb_kill_urb(usbhid->urbin); if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) {
usbhid->intf->needs_remote_wakeup = 0; usb_kill_urb(usbhid->urbin);
usbhid->intf->needs_remote_wakeup = 0;
}
} else { } else {
spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock);
} }
...@@ -1134,6 +1122,19 @@ static int usbhid_start(struct hid_device *hid) ...@@ -1134,6 +1122,19 @@ static int usbhid_start(struct hid_device *hid)
set_bit(HID_STARTED, &usbhid->iofl); set_bit(HID_STARTED, &usbhid->iofl);
if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
ret = usb_autopm_get_interface(usbhid->intf);
if (ret)
goto fail;
usbhid->intf->needs_remote_wakeup = 1;
ret = hid_start_in(hid);
if (ret) {
dev_err(&hid->dev,
"failed to start in urb: %d\n", ret);
}
usb_autopm_put_interface(usbhid->intf);
}
/* Some keyboards don't work until their LEDs have been set. /* Some keyboards don't work until their LEDs have been set.
* Since BIOSes do set the LEDs, it must be safe for any device * Since BIOSes do set the LEDs, it must be safe for any device
* that supports the keyboard boot protocol. * that supports the keyboard boot protocol.
...@@ -1166,6 +1167,9 @@ static void usbhid_stop(struct hid_device *hid) ...@@ -1166,6 +1167,9 @@ static void usbhid_stop(struct hid_device *hid)
if (WARN_ON(!usbhid)) if (WARN_ON(!usbhid))
return; return;
if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
usbhid->intf->needs_remote_wakeup = 0;
clear_bit(HID_STARTED, &usbhid->iofl); clear_bit(HID_STARTED, &usbhid->iofl);
spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */
set_bit(HID_DISCONNECTED, &usbhid->iofl); set_bit(HID_DISCONNECTED, &usbhid->iofl);
......
...@@ -70,6 +70,7 @@ static const struct hid_blacklist { ...@@ -70,6 +70,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
...@@ -79,6 +80,8 @@ static const struct hid_blacklist { ...@@ -79,6 +80,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
......
...@@ -89,6 +89,7 @@ ...@@ -89,6 +89,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/hid.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -143,4 +144,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev, ...@@ -143,4 +144,9 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac); struct wacom_wac *wacom_wac);
int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac); struct wacom_wac *wacom_wac);
void wacom_wac_usage_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage);
int wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
#endif #endif
This diff is collapsed.
This diff is collapsed.
...@@ -113,6 +113,7 @@ enum { ...@@ -113,6 +113,7 @@ enum {
MTSCREEN, MTSCREEN,
MTTPC, MTTPC,
MTTPC_B, MTTPC_B,
HID_GENERIC,
MAX_TYPE MAX_TYPE
}; };
...@@ -154,6 +155,20 @@ struct wacom_shared { ...@@ -154,6 +155,20 @@ struct wacom_shared {
struct input_dev *touch_input; struct input_dev *touch_input;
}; };
struct hid_data {
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s16 inputmode_index; /* InputMode HID feature index in the report */
bool inrange_state;
bool invert_state;
bool tipswitch;
int x;
int y;
int pressure;
int width;
int height;
int id;
};
struct wacom_wac { struct wacom_wac {
char name[WACOM_NAME_MAX]; char name[WACOM_NAME_MAX];
char pad_name[WACOM_NAME_MAX]; char pad_name[WACOM_NAME_MAX];
...@@ -167,6 +182,7 @@ struct wacom_wac { ...@@ -167,6 +182,7 @@ struct wacom_wac {
struct wacom_shared *shared; struct wacom_shared *shared;
struct input_dev *input; struct input_dev *input;
struct input_dev *pad_input; struct input_dev *pad_input;
bool input_registered;
int pid; int pid;
int battery_capacity; int battery_capacity;
int num_contacts_left; int num_contacts_left;
...@@ -174,6 +190,7 @@ struct wacom_wac { ...@@ -174,6 +190,7 @@ struct wacom_wac {
int ps_connected; int ps_connected;
u8 bt_features; u8 bt_features;
u8 bt_high_speed; u8 bt_high_speed;
struct hid_data hid_data;
}; };
#endif #endif
...@@ -265,6 +265,7 @@ struct hid_item { ...@@ -265,6 +265,7 @@ struct hid_item {
#define HID_CONNECT_HIDDEV 0x08 #define HID_CONNECT_HIDDEV 0x08
#define HID_CONNECT_HIDDEV_FORCE 0x10 #define HID_CONNECT_HIDDEV_FORCE 0x10
#define HID_CONNECT_FF 0x20 #define HID_CONNECT_FF 0x20
#define HID_CONNECT_DRIVER 0x40
#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \ #define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
HID_CONNECT_HIDDEV|HID_CONNECT_FF) HID_CONNECT_HIDDEV|HID_CONNECT_FF)
...@@ -287,6 +288,7 @@ struct hid_item { ...@@ -287,6 +288,7 @@ struct hid_item {
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 #define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 #define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 #define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
#define HID_QUIRK_ALWAYS_POLL 0x00000400
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000 #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000
...@@ -440,6 +442,7 @@ struct hid_output_fifo { ...@@ -440,6 +442,7 @@ struct hid_output_fifo {
#define HID_CLAIMED_INPUT 1 #define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 2 #define HID_CLAIMED_HIDDEV 2
#define HID_CLAIMED_HIDRAW 4 #define HID_CLAIMED_HIDRAW 4
#define HID_CLAIMED_DRIVER 8
#define HID_STAT_ADDED 1 #define HID_STAT_ADDED 1
#define HID_STAT_PARSED 2 #define HID_STAT_PARSED 2
......
...@@ -24,35 +24,23 @@ ...@@ -24,35 +24,23 @@
#include <linux/hid.h> #include <linux/hid.h>
enum uhid_event_type { enum uhid_event_type {
UHID_CREATE, __UHID_LEGACY_CREATE,
UHID_DESTROY, UHID_DESTROY,
UHID_START, UHID_START,
UHID_STOP, UHID_STOP,
UHID_OPEN, UHID_OPEN,
UHID_CLOSE, UHID_CLOSE,
UHID_OUTPUT, UHID_OUTPUT,
UHID_OUTPUT_EV, /* obsolete! */ __UHID_LEGACY_OUTPUT_EV,
UHID_INPUT, __UHID_LEGACY_INPUT,
UHID_FEATURE, UHID_GET_REPORT,
UHID_FEATURE_ANSWER, UHID_GET_REPORT_REPLY,
UHID_CREATE2, UHID_CREATE2,
UHID_INPUT2, UHID_INPUT2,
UHID_SET_REPORT,
UHID_SET_REPORT_REPLY,
}; };
struct uhid_create_req {
__u8 name[128];
__u8 phys[64];
__u8 uniq[64];
__u8 __user *rd_data;
__u16 rd_size;
__u16 bus;
__u32 vendor;
__u32 product;
__u32 version;
__u32 country;
} __attribute__((__packed__));
struct uhid_create2_req { struct uhid_create2_req {
__u8 name[128]; __u8 name[128];
__u8 phys[64]; __u8 phys[64];
...@@ -66,6 +54,16 @@ struct uhid_create2_req { ...@@ -66,6 +54,16 @@ struct uhid_create2_req {
__u8 rd_data[HID_MAX_DESCRIPTOR_SIZE]; __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
} __attribute__((__packed__)); } __attribute__((__packed__));
enum uhid_dev_flag {
UHID_DEV_NUMBERED_FEATURE_REPORTS = (1ULL << 0),
UHID_DEV_NUMBERED_OUTPUT_REPORTS = (1ULL << 1),
UHID_DEV_NUMBERED_INPUT_REPORTS = (1ULL << 2),
};
struct uhid_start_req {
__u64 dev_flags;
};
#define UHID_DATA_MAX 4096 #define UHID_DATA_MAX 4096
enum uhid_report_type { enum uhid_report_type {
...@@ -74,36 +72,94 @@ enum uhid_report_type { ...@@ -74,36 +72,94 @@ enum uhid_report_type {
UHID_INPUT_REPORT, UHID_INPUT_REPORT,
}; };
struct uhid_input_req { struct uhid_input2_req {
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));
struct uhid_output_req {
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
__u16 size; __u16 size;
__u8 rtype;
} __attribute__((__packed__)); } __attribute__((__packed__));
struct uhid_input2_req { struct uhid_get_report_req {
__u32 id;
__u8 rnum;
__u8 rtype;
} __attribute__((__packed__));
struct uhid_get_report_reply_req {
__u32 id;
__u16 err;
__u16 size; __u16 size;
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
} __attribute__((__packed__)); } __attribute__((__packed__));
struct uhid_output_req { struct uhid_set_report_req {
__u32 id;
__u8 rnum;
__u8 rtype;
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));
struct uhid_set_report_reply_req {
__u32 id;
__u16 err;
} __attribute__((__packed__));
/*
* Compat Layer
* All these commands and requests are obsolete. You should avoid using them in
* new code. We support them for backwards-compatibility, but you might not get
* access to new feature in case you use them.
*/
enum uhid_legacy_event_type {
UHID_CREATE = __UHID_LEGACY_CREATE,
UHID_OUTPUT_EV = __UHID_LEGACY_OUTPUT_EV,
UHID_INPUT = __UHID_LEGACY_INPUT,
UHID_FEATURE = UHID_GET_REPORT,
UHID_FEATURE_ANSWER = UHID_GET_REPORT_REPLY,
};
/* Obsolete! Use UHID_CREATE2. */
struct uhid_create_req {
__u8 name[128];
__u8 phys[64];
__u8 uniq[64];
__u8 __user *rd_data;
__u16 rd_size;
__u16 bus;
__u32 vendor;
__u32 product;
__u32 version;
__u32 country;
} __attribute__((__packed__));
/* Obsolete! Use UHID_INPUT2. */
struct uhid_input_req {
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
__u16 size; __u16 size;
__u8 rtype;
} __attribute__((__packed__)); } __attribute__((__packed__));
/* Obsolete! Newer kernels will no longer send these events but instead convert /* Obsolete! Kernel uses UHID_OUTPUT exclusively now. */
* it into raw output reports via UHID_OUTPUT. */
struct uhid_output_ev_req { struct uhid_output_ev_req {
__u16 type; __u16 type;
__u16 code; __u16 code;
__s32 value; __s32 value;
} __attribute__((__packed__)); } __attribute__((__packed__));
/* Obsolete! Kernel uses ABI compatible UHID_GET_REPORT. */
struct uhid_feature_req { struct uhid_feature_req {
__u32 id; __u32 id;
__u8 rnum; __u8 rnum;
__u8 rtype; __u8 rtype;
} __attribute__((__packed__)); } __attribute__((__packed__));
/* Obsolete! Use ABI compatible UHID_GET_REPORT_REPLY. */
struct uhid_feature_answer_req { struct uhid_feature_answer_req {
__u32 id; __u32 id;
__u16 err; __u16 err;
...@@ -111,6 +167,15 @@ struct uhid_feature_answer_req { ...@@ -111,6 +167,15 @@ struct uhid_feature_answer_req {
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
} __attribute__((__packed__)); } __attribute__((__packed__));
/*
* UHID Events
* All UHID events from and to the kernel are encoded as "struct uhid_event".
* The "type" field contains a UHID_* type identifier. All payload depends on
* that type and can be accessed via ev->u.XYZ accordingly.
* If user-space writes short events, they're extended with 0s by the kernel. If
* the kernel writes short events, user-space shall extend them with 0s.
*/
struct uhid_event { struct uhid_event {
__u32 type; __u32 type;
...@@ -120,9 +185,14 @@ struct uhid_event { ...@@ -120,9 +185,14 @@ struct uhid_event {
struct uhid_output_req output; struct uhid_output_req output;
struct uhid_output_ev_req output_ev; struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature; struct uhid_feature_req feature;
struct uhid_get_report_req get_report;
struct uhid_feature_answer_req feature_answer; struct uhid_feature_answer_req feature_answer;
struct uhid_get_report_reply_req get_report_reply;
struct uhid_create2_req create2; struct uhid_create2_req create2;
struct uhid_input2_req input2; struct uhid_input2_req input2;
struct uhid_set_report_req set_report;
struct uhid_set_report_reply_req set_report_reply;
struct uhid_start_req start;
} u; } u;
} __attribute__((__packed__)); } __attribute__((__packed__));
......
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