summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-14 16:20:42 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-14 16:20:42 -0800
commitc2848f2eef4dd08b0fd2a8eba1694fd8e77ddb67 (patch)
tree8e84e3cc86074aabd3d2ea9c48e33221bc01d4fe
parent75f26df6ae6f8787fc6198609c8be17400a69e25 (diff)
parent83f1bfd6f57c422da70d1e296df1becc35c868be (diff)
downloadlinux-c2848f2eef4dd08b0fd2a8eba1694fd8e77ddb67.tar.bz2
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - appoint Benjamin Tissoires as co-maintainer / designated reviewer - sysfs report_descriptor visibility fix for unclaimed devices, from Andy Lutomirski - suspend/resume fixes for Sony driver from Frank Praznik - IRQ deadlock fix from Ioan-Adrian Ratiu - hid-i2c fixes affecting (at least) Yoga 900 from Mika Westerberg and Srinivas Pandruvada - a lot of new device support (especially, but not limited to, Wacom) and assorted small misc fixes - almost complete G920 support; the only bit that is missing is switching the device to HID mode automatically; Simon Wood and Michal Maly are working on it. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (46 commits) Revert "INPUT: xpad: switch Logitech G920 Wheel into HID mode" HID: sensor-hub: Add quirk for Lenovo Yoga 900 with ITE Chips HID: Add new PID for Microchip Pick16F1454 HID: wacom: Use correct report to query pen ID from INTUOSHT2 devices HID: i2c-hid: Prevent sending reports from racing with device reset HID: use kobj_to_dev() HID: wiimote: use dev_to_wii() HID: add a new helper to_hid_driver() HID: use to_hid_device() HID: move to_hid_device() to hid.h HID: usbhid: use to_usb_device HID: corsair: Convert to use module_hid_driver HID: input: ignore the battery in OKLICK Laser BTmouse HID: wacom: Fix pad button range for CINTIQ_COMPANION_2 HID: wacom: Fix touchring value reporting HID: wacom: Report 'strip2' values in ABS_RY HID: wacom: Limit touchstrip data to 13 bits HID: wacom: bitwise vs logical ORs HID: wacom: Apply lowres quirk to BAMBOO_TOUCH devices HID: enable hid device to suspend/resume asynchronously ...
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/hid/hid-core.c49
-rw-r--r--drivers/hid/hid-corsair.c13
-rw-r--r--drivers/hid/hid-cp2112.c8
-rw-r--r--drivers/hid/hid-debug.c4
-rw-r--r--drivers/hid/hid-gt683r.c8
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-input.c21
-rw-r--r--drivers/hid/hid-lenovo.c36
-rw-r--r--drivers/hid/hid-lg4ff.c6
-rw-r--r--drivers/hid/hid-logitech-hidpp.c286
-rw-r--r--drivers/hid/hid-multitouch.c24
-rw-r--r--drivers/hid/hid-ntrig.c32
-rw-r--r--drivers/hid/hid-picolcd_leds.c4
-rw-r--r--drivers/hid/hid-prodikeys.c12
-rw-r--r--drivers/hid/hid-roccat-arvo.c6
-rw-r--r--drivers/hid/hid-roccat-common.c6
-rw-r--r--drivers/hid/hid-roccat-isku.c6
-rw-r--r--drivers/hid/hid-roccat-kone.c12
-rw-r--r--drivers/hid/hid-roccat-koneplus.c12
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c12
-rw-r--r--drivers/hid/hid-roccat-lua.c4
-rw-r--r--drivers/hid/hid-roccat-pyra.c15
-rw-r--r--drivers/hid/hid-sensor-hub.c3
-rw-r--r--drivers/hid/hid-sony.c107
-rw-r--r--drivers/hid/hid-steelseries.c8
-rw-r--r--drivers/hid/hid-wiimote-modules.c8
-rw-r--r--drivers/hid/hid-wiimote.h3
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c22
-rw-r--r--drivers/hid/usbhid/hid-core.c6
-rw-r--r--drivers/hid/usbhid/usbhid.h2
-rw-r--r--drivers/hid/wacom_sys.c23
-rw-r--r--drivers/hid/wacom_wac.c617
-rw-r--r--drivers/hid/wacom_wac.h5
-rw-r--r--include/linux/hid.h8
35 files changed, 819 insertions, 574 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index ab68d0597542..5696e08918f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4984,6 +4984,7 @@ F: arch/*/include/asm/suspend*.h
HID CORE LAYER
M: Jiri Kosina <jikos@kernel.org>
+R: Benjamin Tissoires <benjamin.tissoires@redhat.com>
L: linux-input@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
@@ -11162,6 +11163,7 @@ F: include/linux/usb/gadget*
USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REMOTE CONTROLS, ...)
M: Jiri Kosina <jikos@kernel.org>
+R: Benjamin Tissoires <benjamin.tissoires@redhat.com>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c6f7a694f67a..7e89288b1537 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -625,7 +625,7 @@ static void hid_close_report(struct hid_device *device)
static void hid_device_release(struct device *dev)
{
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
hid_close_report(hid);
kfree(hid->dev_rdesc);
@@ -1571,8 +1571,8 @@ read_report_descriptor(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj);
+ struct hid_device *hdev = to_hid_device(dev);
if (off >= hdev->rsize)
return 0;
@@ -1589,7 +1589,7 @@ static ssize_t
show_country(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
return sprintf(buf, "%02x\n", hdev->country & 0xff);
}
@@ -1691,11 +1691,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
hid_warn(hdev,
"can't create sysfs country code attribute err: %d\n", ret);
- ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
- if (ret)
- hid_warn(hdev,
- "can't create sysfs report descriptor attribute err: %d\n", ret);
-
hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
buf, bus, hdev->version >> 8, hdev->version & 0xff,
type, hdev->name, hdev->phys);
@@ -1707,7 +1702,6 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev)
{
device_remove_file(&hdev->dev, &dev_attr_country);
- device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev);
if (hdev->claimed & HID_CLAIMED_HIDDEV)
@@ -1902,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
@@ -2076,7 +2071,7 @@ struct hid_dynid {
static ssize_t store_new_id(struct device_driver *drv, const char *buf,
size_t count)
{
- struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+ struct hid_driver *hdrv = to_hid_driver(drv);
struct hid_dynid *dynid;
__u32 bus, vendor, product;
unsigned long driver_data = 0;
@@ -2138,17 +2133,16 @@ static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
static int hid_bus_match(struct device *dev, struct device_driver *drv)
{
- struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_driver *hdrv = to_hid_driver(drv);
+ struct hid_device *hdev = to_hid_device(dev);
return hid_match_device(hdev, hdrv) != NULL;
}
static int hid_device_probe(struct device *dev)
{
- struct hid_driver *hdrv = container_of(dev->driver,
- struct hid_driver, driver);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_driver *hdrv = to_hid_driver(dev->driver);
+ struct hid_device *hdev = to_hid_device(dev);
const struct hid_device_id *id;
int ret = 0;
@@ -2190,7 +2184,7 @@ unlock_driver_lock:
static int hid_device_remove(struct device *dev)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct hid_driver *hdrv;
int ret = 0;
@@ -2223,12 +2217,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
char *buf)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- int len;
-
- len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
- hdev->bus, hdev->group, hdev->vendor, hdev->product);
- return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+ return scnprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product);
}
static DEVICE_ATTR_RO(modalias);
@@ -2236,11 +2227,19 @@ static struct attribute *hid_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL,
};
-ATTRIBUTE_GROUPS(hid_dev);
+static struct bin_attribute *hid_dev_bin_attrs[] = {
+ &dev_bin_attr_report_desc,
+ NULL
+};
+static const struct attribute_group hid_dev_group = {
+ .attrs = hid_dev_attrs,
+ .bin_attrs = hid_dev_bin_attrs,
+};
+__ATTRIBUTE_GROUPS(hid_dev);
static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
hdev->bus, hdev->vendor, hdev->product))
@@ -2408,6 +2407,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454_V2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
@@ -2660,6 +2660,7 @@ struct hid_device *hid_allocate_device(void)
device_initialize(&hdev->dev);
hdev->dev.release = hid_device_release;
hdev->dev.bus = &hid_bus_type;
+ device_enable_async_suspend(&hdev->dev);
hid_close_report(hdev);
diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c
index bcefb9ebb026..58551964ce86 100644
--- a/drivers/hid/hid-corsair.c
+++ b/drivers/hid/hid-corsair.c
@@ -655,18 +655,7 @@ static struct hid_driver corsair_driver = {
.input_mapping = corsair_input_mapping,
};
-static int __init corsair_init(void)
-{
- return hid_register_driver(&corsair_driver);
-}
-
-static void corsair_exit(void)
-{
- hid_unregister_driver(&corsair_driver);
-}
-
-module_init(corsair_init);
-module_exit(corsair_exit);
+module_hid_driver(corsair_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Clement Vuchener");
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 7afc3fcc122c..7c38bfa05fac 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -807,7 +807,7 @@ static ssize_t name##_store(struct device *kdev, \
struct device_attribute *attr, const char *buf, \
size_t count) \
{ \
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct hid_device *hdev = to_hid_device(kdev); \
struct cp2112_usb_config_report cfg; \
int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \
@@ -822,7 +822,7 @@ static ssize_t name##_store(struct device *kdev, \
static ssize_t name##_show(struct device *kdev, \
struct device_attribute *attr, char *buf) \
{ \
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev); \
+ struct hid_device *hdev = to_hid_device(kdev); \
struct cp2112_usb_config_report cfg; \
int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \
@@ -887,7 +887,7 @@ static ssize_t pstr_store(struct device *kdev,
struct device_attribute *kattr, const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report;
@@ -918,7 +918,7 @@ static ssize_t pstr_store(struct device *kdev,
static ssize_t pstr_show(struct device *kdev,
struct device_attribute *kattr, char *buf)
{
- struct hid_device *hdev = container_of(kdev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(kdev);
struct cp2112_pstring_attribute *attr =
container_of(kattr, struct cp2112_pstring_attribute, attr);
struct cp2112_string_report report;
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 2886b645ced7..acfb522a432a 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -659,13 +659,13 @@ EXPORT_SYMBOL_GPL(hid_dump_device);
/* enqueue string to 'events' ring buffer */
void hid_debug_event(struct hid_device *hdev, char *buf)
{
- int i;
+ unsigned i;
struct hid_debug_list *list;
unsigned long flags;
spin_lock_irqsave(&hdev->debug_list_lock, flags);
list_for_each_entry(list, &hdev->debug_list, node) {
- for (i = 0; i < strlen(buf); i++)
+ for (i = 0; buf[i]; i++)
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
index 0d6f135e266c..a298fbd8db6b 100644
--- a/drivers/hid/hid-gt683r.c
+++ b/drivers/hid/hid-gt683r.c
@@ -70,7 +70,7 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
{
int i;
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
for (i = 0; i < GT683R_LED_COUNT; i++) {
@@ -89,8 +89,7 @@ static ssize_t mode_show(struct device *dev,
char *buf)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev->parent,
- struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev->parent);
struct gt683r_led *led = hid_get_drvdata(hdev);
if (led->mode == GT683R_LED_NORMAL)
@@ -108,8 +107,7 @@ static ssize_t mode_store(struct device *dev,
const char *buf, size_t count)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev->parent,
- struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev->parent);
struct gt683r_led *led = hid_get_drvdata(hdev);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8b78a7f1f779..b6ff6e78ac54 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -510,6 +510,7 @@
#define USB_VENDOR_ID_ITE 0x048d
#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350
+#define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396
#define USB_VENDOR_ID_JABRA 0x0b0e
#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
@@ -615,6 +616,7 @@
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
+#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
@@ -664,6 +666,7 @@
#define USB_DEVICE_ID_PICOLCD 0xc002
#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002
#define USB_DEVICE_ID_PICK16F1454 0x0042
+#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7
#define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 2ba6bf69b7d0..bcfaf32d9e5e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -303,6 +303,7 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
+#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -320,6 +321,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
+ USB_DEVICE_ID_ELECOM_BM084),
+ HID_BATTERY_QUIRK_IGNORE },
{}
};
@@ -408,6 +412,14 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
if (dev->battery != NULL)
goto out; /* already initialized? */
+ quirks = find_battery_quirk(dev);
+
+ hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
+ dev->bus, dev->vendor, dev->product, dev->version, quirks);
+
+ if (quirks & HID_BATTERY_QUIRK_IGNORE)
+ goto out;
+
psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
if (psy_desc == NULL)
goto out;
@@ -424,11 +436,6 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
psy_desc->use_for_apm = 0;
psy_desc->get_property = hidinput_get_battery_property;
- quirks = find_battery_quirk(dev);
-
- hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
- dev->bus, dev->vendor, dev->product, dev->version, quirks);
-
min = field->logical_minimum;
max = field->logical_maximum;
@@ -960,6 +967,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
case HID_UP_LOGIVENDOR:
+ /* intentional fallback */
+ case HID_UP_LOGIVENDOR2:
+ /* intentional fallback */
+ case HID_UP_LOGIVENDOR3:
goto ignore;
case HID_UP_PID:
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 8979f1fd5208..0125e356bd8d 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -220,7 +220,7 @@ static ssize_t attr_fn_lock_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", cptkbd_data->fn_lock);
@@ -231,7 +231,7 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
int value;
@@ -250,7 +250,7 @@ static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -262,7 +262,7 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
int value;
@@ -387,7 +387,7 @@ static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
@@ -398,7 +398,7 @@ static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -417,7 +417,7 @@ static ssize_t attr_dragging_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
@@ -428,7 +428,7 @@ static ssize_t attr_dragging_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -447,7 +447,7 @@ static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
@@ -458,7 +458,7 @@ static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -477,7 +477,7 @@ static ssize_t attr_select_right_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
@@ -488,7 +488,7 @@ static ssize_t attr_select_right_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -507,7 +507,7 @@ static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -519,7 +519,7 @@ static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -536,7 +536,7 @@ static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
@@ -548,7 +548,7 @@ static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
const char *buf,
size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int value;
@@ -609,7 +609,7 @@ static enum led_brightness lenovo_led_brightness_get_tpkbd(
struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
int led_nr = 0;
@@ -625,7 +625,7 @@ static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
struct hid_report *report;
int led_nr = 0;
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index fbddcb37ae98..af3a8ec8a746 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -33,8 +33,6 @@
#include "hid-lg4ff.h"
#include "hid-ids.h"
-#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
-
#define LG4FF_MMODE_IS_MULTIMODE 0
#define LG4FF_MMODE_SWITCHED 1
#define LG4FF_MMODE_NOT_MULTIMODE 2
@@ -1020,7 +1018,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct lg_drv_data *drv_data = hid_get_drvdata(hid);
struct lg4ff_device_entry *entry;
int i, state = 0;
@@ -1055,7 +1053,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct lg_drv_data *drv_data = hid_get_drvdata(hid);
struct lg4ff_device_entry *entry;
int i, value = 0;
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 5fd97860aec4..bd2ab476c65e 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -40,18 +40,22 @@ MODULE_PARM_DESC(disable_tap_to_click,
#define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11
+#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20
+#define HIDPP_REPORT_VERY_LONG_LENGTH 64
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
#define HIDPP_QUIRK_CLASS_K400 BIT(2)
+#define HIDPP_QUIRK_CLASS_G920 BIT(3)
/* bits 2..20 are reserved for classes */
#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
+#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
#define HIDPP_QUIRK_DELAYED_INIT (HIDPP_QUIRK_NO_HIDINPUT | \
HIDPP_QUIRK_CONNECT_EVENTS)
@@ -81,13 +85,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
struct fap {
u8 feature_index;
u8 funcindex_clientid;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct rap {
u8 sub_id;
u8 reg_address;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct hidpp_report {
@@ -144,8 +148,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
static int __hidpp_send_report(struct hid_device *hdev,
struct hidpp_report *hidpp_report)
{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
int fields_count, ret;
+ hidpp = hid_get_drvdata(hdev);
+
switch (hidpp_report->report_id) {
case REPORT_ID_HIDPP_SHORT:
fields_count = HIDPP_REPORT_SHORT_LENGTH;
@@ -153,6 +160,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
case REPORT_ID_HIDPP_LONG:
fields_count = HIDPP_REPORT_LONG_LENGTH;
break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
+ break;
default:
return -ENODEV;
}
@@ -163,9 +173,13 @@ static int __hidpp_send_report(struct hid_device *hdev,
*/
hidpp_report->device_index = 0xff;
- ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
- (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
- HID_REQ_SET_REPORT);
+ if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
+ ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
+ } else {
+ ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
+ (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
+ }
return ret == fields_count ? 0 : -1;
}
@@ -217,8 +231,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
goto exit;
}
- if (response->report_id == REPORT_ID_HIDPP_LONG &&
- response->fap.feature_index == HIDPP20_ERROR) {
+ if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+ response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+ response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1];
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit;
@@ -243,7 +258,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
if (!message)
return -ENOMEM;
- message->report_id = REPORT_ID_HIDPP_LONG;
+
+ if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
+ message->report_id = REPORT_ID_HIDPP_VERY_LONG;
+ else
+ message->report_id = REPORT_ID_HIDPP_LONG;
message->fap.feature_index = feat_index;
message->fap.funcindex_clientid = funcindex_clientid;
memcpy(&message->fap.params, params, param_count);
@@ -258,13 +277,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
struct hidpp_report *response)
{
struct hidpp_report *message;
- int ret;
+ int ret, max_count;
- if ((report_id != REPORT_ID_HIDPP_SHORT) &&
- (report_id != REPORT_ID_HIDPP_LONG))
+ switch (report_id) {
+ case REPORT_ID_HIDPP_SHORT:
+ max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
+ max_count = HIDPP_REPORT_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ default:
return -EINVAL;
+ }
- if (param_count > sizeof(message->rap.params))
+ if (param_count > max_count)
return -EINVAL;
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -508,10 +537,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
if (ret)
return ret;
- if (response.report_id == REPORT_ID_HIDPP_LONG)
+ switch (response.report_id) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
count = HIDPP_REPORT_LONG_LENGTH - 4;
- else
+ break;
+ case REPORT_ID_HIDPP_SHORT:
count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ default:
+ return -EPROTO;
+ }
if (len_buf < count)
count = len_buf;
@@ -1257,6 +1295,131 @@ static int k400_connect(struct hid_device *hdev, bool connected)
return k400_disable_tap_to_click(hidpp);
}
+/* ------------------------------------------------------------------------- */
+/* Logitech G920 Driving Force Racing Wheel for Xbox One */
+/* ------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
+
+/* Using session ID = 1 */
+#define CMD_G920_FORCE_GET_APERTURE 0x51
+#define CMD_G920_FORCE_SET_APERTURE 0x61
+
+struct g920_private_data {
+ u8 force_feature;
+ u16 range;
+};
+
+static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range);
+}
+
+static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+ struct hidpp_report response;
+ u8 params[2];
+ int ret;
+ u16 range = simple_strtoul(buf, NULL, 10);
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ if (range < 180)
+ range = 180;
+ else if (range > 900)
+ range = 900;
+
+ params[0] = range >> 8;
+ params[1] = range & 0x00FF;
+
+ ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature,
+ CMD_G920_FORCE_SET_APERTURE, params, 2, &response);
+ if (ret)
+ return ret;
+
+ pdata->range = range;
+ return count;
+}
+
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store);
+
+static int g920_allocate(struct hid_device *hdev)
+{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ struct g920_private_data *pdata;
+
+ pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ hidpp->private_data = pdata;
+
+ return 0;
+}
+
+static int g920_get_config(struct hidpp_device *hidpp)
+{
+ struct g920_private_data *pdata = hidpp->private_data;
+ struct hidpp_report response;
+ u8 feature_type;
+ u8 feature_index;
+ int ret;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hidpp->hid_dev, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ /* Find feature and store for later use */
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
+ &feature_index, &feature_type);
+ if (ret)
+ return ret;
+
+ pdata->force_feature = feature_index;
+
+ /* Read current Range */
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response);
+ if (ret > 0) {
+ hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+ __func__, ret);
+ return -EPROTO;
+ }
+ if (ret)
+ return ret;
+
+ pdata->range = get_unaligned_be16(&response.fap.params[0]);
+
+ /* Create sysfs interface */
+ ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
+ if (ret)
+ hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret);
+
+ return 0;
+}
+
/* -------------------------------------------------------------------------- */
/* Generic HID++ devices */
/* -------------------------------------------------------------------------- */
@@ -1276,6 +1439,25 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
+static int hidpp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+
+ /* Ensure that Logitech G920 is not given a default fuzz/flat value */
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ if (usage->type == EV_ABS && (usage->code == ABS_X ||
+ usage->code == ABS_Y || usage->code == ABS_Z ||
+ usage->code == ABS_RZ)) {
+ field->application = HID_GD_MULTIAXIS;
+ }
+ }
+
+ return 0;
+}
+
+
static void hidpp_populate_input(struct hidpp_device *hidpp,
struct input_dev *input, bool origin_is_hid_core)
{
@@ -1347,6 +1529,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
/* Generic HID++ processing. */
switch (data[0]) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
+ hid_err(hdev, "received hid++ report of bad size (%d)",
+ size);
+ return 1;
+ }
+ ret = hidpp_raw_hidpp_event(hidpp, data, size);
+ break;
case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)",
@@ -1393,10 +1583,12 @@ static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
else
name = hidpp_get_device_name(hidpp);
- if (!name)
+ if (!name) {
hid_err(hdev, "unable to retrieve the name of the device");
- else
+ } else {
+ dbg_hid("HID++: Got name: %s\n", name);
snprintf(hdev->name, sizeof(hdev->name), "%s", name);
+ }
kfree(name);
}
@@ -1547,6 +1739,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = k400_allocate(hdev);
if (ret)
goto allocate_fail;
+ } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = g920_allocate(hdev);
+ if (ret)
+ goto allocate_fail;
}
INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1559,6 +1755,25 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto hid_parse_fail;
}
+ if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto hid_hw_start_fail;
+ }
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+ __func__, ret);
+ hid_hw_stop(hdev);
+ goto hid_hw_start_fail;
+ }
+ }
+
+
/* Allow incoming packets */
hid_device_io_start(hdev);
@@ -1567,8 +1782,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!connected) {
ret = -ENODEV;
hid_err(hdev, "Device not connected");
- hid_device_io_stop(hdev);
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
}
hid_info(hdev, "HID++ %u.%u device connected.\n",
@@ -1581,19 +1795,22 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
ret = wtp_get_config(hidpp);
if (ret)
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
+ } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = g920_get_config(hidpp);
+ if (ret)
+ goto hid_hw_open_failed;
}
/* Block incoming packets */
hid_device_io_stop(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
- connect_mask &= ~HID_CONNECT_HIDINPUT;
-
- ret = hid_hw_start(hdev, connect_mask);
- if (ret) {
- hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
- goto hid_hw_start_fail;
+ if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
+ goto hid_hw_start_fail;
+ }
}
if (hidpp->quirks & HIDPP_QUIRK_CONNECT_EVENTS) {
@@ -1605,6 +1822,13 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
+hid_hw_open_failed:
+ hid_device_io_stop(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+ }
hid_hw_start_fail:
hid_parse_fail:
cancel_work_sync(&hidpp->work);
@@ -1618,9 +1842,13 @@ static void hidpp_remove(struct hid_device *hdev)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
+ hid_hw_close(hdev);
+ }
+ hid_hw_stop(hdev);
cancel_work_sync(&hidpp->work);
mutex_destroy(&hidpp->send_mutex);
- hid_hw_stop(hdev);
}
static const struct hid_device_id hidpp_devices[] = {
@@ -1648,6 +1876,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
+ .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
{}
};
@@ -1661,6 +1892,7 @@ static struct hid_driver hidpp_driver = {
.raw_event = hidpp_raw_event,
.input_configured = hidpp_input_configured,
.input_mapping = hidpp_input_mapping,
+ .input_mapped = hidpp_input_mapped,
};
module_hid_driver(hidpp_driver);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3d664d01305e..296d4991560e 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -272,7 +272,7 @@ static ssize_t mt_show_quirks(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
return sprintf(buf, "%u\n", td->mtclass.quirks);
@@ -282,7 +282,7 @@ static ssize_t mt_set_quirks(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
unsigned long val;
@@ -357,8 +357,19 @@ static void mt_feature_mapping(struct hid_device *hdev,
break;
}
- td->inputmode = field->report->id;
- td->inputmode_index = usage->usage_index;
+ 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:
@@ -486,6 +497,11 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
mt_store_field(usage, td, hi);
return 1;
case HID_DG_CONFIDENCE:
+ if (cls->name == MT_CLS_WIN_8 &&
+ field->application == HID_DG_TOUCHPAD) {
+ cls->quirks &= ~MT_QUIRK_ALWAYS_VALID;
+ cls->quirks |= MT_QUIRK_VALID_IS_CONFIDENCE;
+ }
mt_store_field(usage, td, hi);
return 1;
case HID_DG_TIPSWITCH:
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 756d1ef9bd99..1b0084d4af2e 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -173,7 +173,7 @@ static ssize_t show_phys_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_physical_width);
@@ -185,7 +185,7 @@ static ssize_t show_phys_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_physical_height);
@@ -197,7 +197,7 @@ static ssize_t show_log_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_logical_width);
@@ -209,7 +209,7 @@ static ssize_t show_log_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->sensor_logical_height);
@@ -221,7 +221,7 @@ static ssize_t show_min_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->min_width *
@@ -233,7 +233,7 @@ static ssize_t set_min_width(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -256,7 +256,7 @@ static ssize_t show_min_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->min_height *
@@ -268,7 +268,7 @@ static ssize_t set_min_height(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -292,7 +292,7 @@ static ssize_t show_activate_slack(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activate_slack);
@@ -302,7 +302,7 @@ static ssize_t set_activate_slack(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -325,7 +325,7 @@ static ssize_t show_activation_width(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activation_width *
@@ -337,7 +337,7 @@ static ssize_t set_activation_width(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -361,7 +361,7 @@ static ssize_t show_activation_height(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", nd->activation_height *
@@ -373,7 +373,7 @@ static ssize_t set_activation_height(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
@@ -397,7 +397,7 @@ static ssize_t show_deactivate_slack(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
return sprintf(buf, "%d\n", -nd->deactivate_slack);
@@ -407,7 +407,7 @@ static ssize_t set_deactivate_slack(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct ntrig_data *nd = hid_get_drvdata(hdev);
unsigned long val;
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
index e994f9c29012..a802b4f49c7b 100644
--- a/drivers/hid/hid-picolcd_leds.c
+++ b/drivers/hid/hid-picolcd_leds.c
@@ -66,7 +66,7 @@ static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
int i, state = 0;
dev = led_cdev->dev->parent;
- hdev = container_of(dev, struct hid_device, dev);
+ hdev = to_hid_device(dev);
data = hid_get_drvdata(hdev);
if (!data)
return;
@@ -93,7 +93,7 @@ static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_c
int i, value = 0;
dev = led_cdev->dev->parent;
- hdev = container_of(dev, struct hid_device, dev);
+ hdev = to_hid_device(dev);
data = hid_get_drvdata(hdev);
for (i = 0; i < 8; i++)
if (led_cdev == data->led[i]) {
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 3a207c0ac0e3..f095bf8a3aa9 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -103,7 +103,7 @@ MODULE_PARM_DESC(enable, "Enable for the PC-MIDI virtual audio driver");
static ssize_t show_channel(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
@@ -116,7 +116,7 @@ static ssize_t show_channel(struct device *dev,
static ssize_t store_channel(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
unsigned channel = 0;
@@ -140,7 +140,7 @@ static struct device_attribute *sysfs_device_attr_channel = {
static ssize_t show_sustain(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
@@ -153,7 +153,7 @@ static ssize_t show_sustain(struct device *dev,
static ssize_t store_sustain(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
unsigned sustain = 0;
@@ -179,7 +179,7 @@ static struct device_attribute *sysfs_device_attr_sustain = {
static ssize_t show_octave(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
@@ -192,7 +192,7 @@ static ssize_t show_octave(struct device *dev,
static ssize_t store_octave(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
int octave = 0;
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 1948208fe038..329c5d1270f9 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -191,8 +191,7 @@ static ssize_t arvo_sysfs_write(struct file *fp,
struct kobject *kobj, void const *buf,
loff_t off, size_t count, size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -211,8 +210,7 @@ static ssize_t arvo_sysfs_read(struct file *fp,
struct kobject *kobj, void *buf, loff_t off,
size_t count, size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c
index 02e28e9f4ea7..8155ac5fede2 100644
--- a/drivers/hid/hid-roccat-common.c
+++ b/drivers/hid/hid-roccat-common.c
@@ -134,8 +134,7 @@ ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -158,8 +157,7 @@ ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index bc62ed91e451..02db537f8f3e 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -121,8 +121,7 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -144,8 +143,7 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index c29265055ac1..bf4675a27396 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -269,8 +269,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_settings))
@@ -294,8 +293,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0, difference, old_profile;
@@ -332,8 +330,7 @@ static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
static ssize_t kone_sysfs_read_profilex(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_profile))
@@ -353,8 +350,7 @@ static ssize_t kone_sysfs_read_profilex(struct file *fp,
static ssize_t kone_sysfs_write_profilex(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count) {
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct kone_profile *profile;
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 5e99fcdc71b9..09e8fc72aa1d 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -87,8 +87,7 @@ static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -113,8 +112,7 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -193,8 +191,7 @@ static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -212,8 +209,7 @@ static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index 966047711fbf..43617fb28b87 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -128,8 +128,7 @@ static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -154,8 +153,7 @@ static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -221,8 +219,7 @@ static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -240,8 +237,7 @@ static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
diff --git a/drivers/hid/hid-roccat-lua.c b/drivers/hid/hid-roccat-lua.c
index 65e2e76bf2fe..ac1a7313e259 100644
--- a/drivers/hid/hid-roccat-lua.c
+++ b/drivers/hid/hid-roccat-lua.c
@@ -30,7 +30,7 @@ static ssize_t lua_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -52,7 +52,7 @@ static ssize_t lua_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct lua_device *lua = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 47d7e74231e5..b30aa7b82bf8 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -90,8 +90,7 @@ static ssize_t pyra_sysfs_read(struct file *fp, struct kobject *kobj,
char *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -116,8 +115,7 @@ static ssize_t pyra_sysfs_write(struct file *fp, struct kobject *kobj,
void const *buf, loff_t off, size_t count,
size_t real_size, uint command)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
@@ -191,8 +189,7 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -210,8 +207,7 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
ssize_t retval;
@@ -248,8 +244,7 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev =
- container_of(kobj, struct device, kobj)->parent->parent;
+ struct device *dev = kobj_to_dev(kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 92870cdb52d9..58ed8f25ab21 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -794,6 +794,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
USB_DEVICE_ID_ITE_LENOVO_YOGA2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE,
+ USB_DEVICE_ID_ITE_LENOVO_YOGA900),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
HID_ANY_ID) },
{ }
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 774cd2210566..9b8db0e0ef1c 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1028,6 +1028,7 @@ struct sony_sc {
struct led_classdev *leds[MAX_LEDS];
unsigned long quirks;
struct work_struct state_worker;
+ void(*send_output_report)(struct sony_sc*);
struct power_supply *battery;
struct power_supply_desc battery_desc;
int device_id;
@@ -1044,6 +1045,7 @@ struct sony_sc {
__u8 battery_charging;
__u8 battery_capacity;
__u8 led_state[MAX_LEDS];
+ __u8 resume_led_state[MAX_LEDS];
__u8 led_delay_on[MAX_LEDS];
__u8 led_delay_off[MAX_LEDS];
__u8 led_count;
@@ -1137,11 +1139,11 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
* the gyroscope values to corresponding axes so we need a
* modified one.
*/
- if ((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && *rsize == 467) {
+ if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
hid_info(hdev, "Using modified Dualshock 4 report descriptor with gyroscope axes\n");
rdesc = dualshock4_usb_rdesc;
*rsize = sizeof(dualshock4_usb_rdesc);
- } else if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && *rsize == 357) {
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
hid_info(hdev, "Using modified Dualshock 4 Bluetooth report descriptor\n");
rdesc = dualshock4_bt_rdesc;
*rsize = sizeof(dualshock4_bt_rdesc);
@@ -1549,7 +1551,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
enum led_brightness value)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data;
int n;
@@ -1591,7 +1593,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data;
int n;
@@ -1614,7 +1616,7 @@ static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
unsigned long *delay_off)
{
struct device *dev = led->dev->parent;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
__u8 new_on, new_off;
@@ -1789,7 +1791,7 @@ error_leds:
return ret;
}
-static void sixaxis_state_worker(struct work_struct *work)
+static void sixaxis_send_output_report(struct sony_sc *sc)
{
static const union sixaxis_output_report_01 default_report = {
.buf = {
@@ -1803,7 +1805,6 @@ static void sixaxis_state_worker(struct work_struct *work)
0x00, 0x00, 0x00, 0x00, 0x00
}
};
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct sixaxis_output_report *report =
(struct sixaxis_output_report *)sc->output_report_dmabuf;
int n;
@@ -1846,9 +1847,8 @@ static void sixaxis_state_worker(struct work_struct *work)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
-static void dualshock4_state_worker(struct work_struct *work)
+static void dualshock4_send_output_report(struct sony_sc *sc)
{
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct hid_device *hdev = sc->hdev;
__u8 *buf = sc->output_report_dmabuf;
int offset;
@@ -1893,9 +1893,8 @@ static void dualshock4_state_worker(struct work_struct *work)
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
-static void motion_state_worker(struct work_struct *work)
+static void motion_send_output_report(struct sony_sc *sc)
{
- struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
struct hid_device *hdev = sc->hdev;
struct motion_output_report_02 *report =
(struct motion_output_report_02 *)sc->output_report_dmabuf;
@@ -1914,6 +1913,18 @@ static void motion_state_worker(struct work_struct *work)
hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE);
}
+static inline void sony_send_output_report(struct sony_sc *sc)
+{
+ if (sc->send_output_report)
+ sc->send_output_report(sc);
+}
+
+static void sony_state_worker(struct work_struct *work)
+{
+ struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
+ sc->send_output_report(sc);
+}
+
static int sony_allocate_output_report(struct sony_sc *sc)
{
if ((sc->quirks & SIXAXIS_CONTROLLER) ||
@@ -2241,11 +2252,13 @@ static void sony_release_device_id(struct sony_sc *sc)
}
}
-static inline void sony_init_work(struct sony_sc *sc,
- void (*worker)(struct work_struct *))
+static inline void sony_init_output_report(struct sony_sc *sc,
+ void(*send_output_report)(struct sony_sc*))
{
+ sc->send_output_report = send_output_report;
+
if (!sc->worker_initialized)
- INIT_WORK(&sc->state_worker, worker);
+ INIT_WORK(&sc->state_worker, sony_state_worker);
sc->worker_initialized = 1;
}
@@ -2319,7 +2332,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
- sony_init_work(sc, sixaxis_state_worker);
+ sony_init_output_report(sc, sixaxis_send_output_report);
} else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) ||
(sc->quirks & NAVIGATION_CONTROLLER_BT)) {
/*
@@ -2328,7 +2341,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
- sony_init_work(sc, sixaxis_state_worker);
+ sony_init_output_report(sc, sixaxis_send_output_report);
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
/*
@@ -2343,9 +2356,9 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
- sony_init_work(sc, dualshock4_state_worker);
+ sony_init_output_report(sc, dualshock4_send_output_report);
} else if (sc->quirks & MOTION_CONTROLLER) {
- sony_init_work(sc, motion_state_worker);
+ sony_init_output_report(sc, motion_send_output_report);
} else {
ret = 0;
}
@@ -2421,6 +2434,56 @@ static void sony_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
}
+#ifdef CONFIG_PM
+
+static int sony_suspend(struct hid_device *hdev, pm_message_t message)
+{
+ /*
+ * On suspend save the current LED state,
+ * stop running force-feedback and blank the LEDS.
+ */
+ if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+#ifdef CONFIG_SONY_FF
+ sc->left = sc->right = 0;
+#endif
+
+ memcpy(sc->resume_led_state, sc->led_state,
+ sizeof(sc->resume_led_state));
+ memset(sc->led_state, 0, sizeof(sc->led_state));
+
+ sony_send_output_report(sc);
+ }
+
+ return 0;
+}
+
+static int sony_resume(struct hid_device *hdev)
+{
+ /* Restore the state of controller LEDs on resume */
+ if (SONY_LED_SUPPORT) {
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ memcpy(sc->led_state, sc->resume_led_state,
+ sizeof(sc->led_state));
+
+ /*
+ * The Sixaxis and navigation controllers on USB need to be
+ * reinitialized on resume or they won't behave properly.
+ */
+ if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
+ (sc->quirks & NAVIGATION_CONTROLLER_USB))
+ sixaxis_set_operational_usb(sc->hdev);
+
+ sony_set_leds(sc);
+ }
+
+ return 0;
+}
+
+#endif
+
static const struct hid_device_id sony_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB },
@@ -2470,7 +2533,13 @@ static struct hid_driver sony_driver = {
.probe = sony_probe,
.remove = sony_remove,
.report_fixup = sony_report_fixup,
- .raw_event = sony_raw_event
+ .raw_event = sony_raw_event,
+
+#ifdef CONFIG_PM
+ .suspend = sony_suspend,
+ .resume = sony_resume,
+ .reset_resume = sony_resume,
+#endif
};
static int __init sony_init(void)
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index 3edd4ac36494..ec18768b124a 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -141,7 +141,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
if (!drv_data) {
@@ -160,7 +160,7 @@ static void steelseries_srws1_led_all_set_brightness(struct led_classdev *led_cd
static enum led_brightness steelseries_srws1_led_all_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data;
drv_data = hid_get_drvdata(hid);
@@ -177,7 +177,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data = hid_get_drvdata(hid);
int i, state = 0;
@@ -205,7 +205,7 @@ static void steelseries_srws1_led_set_brightness(struct led_classdev *led_cdev,
static enum led_brightness steelseries_srws1_led_get_brightness(struct led_classdev *led_cdev)
{
struct device *dev = led_cdev->dev->parent;
- struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct hid_device *hid = to_hid_device(dev);
struct steelseries_srws1_data *drv_data;
int i, value = 0;
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 05e23c417d50..4390eee2ce84 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -296,14 +296,12 @@ static const struct wiimod_ops wiimod_battery = {
static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
{
- struct wiimote_data *wdata;
struct device *dev = led_dev->dev->parent;
+ struct wiimote_data *wdata = dev_to_wii(dev);
int i;
unsigned long flags;
bool value = false;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
spin_lock_irqsave(&wdata->state.lock, flags);
@@ -319,14 +317,12 @@ static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
static void wiimod_led_set(struct led_classdev *led_dev,
enum led_brightness value)
{
- struct wiimote_data *wdata;
struct device *dev = led_dev->dev->parent;
+ struct wiimote_data *wdata = dev_to_wii(dev);
int i;
unsigned long flags;
__u8 state, flag;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
-
for (i = 0; i < 4; ++i) {
if (wdata->leds[i] == led_dev) {
flag = WIIPROTO_FLAG_LED(i + 1);
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 875694d43e4d..510ca77fe14e 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -256,8 +256,7 @@ enum wiiproto_reqs {
WIIPROTO_REQ_MAX
};
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
- dev))
+#define dev_to_wii(pdev) hid_get_drvdata(to_hid_device(pdev))
void __wiimote_schedule(struct wiimote_data *wdata);
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 10bd8e6e4c9c..b9216938a718 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -151,6 +151,7 @@ struct i2c_hid {
struct i2c_hid_platform_data pdata;
bool irq_wake_enabled;
+ struct mutex reset_lock;
};
static int __i2c_hid_command(struct i2c_client *client,
@@ -356,9 +357,16 @@ static int i2c_hid_hwreset(struct i2c_client *client)
i2c_hid_dbg(ihid, "%s\n", __func__);
+ /*
+ * This prevents sending feature reports while the device is
+ * being reset. Otherwise we may lose the reset complete
+ * interrupt.
+ */
+ mutex_lock(&ihid->reset_lock);
+
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret)
- return ret;
+ goto out_unlock;
i2c_hid_dbg(ihid, "resetting...\n");
@@ -366,10 +374,11 @@ static int i2c_hid_hwreset(struct i2c_client *client)
if (ret) {
dev_err(&client->dev, "failed to reset device.\n");
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
- return ret;
}
- return 0;
+out_unlock:
+ mutex_unlock(&ihid->reset_lock);
+ return ret;
}
static void i2c_hid_get_input(struct i2c_hid *ihid)
@@ -587,12 +596,15 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type, bool use_data)
{
struct i2c_client *client = hid->driver_data;
+ struct i2c_hid *ihid = i2c_get_clientdata(client);
int report_id = buf[0];
int ret;
if (report_type == HID_INPUT_REPORT)
return -EINVAL;
+ mutex_lock(&ihid->reset_lock);
+
if (report_id) {
buf++;
count--;
@@ -605,6 +617,8 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */
+ mutex_unlock(&ihid->reset_lock);
+
return ret;
}
@@ -990,6 +1004,7 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->wHIDDescRegister = cpu_to_le16(hidRegister);
init_waitqueue_head(&ihid->wait);
+ mutex_init(&ihid->reset_lock);
/* we need to allocate the command buffer without knowing the maximum
* size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the
@@ -1184,7 +1199,6 @@ MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
static struct i2c_driver i2c_hid_driver = {
.driver = {
.name = "i2c_hid",
- .owner = THIS_MODULE,
.pm = &i2c_hid_pm,
.acpi_match_table = ACPI_PTR(i2c_hid_acpi_match),
.of_match_table = of_match_ptr(i2c_hid_of_match),
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 36712e9f56c2..ad71160b9ea4 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -274,10 +274,10 @@ static void hid_irq_in(struct urb *urb)
switch (urb->status) {
case 0: /* success */
- usbhid_mark_busy(usbhid);
usbhid->retry_delay = 0;
if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open)
break;
+ usbhid_mark_busy(usbhid);
if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer,
@@ -477,8 +477,6 @@ static void hid_ctrl(struct urb *urb)
struct usbhid_device *usbhid = hid->driver_data;
int unplug = 0, status = urb->status;
- spin_lock(&usbhid->lock);
-
switch (status) {
case 0: /* success */
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
@@ -498,6 +496,8 @@ static void hid_ctrl(struct urb *urb)
hid_warn(urb->dev, "ctrl urb status %d received\n", status);
}
+ spin_lock(&usbhid->lock);
+
if (unplug) {
usbhid->ctrltail = usbhid->ctrlhead;
} else {
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 807922b49aa4..fa47d666cfcf 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -96,7 +96,7 @@ struct usbhid_device {
};
#define hid_to_usb_dev(hid_dev) \
- container_of(hid_dev->dev.parent->parent, struct usb_device, dev)
+ to_usb_device(hid_dev->dev.parent->parent)
#endif
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index e06af5b9f59e..5cb21dd91094 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -686,7 +686,7 @@ out:
static ssize_t wacom_led_select_store(struct device *dev, int set_id,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
unsigned int id;
int err;
@@ -714,7 +714,7 @@ static ssize_t wacom_led##SET_ID##_select_store(struct device *dev, \
static ssize_t wacom_led##SET_ID##_select_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+ struct hid_device *hdev = to_hid_device(dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
return scnprintf(buf, PAGE_SIZE, "%d\n", \
wacom->led.select[SET_ID]); \
@@ -750,7 +750,7 @@ static ssize_t wacom_luminance_store(struct wacom *wacom, u8 *dest,
static ssize_t wacom_##name##_luminance_store(struct device *dev, \
struct device_attribute *attr, const char *buf, size_t count) \
{ \
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);\
+ struct hid_device *hdev = to_hid_device(dev);\
struct wacom *wacom = hid_get_drvdata(hdev); \
\
return wacom_luminance_store(wacom, &wacom->led.field, \
@@ -773,7 +773,7 @@ DEVICE_LUMINANCE_ATTR(buttons, img_lum);
static ssize_t wacom_button_image_store(struct device *dev, int button_id,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err;
unsigned len;
@@ -1097,7 +1097,7 @@ static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%i\n", wacom->wacom_wac.bt_high_speed);
@@ -1107,7 +1107,7 @@ static ssize_t wacom_store_speed(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
u8 new_speed;
@@ -1130,8 +1130,8 @@ static ssize_t wacom_show_remote_mode(struct kobject *kobj,
struct kobj_attribute *kattr,
char *buf, int index)
{
- struct device *dev = container_of(kobj->parent, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj->parent);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
u8 mode;
@@ -1241,8 +1241,8 @@ static ssize_t wacom_store_unpair_remote(struct kobject *kobj,
const char *buf, size_t count)
{
unsigned char selector = 0;
- struct device *dev = container_of(kobj->parent, struct device, kobj);
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct device *dev = kobj_to_dev(kobj->parent);
+ struct hid_device *hdev = to_hid_device(dev);
struct wacom *wacom = hid_get_drvdata(hdev);
int err;
@@ -1353,8 +1353,7 @@ static void wacom_clean_inputs(struct wacom *wacom)
else
input_free_device(wacom->wacom_wac.pad_input);
}
- if (wacom->remote_dir)
- kobject_put(wacom->remote_dir);
+ kobject_put(wacom->remote_dir);
wacom->wacom_wac.pen_input = NULL;
wacom->wacom_wac.touch_input = NULL;
wacom->wacom_wac.pad_input = NULL;
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 01a4f05c1642..99ef77fcfb80 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -34,6 +34,9 @@
*/
#define WACOM_CONTACT_AREA_SCALE 2607
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+ int button_count, int mask);
+
/*
* Percent of battery capacity for Graphire.
* 8th value means AC online and show 100% capacity.
@@ -436,16 +439,142 @@ exit:
static void wacom_intuos_schedule_prox_event(struct wacom_wac *wacom_wac)
{
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
+ struct wacom_features *features = &wacom_wac->features;
struct hid_report *r;
struct hid_report_enum *re;
re = &(wacom->hdev->report_enum[HID_FEATURE_REPORT]);
- r = re->report_id_hash[WACOM_REPORT_INTUOSREAD];
+ if (features->type == INTUOSHT2)
+ r = re->report_id_hash[WACOM_REPORT_INTUOSHT2_ID];
+ else
+ r = re->report_id_hash[WACOM_REPORT_INTUOS_ID1];
if (r) {
hid_hw_request(wacom->hdev, r, HID_REQ_GET_REPORT);
}
}
+static int wacom_intuos_pad(struct wacom_wac *wacom)
+{
+ struct wacom_features *features = &wacom->features;
+ unsigned char *data = wacom->data;
+ struct input_dev *input = wacom->pad_input;
+ int i;
+ int buttons = 0, nbuttons = features->numbered_buttons;
+ int keys = 0, nkeys = 0;
+ int ring1 = 0, ring2 = 0;
+ int strip1 = 0, strip2 = 0;
+ bool prox = false;
+
+ /* pad packets. Works as a second tool and is always in prox */
+ if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
+ data[0] == WACOM_REPORT_CINTIQPAD))
+ return 0;
+
+ if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+ buttons = (data[3] << 1) | (data[2] & 0x01);
+ ring1 = data[1];
+ } else if (features->type == DTK) {
+ buttons = data[6];
+ } else if (features->type == WACOM_13HD) {
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ } else if (features->type == WACOM_24HD) {
+ buttons = (data[8] << 8) | data[6];
+ ring1 = data[1];
+ ring2 = data[2];
+
+ /*
+ * Three "buttons" are available on the 24HD which are
+ * physically implemented as a touchstrip. Each button
+ * is approximately 3 bits wide with a 2 bit spacing.
+ * The raw touchstrip bits are stored at:
+ * ((data[3] & 0x1f) << 8) | data[4])
+ */
+ nkeys = 3;
+ keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
+ ((data[4] & 0xE0) ? 1<<1 : 0) |
+ ((data[4] & 0x07) ? 1<<0 : 0);
+ } else if (features->type == WACOM_27QHD) {
+ nkeys = 3;
+ keys = data[2] & 0x07;
+
+ input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
+ input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
+ input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+ } else if (features->type == CINTIQ_HYBRID) {
+ /*
+ * Do not send hardware buttons under Android. They
+ * are already sent to the system through GPIO (and
+ * have different meaning).
+ *
+ * d-pad right -> data[4] & 0x10
+ * d-pad up -> data[4] & 0x20
+ * d-pad left -> data[4] & 0x40
+ * d-pad down -> data[4] & 0x80
+ * d-pad center -> data[3] & 0x01
+ */
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ } else if (features->type == CINTIQ_COMPANION_2) {
+ /* d-pad right -> data[4] & 0x10
+ * d-pad up -> data[4] & 0x20
+ * d-pad left -> data[4] & 0x40
+ * d-pad down -> data[4] & 0x80
+ * d-pad center -> data[3] & 0x01
+ */
+ buttons = ((data[2] >> 4) << 7) |
+ ((data[1] & 0x04) << 6) |
+ ((data[2] & 0x0F) << 2) |
+ (data[1] & 0x03);
+ } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
+ /*
+ * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
+ * addition to the mechanical switch. Switch data is
+ * stored in data[4], capacitive data in data[5].
+ *
+ * Touch ring mode switch (data[3]) has no capacitive sensor
+ */
+ buttons = (data[4] << 1) | (data[3] & 0x01);
+ ring1 = data[2];
+ } else {
+ if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
+ buttons = (data[8] << 10) | ((data[7] & 0x01) << 9) |
+ (data[6] << 1) | (data[5] & 0x01);
+
+ if (features->type == WACOM_22HD) {
+ nkeys = 3;
+ keys = data[9] & 0x07;
+ }
+ } else {
+ buttons = ((data[6] & 0x10) << 10) |
+ ((data[5] & 0x10) << 9) |
+ ((data[6] & 0x0F) << 4) |
+ (data[5] & 0x0F);
+ }
+ strip1 = ((data[1] & 0x1f) << 8) | data[2];
+ strip2 = ((data[3] & 0x1f) << 8) | data[4];
+ }
+
+ prox = (buttons & ~(~0 << nbuttons)) | (keys & ~(~0 << nkeys)) |
+ (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
+
+ wacom_report_numbered_buttons(input, nbuttons, buttons);
+
+ for (i = 0; i < nkeys; i++)
+ input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
+
+ input_report_abs(input, ABS_RX, strip1);
+ input_report_abs(input, ABS_RY, strip2);
+
+ input_report_abs(input, ABS_WHEEL, (ring1 & 0x80) ? (ring1 & 0x7f) : 0);
+ input_report_abs(input, ABS_THROTTLE, (ring2 & 0x80) ? (ring2 & 0x7f) : 0);
+
+ input_report_key(input, wacom->tool[1], prox ? 1 : 0);
+ input_report_abs(input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
+
+ input_event(input, EV_MSC, MSC_SERIAL, 0xffffffff);
+
+ return 1;
+}
+
static int wacom_intuos_inout(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
@@ -755,19 +884,40 @@ static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
return 0;
}
-static void wacom_intuos_general(struct wacom_wac *wacom)
+static int wacom_intuos_general(struct wacom_wac *wacom)
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
- unsigned int t;
+ int idx = (features->type == INTUOS) ? (data[1] & 0x01) : 0;
+ unsigned char type = (data[1] >> 1) & 0x0F;
+ unsigned int x, y, distance, t;
- /* general pen packet */
- if ((data[1] & 0xb8) == 0xa0) {
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- if (features->pressure_max == 2047) {
- t = (t << 1) | (data[1] & 1);
- }
+ if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_CINTIQ &&
+ data[0] != WACOM_REPORT_INTUOS_PEN)
+ return 0;
+
+ x = (be16_to_cpup((__be16 *)&data[2]) << 1) | ((data[9] >> 1) & 1);
+ y = (be16_to_cpup((__be16 *)&data[4]) << 1) | (data[9] & 1);
+ distance = data[9] >> 2;
+ if (features->type < INTUOS3S) {
+ x >>= 1;
+ y >>= 1;
+ distance >>= 1;
+ }
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_DISTANCE, distance);
+
+ switch (type) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ /* general pen packet */
+ t = (data[6] << 3) | ((data[7] & 0xC0) >> 5) | (data[1] & 1);
+ if (features->pressure_max < 2047)
+ t >>= 1;
input_report_abs(input, ABS_PRESSURE, t);
if (features->type != INTUOSHT2) {
input_report_abs(input, ABS_TILT_X,
@@ -777,29 +927,112 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
input_report_key(input, BTN_STYLUS, data[1] & 2);
input_report_key(input, BTN_STYLUS2, data[1] & 4);
input_report_key(input, BTN_TOUCH, t > 10);
- }
+ break;
- /* airbrush second packet */
- if ((data[1] & 0xbc) == 0xb4) {
+ case 0x0a:
+ /* airbrush second packet */
input_report_abs(input, ABS_WHEEL,
(data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(input, ABS_TILT_X,
(((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+ break;
+
+ case 0x05:
+ /* Rotation packet */
+ if (features->type >= INTUOS3S) {
+ /* I3 marker pen rotation */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ input_report_abs(input, ABS_Z, t);
+ } else {
+ /* 4D mouse 2nd packet */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
+ ((t - 1) / 2) : -t / 2);
+ }
+ break;
+
+ case 0x04:
+ /* 4D mouse 1st packet */
+ input_report_key(input, BTN_LEFT, data[8] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x04);
+
+ input_report_key(input, BTN_SIDE, data[8] & 0x20);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x10);
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+ break;
+
+ case 0x06:
+ /* I4 mouse */
+ input_report_key(input, BTN_LEFT, data[6] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[6] & 0x04);
+ input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
+ - ((data[7] & 0x40) >> 6));
+ input_report_key(input, BTN_SIDE, data[6] & 0x08);
+ input_report_key(input, BTN_EXTRA, data[6] & 0x10);
+
+ input_report_abs(input, ABS_TILT_X,
+ (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
+ input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
+ break;
+
+ case 0x08:
+ if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+ /* 2D mouse packet */
+ input_report_key(input, BTN_LEFT, data[8] & 0x04);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x10);
+ input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
+ - ((data[8] & 0x02) >> 1));
+
+ /* I3 2D mouse side buttons */
+ if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
+ input_report_key(input, BTN_SIDE, data[8] & 0x40);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x20);
+ }
+ }
+ else if (wacom->tool[idx] == BTN_TOOL_LENS) {
+ /* Lens cursor packets */
+ input_report_key(input, BTN_LEFT, data[8] & 0x01);
+ input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(input, BTN_RIGHT, data[8] & 0x04);
+ input_report_key(input, BTN_SIDE, data[8] & 0x10);
+ input_report_key(input, BTN_EXTRA, data[8] & 0x08);
+ }
+ break;
+
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ /* unhandled */
+ break;
}
+
+ input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
+ input_report_key(input, wacom->tool[idx], 1);
+ input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ wacom->reporting_data = true;
+ return 2;
}
static int wacom_intuos_irq(struct wacom_wac *wacom)
{
- struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
- unsigned int t;
- int idx = 0, result;
+ int result;
if (data[0] != WACOM_REPORT_PENABLED &&
- data[0] != WACOM_REPORT_INTUOSREAD &&
- data[0] != WACOM_REPORT_INTUOSWRITE &&
+ data[0] != WACOM_REPORT_INTUOS_ID1 &&
+ data[0] != WACOM_REPORT_INTUOS_ID2 &&
data[0] != WACOM_REPORT_INTUOSPAD &&
data[0] != WACOM_REPORT_INTUOS_PEN &&
data[0] != WACOM_REPORT_CINTIQ &&
@@ -810,339 +1043,22 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 0;
}
- /* tool number */
- if (features->type == INTUOS)
- idx = data[1] & 0x01;
-
- /* pad packets. Works as a second tool and is always in prox */
- if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
- data[0] == WACOM_REPORT_CINTIQPAD) {
- input = wacom->pad_input;
- if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
- input_report_key(input, BTN_0, (data[2] & 0x01));
- input_report_key(input, BTN_1, (data[3] & 0x01));
- input_report_key(input, BTN_2, (data[3] & 0x02));
- input_report_key(input, BTN_3, (data[3] & 0x04));
- input_report_key(input, BTN_4, (data[3] & 0x08));
- input_report_key(input, BTN_5, (data[3] & 0x10));
- input_report_key(input, BTN_6, (data[3] & 0x20));
- if (data[1] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
- if (features->type != INTUOS4S) {
- input_report_key(input, BTN_7, (data[3] & 0x40));
- input_report_key(input, BTN_8, (data[3] & 0x80));
- }
- if (data[1] | (data[2] & 0x01) | data[3]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == DTK) {
- input_report_key(input, BTN_0, (data[6] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x02));
- input_report_key(input, BTN_2, (data[6] & 0x04));
- input_report_key(input, BTN_3, (data[6] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x10));
- input_report_key(input, BTN_5, (data[6] & 0x20));
- if (data[6] & 0x3f) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_13HD) {
- input_report_key(input, BTN_0, (data[3] & 0x01));
- input_report_key(input, BTN_1, (data[4] & 0x01));
- input_report_key(input, BTN_2, (data[4] & 0x02));
- input_report_key(input, BTN_3, (data[4] & 0x04));
- input_report_key(input, BTN_4, (data[4] & 0x08));
- input_report_key(input, BTN_5, (data[4] & 0x10));
- input_report_key(input, BTN_6, (data[4] & 0x20));
- input_report_key(input, BTN_7, (data[4] & 0x40));
- input_report_key(input, BTN_8, (data[4] & 0x80));
- if ((data[3] & 0x01) | data[4]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_24HD) {
- input_report_key(input, BTN_0, (data[6] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x02));
- input_report_key(input, BTN_2, (data[6] & 0x04));
- input_report_key(input, BTN_3, (data[6] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x10));
- input_report_key(input, BTN_5, (data[6] & 0x20));
- input_report_key(input, BTN_6, (data[6] & 0x40));
- input_report_key(input, BTN_7, (data[6] & 0x80));
- input_report_key(input, BTN_8, (data[8] & 0x01));
- input_report_key(input, BTN_9, (data[8] & 0x02));
- input_report_key(input, BTN_A, (data[8] & 0x04));
- input_report_key(input, BTN_B, (data[8] & 0x08));
- input_report_key(input, BTN_C, (data[8] & 0x10));
- input_report_key(input, BTN_X, (data[8] & 0x20));
- input_report_key(input, BTN_Y, (data[8] & 0x40));
- input_report_key(input, BTN_Z, (data[8] & 0x80));
-
- /*
- * Three "buttons" are available on the 24HD which are
- * physically implemented as a touchstrip. Each button
- * is approximately 3 bits wide with a 2 bit spacing.
- * The raw touchstrip bits are stored at:
- * ((data[3] & 0x1f) << 8) | data[4])
- */
- input_report_key(input, KEY_PROG1, data[4] & 0x07);
- input_report_key(input, KEY_PROG2, data[4] & 0xE0);
- input_report_key(input, KEY_PROG3, data[3] & 0x1C);
-
- if (data[1] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[1] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
-
- if (data[2] & 0x80) {
- input_report_abs(input, ABS_THROTTLE, (data[2] & 0x7f));
- } else {
- /* Out of proximity, clear second wheel value. */
- input_report_abs(input, ABS_THROTTLE, 0);
- }
-
- if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == WACOM_27QHD) {
- input_report_key(input, KEY_PROG1, data[2] & 0x01);
- input_report_key(input, KEY_PROG2, data[2] & 0x02);
- input_report_key(input, KEY_PROG3, data[2] & 0x04);
-
- input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
- input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
- input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
- if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else if (features->type == CINTIQ_HYBRID) {
- /*
- * Do not send hardware buttons under Android. They
- * are already sent to the system through GPIO (and
- * have different meaning).
- */
- input_report_key(input, BTN_1, (data[4] & 0x01));
- input_report_key(input, BTN_2, (data[4] & 0x02));
- input_report_key(input, BTN_3, (data[4] & 0x04));
- input_report_key(input, BTN_4, (data[4] & 0x08));
-
- input_report_key(input, BTN_5, (data[4] & 0x10)); /* Right */
- input_report_key(input, BTN_6, (data[4] & 0x20)); /* Up */
- input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */
- input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */
- input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */
-
- if (data[4] | (data[3] & 0x01)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
-
- } else if (features->type == CINTIQ_COMPANION_2) {
- input_report_key(input, BTN_1, (data[1] & 0x02));
- input_report_key(input, BTN_2, (data[2] & 0x01));
- input_report_key(input, BTN_3, (data[2] & 0x02));
- input_report_key(input, BTN_4, (data[2] & 0x04));
- input_report_key(input, BTN_5, (data[2] & 0x08));
- input_report_key(input, BTN_6, (data[1] & 0x04));
-
- input_report_key(input, BTN_7, (data[2] & 0x10)); /* Right */
- input_report_key(input, BTN_8, (data[2] & 0x20)); /* Up */
- input_report_key(input, BTN_9, (data[2] & 0x40)); /* Left */
- input_report_key(input, BTN_A, (data[2] & 0x80)); /* Down */
- input_report_key(input, BTN_0, (data[1] & 0x01)); /* Center */
-
- if (data[2] | (data[1] & 0x07)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
-
- } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
- int i;
-
- /* Touch ring mode switch has no capacitive sensor */
- input_report_key(input, BTN_0, (data[3] & 0x01));
-
- /*
- * ExpressKeys on Intuos5/Intuos Pro have a capacitive sensor in
- * addition to the mechanical switch. Switch data is
- * stored in data[4], capacitive data in data[5].
- */
- for (i = 0; i < 8; i++)
- input_report_key(input, BTN_1 + i, data[4] & (1 << i));
-
- if (data[2] & 0x80) {
- input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
- } else {
- /* Out of proximity, clear wheel value. */
- input_report_abs(input, ABS_WHEEL, 0);
- }
-
- if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- } else {
- if (features->type == WACOM_21UX2 || features->type == WACOM_22HD) {
- input_report_key(input, BTN_0, (data[5] & 0x01));
- input_report_key(input, BTN_1, (data[6] & 0x01));
- input_report_key(input, BTN_2, (data[6] & 0x02));
- input_report_key(input, BTN_3, (data[6] & 0x04));
- input_report_key(input, BTN_4, (data[6] & 0x08));
- input_report_key(input, BTN_5, (data[6] & 0x10));
- input_report_key(input, BTN_6, (data[6] & 0x20));
- input_report_key(input, BTN_7, (data[6] & 0x40));
- input_report_key(input, BTN_8, (data[6] & 0x80));
- input_report_key(input, BTN_9, (data[7] & 0x01));
- input_report_key(input, BTN_A, (data[8] & 0x01));
- input_report_key(input, BTN_B, (data[8] & 0x02));
- input_report_key(input, BTN_C, (data[8] & 0x04));
- input_report_key(input, BTN_X, (data[8] & 0x08));
- input_report_key(input, BTN_Y, (data[8] & 0x10));
- input_report_key(input, BTN_Z, (data[8] & 0x20));
- input_report_key(input, BTN_BASE, (data[8] & 0x40));
- input_report_key(input, BTN_BASE2, (data[8] & 0x80));
-
- if (features->type == WACOM_22HD) {
- input_report_key(input, KEY_PROG1, data[9] & 0x01);
- input_report_key(input, KEY_PROG2, data[9] & 0x02);
- input_report_key(input, KEY_PROG3, data[9] & 0x04);
- }
- } else {
- input_report_key(input, BTN_0, (data[5] & 0x01));
- input_report_key(input, BTN_1, (data[5] & 0x02));
- input_report_key(input, BTN_2, (data[5] & 0x04));
- input_report_key(input, BTN_3, (data[5] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x01));
- input_report_key(input, BTN_5, (data[6] & 0x02));
- input_report_key(input, BTN_6, (data[6] & 0x04));
- input_report_key(input, BTN_7, (data[6] & 0x08));
- input_report_key(input, BTN_8, (data[5] & 0x10));
- input_report_key(input, BTN_9, (data[6] & 0x10));
- }
- input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
- input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
- if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
- data[2] | (data[3] & 0x1f) | data[4] | data[8] |
- (data[7] & 0x01)) {
- input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
- } else {
- input_report_abs(input, ABS_MISC, 0);
- }
- }
- return 1;
- }
+ /* process pad events */
+ result = wacom_intuos_pad(wacom);
+ if (result)
+ return result;
/* process in/out prox events */
result = wacom_intuos_inout(wacom);
if (result)
- return result - 1;
-
- if (features->type >= INTUOS3S) {
- input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
- input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
- input_report_abs(input, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
- } else {
- input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[2]));
- input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[4]));
- input_report_abs(input, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
- }
+ return result - 1;
/* process general packets */
- wacom_intuos_general(wacom);
-
- /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
-
- if (data[1] & 0x02) {
- /* Rotation packet */
- if (features->type >= INTUOS3S) {
- /* I3 marker pen rotation */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
- ((t-1) / 2 + 450)) : (450 - t / 2) ;
- input_report_abs(input, ABS_Z, t);
- } else {
- /* 4D mouse rotation packet */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- input_report_abs(input, ABS_RZ, (data[7] & 0x20) ?
- ((t - 1) / 2) : -t / 2);
- }
-
- } else if (!(data[1] & 0x10) && features->type < INTUOS3S) {
- /* 4D mouse packet */
- input_report_key(input, BTN_LEFT, data[8] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(input, BTN_RIGHT, data[8] & 0x04);
-
- input_report_key(input, BTN_SIDE, data[8] & 0x20);
- input_report_key(input, BTN_EXTRA, data[8] & 0x10);
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(input, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
- } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
- /* I4 mouse */
- if (features->type >= INTUOS4S && features->type <= INTUOSPL) {
- input_report_key(input, BTN_LEFT, data[6] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
- input_report_key(input, BTN_RIGHT, data[6] & 0x04);
- input_report_rel(input, REL_WHEEL, ((data[7] & 0x80) >> 7)
- - ((data[7] & 0x40) >> 6));
- input_report_key(input, BTN_SIDE, data[6] & 0x08);
- input_report_key(input, BTN_EXTRA, data[6] & 0x10);
-
- input_report_abs(input, ABS_TILT_X,
- (((data[7] << 1) & 0x7e) | (data[8] >> 7)) - 64);
- input_report_abs(input, ABS_TILT_Y, (data[8] & 0x7f) - 64);
- } else {
- /* 2D mouse packet */
- input_report_key(input, BTN_LEFT, data[8] & 0x04);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x08);
- input_report_key(input, BTN_RIGHT, data[8] & 0x10);
- input_report_rel(input, REL_WHEEL, (data[8] & 0x01)
- - ((data[8] & 0x02) >> 1));
-
- /* I3 2D mouse side buttons */
- if (features->type >= INTUOS3S && features->type <= INTUOS3L) {
- input_report_key(input, BTN_SIDE, data[8] & 0x40);
- input_report_key(input, BTN_EXTRA, data[8] & 0x20);
- }
- }
- } else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
- features->type == INTUOS4L || features->type == INTUOS5L ||
- features->type == INTUOSPL) &&
- wacom->tool[idx] == BTN_TOOL_LENS) {
- /* Lens cursor packets */
- input_report_key(input, BTN_LEFT, data[8] & 0x01);
- input_report_key(input, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(input, BTN_RIGHT, data[8] & 0x04);
- input_report_key(input, BTN_SIDE, data[8] & 0x10);
- input_report_key(input, BTN_EXTRA, data[8] & 0x08);
- }
- }
+ result = wacom_intuos_general(wacom);
+ if (result)
+ return result - 1;
- input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(input, wacom->tool[idx], 1);
- input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- wacom->reporting_data = true;
- return 1;
+ return 0;
}
static int int_dist(int x1, int y1, int x2, int y2)
@@ -2509,7 +2425,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
features->quirks |= WACOM_QUIRK_BATTERY;
/* quirk for bamboo touch with 2 low res touches */
- if (features->type == BAMBOO_PT &&
+ if ((features->type == BAMBOO_PT || features->type == BAMBOO_TOUCH) &&
features->pktlen == WACOM_PKGLEN_BBTOUCH) {
features->x_max <<= 5;
features->y_max <<= 5;
@@ -2806,6 +2722,19 @@ static void wacom_setup_numbered_buttons(struct input_dev *input_dev,
__set_bit(BTN_BASE + (i-16), input_dev->keybit);
}
+static void wacom_report_numbered_buttons(struct input_dev *input_dev,
+ int button_count, int mask)
+{
+ int i;
+
+ for (i = 0; i < button_count && i < 10; i++)
+ input_report_key(input_dev, BTN_0 + i, mask & (1 << i));
+ for (i = 10; i < button_count && i < 16; i++)
+ input_report_key(input_dev, BTN_A + (i-10), mask & (1 << i));
+ for (i = 16; i < button_count && i < 18; i++)
+ input_report_key(input_dev, BTN_BASE + (i-16), mask & (1 << i));
+}
+
int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac)
{
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 877c24a5df94..25baa7f29599 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -47,8 +47,8 @@
/* wacom data packet report IDs */
#define WACOM_REPORT_PENABLED 2
#define WACOM_REPORT_PENABLED_BT 3
-#define WACOM_REPORT_INTUOSREAD 5
-#define WACOM_REPORT_INTUOSWRITE 6
+#define WACOM_REPORT_INTUOS_ID1 5
+#define WACOM_REPORT_INTUOS_ID2 6
#define WACOM_REPORT_INTUOSPAD 12
#define WACOM_REPORT_INTUOS5PAD 3
#define WACOM_REPORT_DTUSPAD 21
@@ -70,6 +70,7 @@
#define WACOM_REPORT_DEVICE_LIST 16
#define WACOM_REPORT_INTUOS_PEN 16
#define WACOM_REPORT_REMOTE 17
+#define WACOM_REPORT_INTUOSHT2_ID 8
/* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 251a1d382e23..75b66eccc692 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -168,6 +168,8 @@ struct hid_item {
#define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000
+#define HID_UP_LOGIVENDOR2 0xff090000
+#define HID_UP_LOGIVENDOR3 0xff430000
#define HID_UP_LNVENDOR 0xffa00000
#define HID_UP_SENSOR 0x00200000
@@ -563,6 +565,9 @@ struct hid_device { /* device report descriptor */
wait_queue_head_t debug_wait;
};
+#define to_hid_device(pdev) \
+ container_of(pdev, struct hid_device, dev)
+
static inline void *hid_get_drvdata(struct hid_device *hdev)
{
return dev_get_drvdata(&hdev->dev);
@@ -712,6 +717,9 @@ struct hid_driver {
struct device_driver driver;
};
+#define to_hid_driver(pdrv) \
+ container_of(pdrv, struct hid_driver, driver)
+
/**
* hid_ll_driver - low level driver callbacks
* @start: called on probe to start the device