Commit 7af4c727 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID subsystem updates from Jiri Kosina:

 - The need for HID_QUIRK_NO_INIT_REPORTS per-device quirk has been
   growing dramatically during past years, so the time has come to
   switch over the default, and perform the pro-active reading only in
   cases where it's really needed (multitouch, wacom).

   The only place where this behavior is (in some form) preserved is
   hiddev so that we don't introduce userspace-visible change of
   behavior.

   From Benjamin Tissoires

 - HID++ support for power_supply / baterry reporting.

   From Benjamin Tissoires and Bastien Nocera

 - Vast improvements / rework of DS3 and DS4 in Sony driver.

   From Roderick Colenbrander

 - Improvment (in terms of getting closer to the Microsoft's
   interpretation of slightly ambiguous specification) of logical range
   interpretation in case null-state is set in the rdesc.

   From Valtteri Heikkilä and Tomasz Kramkowski

 - A lot of newly supported device IDs and small assorted fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (71 commits)
  HID: usbhid: Add HID_QUIRK_NOGET for Aten CS-1758 KVM switch
  HID: asus: support backlight on USB keyboards
  HID: wacom: Move wacom_remote_irq and wacom_remote_status_irq
  HID: wacom: generic: sync pad events only for actual packets
  HID: sony: remove redundant check for -ve err
  HID: sony: Make sure to unregister sensors on failure
  HID: sony: Make DS4 bt poll interval adjustable
  HID: sony: Set proper bit flags on DS4 output report
  HID: sony: DS4 use brighter LED colors
  HID: sony: Improve navigation controller axis/button mapping
  HID: sony: Use DS3 MAC address as unique identifier on USB
  HID: logitech-hidpp: add a sysfs file to tell we support power_supply
  HID: logitech-hidpp: enable HID++ 1.0 battery reporting
  HID: logitech-hidpp: add support for battery status for the K750
  HID: logitech-hidpp: battery: provide CAPACITY_LEVEL
  HID: logitech-hidpp: rename battery level into capacity
  HID: logitech-hidpp: battery: provide ONLINE property
  HID: logitech-hidpp: notify battery on connect
  HID: logitech-hidpp: return an error if the queried feature is not present
  HID: logitech-hidpp: create the battery for all types of HID++ devices
  ...
parents 68fed41e 4d6ca227
...@@ -4127,6 +4127,9 @@ ...@@ -4127,6 +4127,9 @@
usbhid.mousepoll= usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at. [USBHID] The interval which mice are to be polled at.
usbhid.jspoll=
[USBHID] The interval which joysticks are to be polled at.
usb-storage.delay_use= usb-storage.delay_use=
[UMS] The delay in seconds before a new device is [UMS] The delay in seconds before a new device is
scanned for Logical Units (default 1). scanned for Logical Units (default 1).
......
...@@ -17,6 +17,22 @@ Required properties: ...@@ -17,6 +17,22 @@ Required properties:
- interrupt-parent: the phandle for the interrupt controller - interrupt-parent: the phandle for the interrupt controller
- interrupts: interrupt line - interrupts: interrupt line
Additional optional properties:
Some devices may support additional optional properties to help with, e.g.,
power sequencing. The following properties can be supported by one or more
device-specific compatible properties, which should be used in addition to the
"hid-over-i2c" string.
- compatible:
* "wacom,w9013" (Wacom W9013 digitizer). Supports:
- vdd-supply
- post-power-on-delay-ms
- vdd-supply: phandle of the regulator that provides the supply voltage.
- post-power-on-delay-ms: time required by the device after enabling its regulators
before it is ready for communication. Must be used with 'vdd-supply'.
Example: Example:
i2c-hid-dev@2c { i2c-hid-dev@2c {
......
...@@ -301,7 +301,10 @@ them as any other INPUT_PROP_BUTTONPAD device. ...@@ -301,7 +301,10 @@ them as any other INPUT_PROP_BUTTONPAD device.
INPUT_PROP_ACCELEROMETER INPUT_PROP_ACCELEROMETER
------------------------- -------------------------
Directional axes on this device (absolute and/or relative x, y, z) represent Directional axes on this device (absolute and/or relative x, y, z) represent
accelerometer data. All other axes retain their meaning. A device must not mix accelerometer data. Some devices also report gyroscope data, which devices
can report through the rotational axes (absolute and/or relative rx, ry, rz).
All other axes retain their meaning. A device must not mix
regular directional axes and accelerometer axes on the same event node. regular directional axes and accelerometer axes on the same event node.
Guidelines: Guidelines:
......
...@@ -98,6 +98,18 @@ config HID_A4TECH ...@@ -98,6 +98,18 @@ config HID_A4TECH
---help--- ---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice. Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACCUTOUCH
tristate "Accutouch touch device"
depends on USB_HID
---help---
This selects a driver for the Accutouch 2216 touch controller.
The driver works around a problem in the reported device capabilities
which causes userspace to detect the device as a mouse rather than
a touchscreen.
Say Y here if you have a Accutouch 2216 touch controller.
config HID_ACRUX config HID_ACRUX
tristate "ACRUX game controller support" tristate "ACRUX game controller support"
depends on HID depends on HID
...@@ -136,13 +148,16 @@ config HID_APPLEIR ...@@ -136,13 +148,16 @@ config HID_APPLEIR
config HID_ASUS config HID_ASUS
tristate "Asus" tristate "Asus"
depends on I2C_HID depends on LEDS_CLASS
---help--- ---help---
Support for Asus notebook built-in keyboard and touchpad via i2c. Support for Asus notebook built-in keyboard and touchpad via i2c, and
the Asus Republic of Gamers laptop keyboard special keys.
Supported devices: Supported devices:
- EeeBook X205TA - EeeBook X205TA
- VivoBook E200HA - VivoBook E200HA
- GL553V series
- GL753V series
config HID_AUREAL config HID_AUREAL
tristate "Aureal" tristate "Aureal"
...@@ -215,7 +230,8 @@ config HID_CMEDIA ...@@ -215,7 +230,8 @@ config HID_CMEDIA
config HID_CP2112 config HID_CP2112
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
depends on USB_HID && I2C && GPIOLIB && GPIOLIB_IRQCHIP depends on USB_HID && I2C && GPIOLIB
select GPIOLIB_IRQCHIP
---help--- ---help---
Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
This is a HID device driver which registers as an i2c adapter This is a HID device driver which registers as an i2c adapter
...@@ -441,6 +457,7 @@ config HID_LOGITECH_DJ ...@@ -441,6 +457,7 @@ config HID_LOGITECH_DJ
config HID_LOGITECH_HIDPP config HID_LOGITECH_HIDPP
tristate "Logitech HID++ devices support" tristate "Logitech HID++ devices support"
depends on HID_LOGITECH depends on HID_LOGITECH
select POWER_SUPPLY
---help--- ---help---
Support for Logitech devices relyingon the HID++ Logitech specification Support for Logitech devices relyingon the HID++ Logitech specification
...@@ -581,6 +598,12 @@ config HID_MULTITOUCH ...@@ -581,6 +598,12 @@ config HID_MULTITOUCH
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called hid-multitouch. module will be called hid-multitouch.
config HID_NTI
tristate "NTI keyboard adapters"
---help---
Support for the "extra" Sun keyboard keys on keyboards attached
through Network Technologies USB-SUN keyboard adapters.
config HID_NTRIG config HID_NTRIG
tristate "N-Trig touch screen" tristate "N-Trig touch screen"
depends on USB_HID depends on USB_HID
......
...@@ -21,6 +21,7 @@ hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o ...@@ -21,6 +21,7 @@ hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACCUTOUCH) += hid-accutouch.o
obj-$(CONFIG_HID_ALPS) += hid-alps.o obj-$(CONFIG_HID_ALPS) += hid-alps.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLE) += hid-apple.o
...@@ -62,6 +63,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o ...@@ -62,6 +63,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTI) += hid-nti.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
......
/*
* HID driver for Elo Accutouch touchscreens
*
* Copyright (c) 2016, Collabora Ltd.
* Copyright (c) 2016, General Electric Company
*
* based on hid-penmount.c
* Copyright (c) 2014 Christian Gmeiner <christian.gmeiner <at> gmail.com>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
static int accutouch_input_mapping(struct hid_device *hdev,
struct hid_input *hi,
struct hid_field *field,
struct hid_usage *usage,
unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
}
return 0;
}
static const struct hid_device_id accutouch_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) },
{ }
};
MODULE_DEVICE_TABLE(hid, accutouch_devices);
static struct hid_driver accutouch_driver = {
.name = "hid-accutouch",
.id_table = accutouch_devices,
.input_mapping = accutouch_input_mapping,
};
module_hid_driver(accutouch_driver);
MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk");
MODULE_DESCRIPTION("Elo Accutouch HID TouchScreen driver");
MODULE_LICENSE("GPL");
...@@ -40,8 +40,12 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); ...@@ -40,8 +40,12 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define FEATURE_REPORT_ID 0x0d #define FEATURE_REPORT_ID 0x0d
#define INPUT_REPORT_ID 0x5d #define INPUT_REPORT_ID 0x5d
#define FEATURE_KBD_REPORT_ID 0x5a
#define INPUT_REPORT_SIZE 28 #define INPUT_REPORT_SIZE 28
#define FEATURE_KBD_REPORT_SIZE 16
#define SUPPORT_KBD_BACKLIGHT BIT(0)
#define MAX_CONTACTS 5 #define MAX_CONTACTS 5
...@@ -63,18 +67,31 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); ...@@ -63,18 +67,31 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define QUIRK_NO_INIT_REPORTS BIT(1) #define QUIRK_NO_INIT_REPORTS BIT(1)
#define QUIRK_SKIP_INPUT_MAPPING BIT(2) #define QUIRK_SKIP_INPUT_MAPPING BIT(2)
#define QUIRK_IS_MULTITOUCH BIT(3) #define QUIRK_IS_MULTITOUCH BIT(3)
#define QUIRK_NO_CONSUMER_USAGES BIT(4)
#define QUIRK_USE_KBD_BACKLIGHT BIT(5)
#define KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
QUIRK_NO_INIT_REPORTS) QUIRK_NO_INIT_REPORTS | \
#define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \ QUIRK_NO_CONSUMER_USAGES)
#define I2C_TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
QUIRK_SKIP_INPUT_MAPPING | \ QUIRK_SKIP_INPUT_MAPPING | \
QUIRK_IS_MULTITOUCH) QUIRK_IS_MULTITOUCH)
#define TRKID_SGN ((TRKID_MAX + 1) >> 1) #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
struct asus_kbd_leds {
struct led_classdev cdev;
struct hid_device *hdev;
struct work_struct work;
unsigned int brightness;
bool removed;
};
struct asus_drvdata { struct asus_drvdata {
unsigned long quirks; unsigned long quirks;
struct input_dev *input; struct input_dev *input;
struct asus_kbd_leds *kbd_backlight;
bool enable_backlight;
}; };
static void asus_report_contact_down(struct input_dev *input, static void asus_report_contact_down(struct input_dev *input,
...@@ -169,6 +186,148 @@ static int asus_raw_event(struct hid_device *hdev, ...@@ -169,6 +186,148 @@ static int asus_raw_event(struct hid_device *hdev,
return 0; return 0;
} }
static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size)
{
unsigned char *dmabuf;
int ret;
dmabuf = kmemdup(buf, buf_size, GFP_KERNEL);
if (!dmabuf)
return -ENOMEM;
ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
buf_size, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
kfree(dmabuf);
return ret;
}
static int asus_kbd_init(struct hid_device *hdev)
{
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
int ret;
ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
if (ret < 0)
hid_err(hdev, "Asus failed to send init command: %d\n", ret);
return ret;
}
static int asus_kbd_get_functions(struct hid_device *hdev,
unsigned char *kbd_func)
{
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
u8 *readbuf;
int ret;
ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
if (ret < 0) {
hid_err(hdev, "Asus failed to send configuration command: %d\n", ret);
return ret;
}
readbuf = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL);
if (!readbuf)
return -ENOMEM;
ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, readbuf,
FEATURE_KBD_REPORT_SIZE, HID_FEATURE_REPORT,
HID_REQ_GET_REPORT);
if (ret < 0) {
hid_err(hdev, "Asus failed to request functions: %d\n", ret);
kfree(readbuf);
return ret;
}
*kbd_func = readbuf[6];
kfree(readbuf);
return ret;
}
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
cdev);
if (led->brightness == brightness)
return;
led->brightness = brightness;
schedule_work(&led->work);
}
static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
{
struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
cdev);
return led->brightness;
}
static void asus_kbd_backlight_work(struct work_struct *work)
{
struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
int ret;
if (led->removed)
return;
buf[4] = led->brightness;
ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
if (ret < 0)
hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
}
static int asus_kbd_register_leds(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
unsigned char kbd_func;
int ret;
/* Initialize keyboard */
ret = asus_kbd_init(hdev);
if (ret < 0)
return ret;
/* Get keyboard functions */
ret = asus_kbd_get_functions(hdev, &kbd_func);
if (ret < 0)
return ret;
/* Check for backlight support */
if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
return -ENODEV;
drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
sizeof(struct asus_kbd_leds),
GFP_KERNEL);
if (!drvdata->kbd_backlight)
return -ENOMEM;
drvdata->kbd_backlight->removed = false;
drvdata->kbd_backlight->brightness = 0;
drvdata->kbd_backlight->hdev = hdev;
drvdata->kbd_backlight->cdev.name = "asus::kbd_backlight";
drvdata->kbd_backlight->cdev.max_brightness = 3;
drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
if (ret < 0) {
/* No need to have this still around */
devm_kfree(&hdev->dev, drvdata->kbd_backlight);
}
return ret;
}
static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
{ {
struct input_dev *input = hi->input; struct input_dev *input = hi->input;
...@@ -196,9 +355,14 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -196,9 +355,14 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
drvdata->input = input; drvdata->input = input;
if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
hid_warn(hdev, "Failed to initialize backlight.\n");
return 0; return 0;
} }
#define asus_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \
max, EV_KEY, (c))
static int asus_input_mapping(struct hid_device *hdev, static int asus_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, struct hid_usage *usage, unsigned long **bit,
...@@ -213,6 +377,65 @@ static int asus_input_mapping(struct hid_device *hdev, ...@@ -213,6 +377,65 @@ static int asus_input_mapping(struct hid_device *hdev,
return -1; return -1;
} }
/* ASUS-specific keyboard hotkeys */
if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) {
case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
case 0x82: asus_map_key_clear(KEY_CAMERA); break;
case 0x88: asus_map_key_clear(KEY_RFKILL); break;
case 0xb5: asus_map_key_clear(KEY_CALC); break;
case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break;
case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN); break;
/* ASUS touchpad toggle */
case 0x6b: asus_map_key_clear(KEY_F21); break;
/* ROG key */
case 0x38: asus_map_key_clear(KEY_PROG1); break;
/* Fn+C ASUS Splendid */
case 0xba: asus_map_key_clear(KEY_PROG2); break;
/* Fn+Space Power4Gear Hybrid */
case 0x5c: asus_map_key_clear(KEY_PROG3); break;
default:
/* ASUS lazily declares 256 usages, ignore the rest,
* as some make the keyboard appear as a pointer device. */
return -1;
}
/*
* Check and enable backlight only on devices with UsagePage ==
* 0xff31 to avoid initializing the keyboard firmware multiple
* times on devices with multiple HID descriptors but same
* PID/VID.
*/
if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
drvdata->enable_backlight = true;
return 1;
}
if (drvdata->quirks & QUIRK_NO_CONSUMER_USAGES &&
(usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
switch (usage->hid & HID_USAGE) {
case 0xe2: /* Mute */
case 0xe9: /* Volume up */
case 0xea: /* Volume down */
return 0;
default:
/* Ignore dummy Consumer usages which make the
* keyboard incorrectly appear as a pointer device.
*/
return -1;
}
}
return 0; return 0;
} }
...@@ -305,6 +528,16 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -305,6 +528,16 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret; return ret;
} }
static void asus_remove(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->kbd_backlight) {
drvdata->kbd_backlight->removed = true;
cancel_work_sync(&drvdata->kbd_backlight->work);
}
}
static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
...@@ -320,9 +553,13 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -320,9 +553,13 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static const struct hid_device_id asus_devices[] = { static const struct hid_device_id asus_devices[] = {
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD), KEYBOARD_QUIRKS}, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS},
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_TOUCHPAD), TOUCHPAD_QUIRKS }, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, asus_devices); MODULE_DEVICE_TABLE(hid, asus_devices);
...@@ -332,6 +569,7 @@ static struct hid_driver asus_driver = { ...@@ -332,6 +569,7 @@ static struct hid_driver asus_driver = {
.id_table = asus_devices, .id_table = asus_devices,
.report_fixup = asus_report_fixup, .report_fixup = asus_report_fixup,
.probe = asus_probe, .probe = asus_probe,
.remove = asus_remove,
.input_mapping = asus_input_mapping, .input_mapping = asus_input_mapping,
.input_configured = asus_input_configured, .input_configured = asus_input_configured,
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -1694,7 +1694,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) ...@@ -1694,7 +1694,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
len += sprintf(buf + len, "input"); len += sprintf(buf + len, "input");
if (hdev->claimed & HID_CLAIMED_HIDDEV) if (hdev->claimed & HID_CLAIMED_HIDDEV)
len += sprintf(buf + len, "%shiddev%d", len ? "," : "", len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
hdev->minor); ((struct hiddev *)hdev->hiddev)->minor);
if (hdev->claimed & HID_CLAIMED_HIDRAW) if (hdev->claimed & HID_CLAIMED_HIDRAW)
len += sprintf(buf + len, "%shidraw%d", len ? "," : "", len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
((struct hidraw *)hdev->hidraw)->minor); ((struct hidraw *)hdev->hidraw)->minor);
...@@ -1851,8 +1851,10 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1851,8 +1851,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_TOUCHPAD) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
...@@ -1891,6 +1893,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1891,6 +1893,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
...@@ -1991,6 +1994,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1991,6 +1994,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/nls.h> #include <linux/nls.h>
...@@ -1297,7 +1298,8 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1297,7 +1298,8 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.algo_data = dev; dev->adap.algo_data = dev;
dev->adap.dev.parent = &hdev->dev; dev->adap.dev.parent = &hdev->dev;
snprintf(dev->adap.name, sizeof(dev->adap.name), snprintf(dev->adap.name, sizeof(dev->adap.name),
"CP2112 SMBus Bridge on hiddev%d", hdev->minor); "CP2112 SMBus Bridge on hidraw%d",
((struct hidraw *)hdev->hidraw)->minor);
dev->hwversion = buf[2]; dev->hwversion = buf[2];
init_waitqueue_head(&dev->wait); init_waitqueue_head(&dev->wait);
......
...@@ -140,9 +140,11 @@ static const struct hid_usage_entry hid_usage_table[] = { ...@@ -140,9 +140,11 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x03, "LightPen"}, {0, 0x03, "LightPen"},
{0, 0x04, "TouchScreen"}, {0, 0x04, "TouchScreen"},
{0, 0x05, "TouchPad"}, {0, 0x05, "TouchPad"},
{0, 0x0e, "DeviceConfiguration"},
{0, 0x20, "Stylus"}, {0, 0x20, "Stylus"},
{0, 0x21, "Puck"}, {0, 0x21, "Puck"},
{0, 0x22, "Finger"}, {0, 0x22, "Finger"},
{0, 0x23, "DeviceSettings"},
{0, 0x30, "TipPressure"}, {0, 0x30, "TipPressure"},
{0, 0x31, "BarrelPressure"}, {0, 0x31, "BarrelPressure"},
{0, 0x32, "InRange"}, {0, 0x32, "InRange"},
......
...@@ -173,8 +173,10 @@ ...@@ -173,8 +173,10 @@
#define USB_VENDOR_ID_ASUSTEK 0x0b05 #define USB_VENDOR_ID_ASUSTEK 0x0b05
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b #define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
#define USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD 0x8585 #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585
#define USB_DEVICE_ID_ASUSTEK_TOUCHPAD 0x0101 #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
#define USB_VENDOR_ID_ATEN 0x0557 #define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004
...@@ -184,6 +186,7 @@ ...@@ -184,6 +186,7 @@
#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 #define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
#define USB_DEVICE_ID_ATEN_CS682 0x2213 #define USB_DEVICE_ID_ATEN_CS682 0x2213
#define USB_DEVICE_ID_ATEN_CS692 0x8021 #define USB_DEVICE_ID_ATEN_CS692 0x8021
#define USB_DEVICE_ID_ATEN_CS1758 0x2220
#define USB_VENDOR_ID_ATMEL 0x03eb #define USB_VENDOR_ID_ATMEL 0x03eb
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
...@@ -366,6 +369,7 @@ ...@@ -366,6 +369,7 @@
#define USB_VENDOR_ID_ELO 0x04E7 #define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2515 0x0022 #define USB_DEVICE_ID_ELO_TS2515 0x0022
#define USB_DEVICE_ID_ELO_TS2700 0x0020 #define USB_DEVICE_ID_ELO_TS2700 0x0020
#define USB_DEVICE_ID_ELO_ACCUTOUCH_2216 0x0050
#define USB_VENDOR_ID_EMS 0x2006 #define USB_VENDOR_ID_EMS 0x2006
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
...@@ -548,6 +552,9 @@ ...@@ -548,6 +552,9 @@
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
#define USB_VENDOR_ID_INNOMEDIA 0x1292
#define USB_DEVICE_ID_INNEX_GENESIS_ATARI 0x4745
#define USB_VENDOR_ID_ITE 0x048d #define USB_VENDOR_ID_ITE 0x048d
#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386 #define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350 #define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350
...@@ -771,6 +778,9 @@ ...@@ -771,6 +778,9 @@
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600
#define USB_DEVICE_ID_NOVATEK_MOUSE 0x1602 #define USB_DEVICE_ID_NOVATEK_MOUSE 0x1602
#define USB_VENDOR_ID_NTI 0x0757
#define USB_DEVICE_ID_USB_SUN 0x0a00
#define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_VENDOR_ID_NTRIG 0x1b96
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
......
...@@ -1150,19 +1150,27 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -1150,19 +1150,27 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
/* /*
* Ignore out-of-range values as per HID specification, * Ignore out-of-range values as per HID specification,
* section 5.10 and 6.2.25. * section 5.10 and 6.2.25, when NULL state bit is present.
* When it's not, clamp the value to match Microsoft's input
* driver as mentioned in "Required HID usages for digitizers":
* https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp
* *
* The logical_minimum < logical_maximum check is done so that we * The logical_minimum < logical_maximum check is done so that we
* don't unintentionally discard values sent by devices which * don't unintentionally discard values sent by devices which
* don't specify logical min and max. * don't specify logical min and max.
*/ */
if ((field->flags & HID_MAIN_ITEM_VARIABLE) && if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
(field->logical_minimum < field->logical_maximum) && (field->logical_minimum < field->logical_maximum)) {
if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
(value < field->logical_minimum || (value < field->logical_minimum ||
value > field->logical_maximum)) { value > field->logical_maximum)) {
dbg_hid("Ignoring out-of-range value %x\n", value); dbg_hid("Ignoring out-of-range value %x\n", value);
return; return;
} }
value = clamp(value,
field->logical_minimum,
field->logical_maximum);
}
/* /*
* Ignore reports for absolute data if the data didn't change. This is * Ignore reports for absolute data if the data didn't change. This is
......
...@@ -692,8 +692,12 @@ static void logi_dj_ll_close(struct hid_device *hid) ...@@ -692,8 +692,12 @@ static void logi_dj_ll_close(struct hid_device *hid)
dbg_hid("%s:%s\n", __func__, hid->phys); dbg_hid("%s:%s\n", __func__, hid->phys);
} }
static u8 unifying_name_query[] = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00}; /*
static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5}; * Register 0xB5 is "pairing information". It is solely intended for the
* receiver, so do not overwrite the device index.
*/
static u8 unifying_pairing_query[] = {0x10, 0xff, 0x83, 0xb5};
static u8 unifying_pairing_answer[] = {0x11, 0xff, 0x83, 0xb5};
static int logi_dj_ll_raw_request(struct hid_device *hid, static int logi_dj_ll_raw_request(struct hid_device *hid,
unsigned char reportnum, __u8 *buf, unsigned char reportnum, __u8 *buf,
...@@ -712,9 +716,9 @@ static int logi_dj_ll_raw_request(struct hid_device *hid, ...@@ -712,9 +716,9 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
/* special case where we should not overwrite /* special case where we should not overwrite
* the device_index */ * the device_index */
if (count == 7 && !memcmp(buf, unifying_name_query, if (count == 7 && !memcmp(buf, unifying_pairing_query,
sizeof(unifying_name_query))) sizeof(unifying_pairing_query)))
buf[4] |= djdev->device_index - 1; buf[4] = (buf[4] & 0xf0) | (djdev->device_index - 1);
else else
buf[1] = djdev->device_index; buf[1] = djdev->device_index;
return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf, return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
...@@ -911,9 +915,8 @@ static int logi_dj_hidpp_event(struct hid_device *hdev, ...@@ -911,9 +915,8 @@ static int logi_dj_hidpp_event(struct hid_device *hdev,
/* special case were the device wants to know its unifying /* special case were the device wants to know its unifying
* name */ * name */
if (size == HIDPP_REPORT_LONG_LENGTH && if (size == HIDPP_REPORT_LONG_LENGTH &&
!memcmp(data, unifying_name_answer, !memcmp(data, unifying_pairing_answer,
sizeof(unifying_name_answer)) && sizeof(unifying_pairing_answer)))
((data[4] & 0xF0) == 0x40))
device_index = (data[4] & 0x0F) + 1; device_index = (data[4] & 0x0F) + 1;
else else
return false; return false;
......
This diff is collapsed.
...@@ -69,6 +69,7 @@ MODULE_LICENSE("GPL"); ...@@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
#define MT_QUIRK_FORCE_GET_FEATURE (1 << 13) #define MT_QUIRK_FORCE_GET_FEATURE (1 << 13)
#define MT_QUIRK_FIX_CONST_CONTACT_ID (1 << 14) #define MT_QUIRK_FIX_CONST_CONTACT_ID (1 << 14)
#define MT_QUIRK_TOUCH_SIZE_SCALING (1 << 15)
#define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03 #define MT_INPUTMODE_TOUCHPAD 0x03
...@@ -222,7 +223,8 @@ static struct mt_class mt_classes[] = { ...@@ -222,7 +223,8 @@ static struct mt_class mt_classes[] = {
*/ */
{ .name = MT_CLS_3M, { .name = MT_CLS_3M,
.quirks = MT_QUIRK_VALID_IS_CONFIDENCE | .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
MT_QUIRK_SLOT_IS_CONTACTID, MT_QUIRK_SLOT_IS_CONTACTID |
MT_QUIRK_TOUCH_SIZE_SCALING,
.sn_move = 2048, .sn_move = 2048,
.sn_width = 128, .sn_width = 128,
.sn_height = 128, .sn_height = 128,
...@@ -658,9 +660,17 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -658,9 +660,17 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
if (active) { if (active) {
/* this finger is in proximity of the sensor */ /* this finger is in proximity of the sensor */
int wide = (s->w > s->h); int wide = (s->w > s->h);
/* divided by two to match visual scale of touch */ int major = max(s->w, s->h);
int major = max(s->w, s->h) >> 1; int minor = min(s->w, s->h);
int minor = min(s->w, s->h) >> 1;
/*
* divided by two to match visual scale of touch
* for devices with this quirk
*/
if (td->mtclass.quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
major = major >> 1;
minor = minor >> 1;
}
input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
......
/*
* USB HID quirks support for Network Technologies, Inc. "USB-SUN" USB
* adapter for pre-USB Sun keyboards
*
* Copyright (c) 2011 Google, Inc.
*
* Based on HID apple driver by
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("Jonathan Klabunde Tomer <jktomer@google.com>");
MODULE_DESCRIPTION("HID driver for Network Technologies USB-SUN keyboard adapter");
/*
* NTI Sun keyboard adapter has wrong logical maximum in report descriptor
*/
static __u8 *nti_usbsun_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) {
hid_info(hdev, "fixing up NTI USB-SUN keyboard adapter report descriptor\n");
rdesc[53] = rdesc[59] = 0xe7;
}
return rdesc;
}
static const struct hid_device_id nti_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) },
{ }
};
MODULE_DEVICE_TABLE(hid, nti_devices);
static struct hid_driver nti_driver = {
.name = "nti",
.id_table = nti_devices,
.report_fixup = nti_usbsun_report_fixup
};
module_hid_driver(nti_driver);
MODULE_LICENSE("GPL");
This diff is collapsed.
...@@ -508,66 +508,6 @@ static int i2c_hid_get_report_length(struct hid_report *report) ...@@ -508,66 +508,6 @@ static int i2c_hid_get_report_length(struct hid_report *report)
report->device->report_enum[report->type].numbered + 2; report->device->report_enum[report->type].numbered + 2;
} }
static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
size_t bufsize)
{
struct hid_device *hid = report->device;
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
unsigned int size, ret_size;
size = i2c_hid_get_report_length(report);
if (i2c_hid_get_report(client,
report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
report->id, buffer, size))
return;
i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, buffer);
ret_size = buffer[0] | (buffer[1] << 8);
if (ret_size != size) {
dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
__func__, size, ret_size);
return;
}
/* hid->driver_lock is held as we are in probe function,
* we just need to setup the input fields, so using
* hid_report_raw_event is safe. */
hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
}
/*
* Initialize all reports
*/
static void i2c_hid_init_reports(struct hid_device *hid)
{
struct hid_report *report;
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
if (!inbuf) {
dev_err(&client->dev, "can not retrieve initial reports\n");
return;
}
/*
* The device must be powered on while we fetch initial reports
* from it.
*/
pm_runtime_get_sync(&client->dev);
list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
pm_runtime_put(&client->dev);
kfree(inbuf);
}
/* /*
* Traverse the supplied list of reports and find the longest * Traverse the supplied list of reports and find the longest
*/ */
...@@ -789,9 +729,6 @@ static int i2c_hid_start(struct hid_device *hid) ...@@ -789,9 +729,6 @@ static int i2c_hid_start(struct hid_device *hid)
return ret; return ret;
} }
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
i2c_hid_init_reports(hid);
return 0; return 0;
} }
...@@ -994,6 +931,11 @@ static int i2c_hid_of_probe(struct i2c_client *client, ...@@ -994,6 +931,11 @@ static int i2c_hid_of_probe(struct i2c_client *client,
} }
pdata->hid_descriptor_address = val; pdata->hid_descriptor_address = val;
ret = of_property_read_u32(dev->of_node, "post-power-on-delay-ms",
&val);
if (!ret)
pdata->post_power_delay_ms = val;
return 0; return 0;
} }
...@@ -1053,6 +995,24 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1053,6 +995,24 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->pdata = *platform_data; ihid->pdata = *platform_data;
} }
ihid->pdata.supply = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(ihid->pdata.supply)) {
ret = PTR_ERR(ihid->pdata.supply);
if (ret != -EPROBE_DEFER)
dev_err(&client->dev, "Failed to get regulator: %d\n",
ret);
goto err;
}
ret = regulator_enable(ihid->pdata.supply);
if (ret < 0) {
dev_err(&client->dev, "Failed to enable regulator: %d\n",
ret);
goto err;
}
if (ihid->pdata.post_power_delay_ms)
msleep(ihid->pdata.post_power_delay_ms);
i2c_set_clientdata(client, ihid); i2c_set_clientdata(client, ihid);
ihid->client = client; ihid->client = client;
...@@ -1068,7 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1068,7 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
* real computation later. */ * real computation later. */
ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE); ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE);
if (ret < 0) if (ret < 0)
goto err; goto err_regulator;
pm_runtime_get_noresume(&client->dev); pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev); pm_runtime_set_active(&client->dev);
...@@ -1125,6 +1085,9 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1125,6 +1085,9 @@ static int i2c_hid_probe(struct i2c_client *client,
pm_runtime_put_noidle(&client->dev); pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
err_regulator:
regulator_disable(ihid->pdata.supply);
err: err:
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
kfree(ihid); kfree(ihid);
...@@ -1149,6 +1112,8 @@ static int i2c_hid_remove(struct i2c_client *client) ...@@ -1149,6 +1112,8 @@ static int i2c_hid_remove(struct i2c_client *client)
if (ihid->bufsize) if (ihid->bufsize)
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
regulator_disable(ihid->pdata.supply);
kfree(ihid); kfree(ihid);
return 0; return 0;
...@@ -1199,6 +1164,10 @@ static int i2c_hid_suspend(struct device *dev) ...@@ -1199,6 +1164,10 @@ static int i2c_hid_suspend(struct device *dev)
else else
hid_warn(hid, "Failed to enable irq wake: %d\n", hid_warn(hid, "Failed to enable irq wake: %d\n",
wake_status); wake_status);
} else {
ret = regulator_disable(ihid->pdata.supply);
if (ret < 0)
hid_warn(hid, "Failed to disable supply: %d\n", ret);
} }
return 0; return 0;
...@@ -1212,7 +1181,13 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1212,7 +1181,13 @@ static int i2c_hid_resume(struct device *dev)
struct hid_device *hid = ihid->hid; struct hid_device *hid = ihid->hid;
int wake_status; int wake_status;
if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { if (!device_may_wakeup(&client->dev)) {
ret = regulator_enable(ihid->pdata.supply);
if (ret < 0)
hid_warn(hid, "Failed to enable supply: %d\n", ret);
if (ihid->pdata.post_power_delay_ms)
msleep(ihid->pdata.post_power_delay_ms);
} else if (ihid->irq_wake_enabled) {
wake_status = disable_irq_wake(client->irq); wake_status = disable_irq_wake(client->irq);
if (!wake_status) if (!wake_status)
ihid->irq_wake_enabled = false; ihid->irq_wake_enabled = false;
......
...@@ -52,6 +52,10 @@ static unsigned int hid_mousepoll_interval; ...@@ -52,6 +52,10 @@ static unsigned int hid_mousepoll_interval;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
static unsigned int hid_jspoll_interval;
module_param_named(jspoll, hid_jspoll_interval, uint, 0644);
MODULE_PARM_DESC(jspoll, "Polling interval of joysticks");
static unsigned int ignoreled; static unsigned int ignoreled;
module_param_named(ignoreled, ignoreled, uint, 0644); module_param_named(ignoreled, ignoreled, uint, 0644);
MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds"); MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
...@@ -753,11 +757,9 @@ void usbhid_init_reports(struct hid_device *hid) ...@@ -753,11 +757,9 @@ void usbhid_init_reports(struct hid_device *hid)
struct hid_report_enum *report_enum; struct hid_report_enum *report_enum;
int err, ret; int err, ret;
if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
report_enum = &hid->report_enum[HID_INPUT_REPORT]; report_enum = &hid->report_enum[HID_INPUT_REPORT];
list_for_each_entry(report, &report_enum->report_list, list) list_for_each_entry(report, &report_enum->report_list, list)
usbhid_submit_report(hid, report, USB_DIR_IN); usbhid_submit_report(hid, report, USB_DIR_IN);
}
report_enum = &hid->report_enum[HID_FEATURE_REPORT]; report_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(report, &report_enum->report_list, list) list_for_each_entry(report, &report_enum->report_list, list)
...@@ -1004,10 +1006,9 @@ static int usbhid_parse(struct hid_device *hid) ...@@ -1004,10 +1006,9 @@ static int usbhid_parse(struct hid_device *hid)
return -EINVAL; return -EINVAL;
} }
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { rdesc = kmalloc(rsize, GFP_KERNEL);
dbg_hid("couldn't allocate rdesc memory\n"); if (!rdesc)
return -ENOMEM; return -ENOMEM;
}
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
...@@ -1077,13 +1078,21 @@ static int usbhid_start(struct hid_device *hid) ...@@ -1077,13 +1078,21 @@ static int usbhid_start(struct hid_device *hid)
if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL && if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
dev->speed == USB_SPEED_HIGH) { dev->speed == USB_SPEED_HIGH) {
interval = fls(endpoint->bInterval*8); interval = fls(endpoint->bInterval*8);
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n", pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
hid->name, endpoint->bInterval, interval); hid->name, endpoint->bInterval, interval);
} }
/* Change the polling interval of mice. */ /* Change the polling interval of mice and joysticks. */
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) switch (hid->collection->usage) {
case HID_GD_MOUSE:
if (hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval; interval = hid_mousepoll_interval;
break;
case HID_GD_JOYSTICK:
if (hid_jspoll_interval > 0)
interval = hid_jspoll_interval;
break;
}
ret = -ENOMEM; ret = -ENOMEM;
if (usb_endpoint_dir_in(endpoint)) { if (usb_endpoint_dir_in(endpoint)) {
...@@ -1120,9 +1129,6 @@ static int usbhid_start(struct hid_device *hid) ...@@ -1120,9 +1129,6 @@ static int usbhid_start(struct hid_device *hid)
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
usbhid_init_reports(hid);
set_bit(HID_STARTED, &usbhid->iofl); set_bit(HID_STARTED, &usbhid->iofl);
if (hid->quirks & HID_QUIRK_ALWAYS_POLL) { if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
...@@ -1456,10 +1462,9 @@ static int hid_post_reset(struct usb_interface *intf) ...@@ -1456,10 +1462,9 @@ static int hid_post_reset(struct usb_interface *intf)
* the size of the HID report descriptor has not changed. * the size of the HID report descriptor has not changed.
*/ */
rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
if (!rdesc) { if (!rdesc)
dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
return -ENOMEM; return -ENOMEM;
}
status = hid_get_class_descriptor(dev, status = hid_get_class_descriptor(dev,
interface->desc.bInterfaceNumber, interface->desc.bInterfaceNumber,
HID_DT_REPORT, rdesc, hid->dev_rsize); HID_DT_REPORT, rdesc, hid->dev_rsize);
...@@ -1637,7 +1642,7 @@ static int __init hid_init(void) ...@@ -1637,7 +1642,7 @@ static int __init hid_init(void)
retval = usb_register(&hid_driver); retval = usb_register(&hid_driver);
if (retval) if (retval)
goto usb_register_fail; goto usb_register_fail;
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); pr_info(KBUILD_MODNAME ": " DRIVER_DESC "\n");
return 0; return 0;
usb_register_fail: usb_register_fail:
......
...@@ -65,6 +65,7 @@ static const struct hid_blacklist { ...@@ -65,6 +65,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS1758, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET },
...@@ -161,10 +162,11 @@ static const struct hid_blacklist { ...@@ -161,10 +162,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_INPUT_REPORTS }, { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT },
{ 0, 0 } { 0, 0 }
}; };
...@@ -240,10 +242,8 @@ static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, ...@@ -240,10 +242,8 @@ static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
} }
q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL); q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
if (!q_new) { if (!q_new)
dbg_hid("Could not allocate quirks_list_struct\n");
return -ENOMEM; return -ENOMEM;
}
q_new->hid_bl_item.idVendor = idVendor; q_new->hid_bl_item.idVendor = idVendor;
q_new->hid_bl_item.idProduct = idProduct; q_new->hid_bl_item.idProduct = idProduct;
...@@ -310,8 +310,7 @@ int usbhid_quirks_init(char **quirks_param) ...@@ -310,8 +310,7 @@ int usbhid_quirks_init(char **quirks_param)
if (m != 3 || if (m != 3 ||
usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) { usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
printk(KERN_WARNING pr_warn("Could not parse HID quirk module param %s\n",
"Could not parse HID quirk module param %s\n",
quirks_param[n]); quirks_param[n]);
} }
} }
......
...@@ -47,16 +47,6 @@ ...@@ -47,16 +47,6 @@
#endif #endif
#define HIDDEV_BUFFER_SIZE 2048 #define HIDDEV_BUFFER_SIZE 2048
struct hiddev {
int exist;
int open;
struct mutex existancelock;
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
spinlock_t list_lock;
};
struct hiddev_list { struct hiddev_list {
struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
int head; int head;
...@@ -690,6 +680,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -690,6 +680,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCINITREPORT: case HIDIOCINITREPORT:
usbhid_init_reports(hid); usbhid_init_reports(hid);
hiddev->initialized = true;
r = 0; r = 0;
break; break;
...@@ -791,6 +782,10 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -791,6 +782,10 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCGUSAGES: case HIDIOCGUSAGES:
case HIDIOCSUSAGES: case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX: case HIDIOCGCOLLECTIONINDEX:
if (!hiddev->initialized) {
usbhid_init_reports(hid);
hiddev->initialized = true;
}
r = hiddev_ioctl_usage(hiddev, cmd, user_arg); r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
break; break;
...@@ -911,6 +906,15 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) ...@@ -911,6 +906,15 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
kfree(hiddev); kfree(hiddev);
return -1; return -1;
} }
/*
* If HID_QUIRK_NO_INIT_REPORTS is set, make sure we don't initialize
* the reports.
*/
hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS;
hiddev->minor = usbhid->intf->minor;
return 0; return 0;
} }
......
...@@ -110,6 +110,7 @@ enum wacom_worker { ...@@ -110,6 +110,7 @@ enum wacom_worker {
WACOM_WORKER_WIRELESS, WACOM_WORKER_WIRELESS,
WACOM_WORKER_BATTERY, WACOM_WORKER_BATTERY,
WACOM_WORKER_REMOTE, WACOM_WORKER_REMOTE,
WACOM_WORKER_MODE_CHANGE,
}; };
struct wacom; struct wacom;
...@@ -167,6 +168,7 @@ struct wacom { ...@@ -167,6 +168,7 @@ struct wacom {
struct work_struct remote_work; struct work_struct remote_work;
struct delayed_work init_work; struct delayed_work init_work;
struct wacom_remote *remote; struct wacom_remote *remote;
struct work_struct mode_change_work;
bool generic_has_leds; bool generic_has_leds;
struct wacom_leds { struct wacom_leds {
struct wacom_group_leds *groups; struct wacom_group_leds *groups;
...@@ -196,6 +198,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac, ...@@ -196,6 +198,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
case WACOM_WORKER_REMOTE: case WACOM_WORKER_REMOTE:
schedule_work(&wacom->remote_work); schedule_work(&wacom->remote_work);
break; break;
case WACOM_WORKER_MODE_CHANGE:
schedule_work(&wacom->mode_change_work);
break;
} }
} }
......
...@@ -325,6 +325,13 @@ static void wacom_post_parse_hid(struct hid_device *hdev, ...@@ -325,6 +325,13 @@ static void wacom_post_parse_hid(struct hid_device *hdev,
if (features->type == HID_GENERIC) { if (features->type == HID_GENERIC) {
/* Any last-minute generic device setup */ /* Any last-minute generic device setup */
if (wacom_wac->has_mode_change) {
if (wacom_wac->is_direct_mode)
features->device_type |= WACOM_DEVICETYPE_DIRECT;
else
features->device_type &= ~WACOM_DEVICETYPE_DIRECT;
}
if (features->touch_max > 1) { if (features->touch_max > 1) {
if (features->device_type & WACOM_DEVICETYPE_DIRECT) if (features->device_type & WACOM_DEVICETYPE_DIRECT)
input_mt_init_slots(wacom_wac->touch_input, input_mt_init_slots(wacom_wac->touch_input,
...@@ -2093,8 +2100,10 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac) ...@@ -2093,8 +2100,10 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
wacom_wac->shared->touch_input = wacom_wac->touch_input; wacom_wac->shared->touch_input = wacom_wac->touch_input;
} }
if (wacom_wac->has_mute_touch_switch) if (wacom_wac->has_mute_touch_switch) {
wacom_wac->shared->has_mute_touch_switch = true; wacom_wac->shared->has_mute_touch_switch = true;
wacom_wac->shared->is_touch_on = true;
}
if (wacom_wac->shared->has_mute_touch_switch && if (wacom_wac->shared->has_mute_touch_switch &&
wacom_wac->shared->touch_input) { wacom_wac->shared->touch_input) {
...@@ -2490,6 +2499,46 @@ static void wacom_remote_work(struct work_struct *work) ...@@ -2490,6 +2499,46 @@ static void wacom_remote_work(struct work_struct *work)
} }
} }
static void wacom_mode_change_work(struct work_struct *work)
{
struct wacom *wacom = container_of(work, struct wacom, mode_change_work);
struct wacom_shared *shared = wacom->wacom_wac.shared;
struct wacom *wacom1 = NULL;
struct wacom *wacom2 = NULL;
bool is_direct = wacom->wacom_wac.is_direct_mode;
int error = 0;
if (shared->pen) {
wacom1 = hid_get_drvdata(shared->pen);
wacom_release_resources(wacom1);
hid_hw_stop(wacom1->hdev);
wacom1->wacom_wac.has_mode_change = true;
wacom1->wacom_wac.is_direct_mode = is_direct;
}
if (shared->touch) {
wacom2 = hid_get_drvdata(shared->touch);
wacom_release_resources(wacom2);
hid_hw_stop(wacom2->hdev);
wacom2->wacom_wac.has_mode_change = true;
wacom2->wacom_wac.is_direct_mode = is_direct;
}
if (wacom1) {
error = wacom_parse_and_register(wacom1, false);
if (error)
return;
}
if (wacom2) {
error = wacom_parse_and_register(wacom2, false);
if (error)
return;
}
return;
}
static int wacom_probe(struct hid_device *hdev, static int wacom_probe(struct hid_device *hdev,
const struct hid_device_id *id) const struct hid_device_id *id)
{ {
...@@ -2534,6 +2583,7 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -2534,6 +2583,7 @@ static int wacom_probe(struct hid_device *hdev,
INIT_WORK(&wacom->wireless_work, wacom_wireless_work); INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work); INIT_WORK(&wacom->remote_work, wacom_remote_work);
INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work);
/* ask for the report descriptor to be loaded by HID */ /* ask for the report descriptor to be loaded by HID */
error = hid_parse(hdev); error = hid_parse(hdev);
...@@ -2576,6 +2626,7 @@ static void wacom_remove(struct hid_device *hdev) ...@@ -2576,6 +2626,7 @@ static void wacom_remove(struct hid_device *hdev)
cancel_work_sync(&wacom->wireless_work); cancel_work_sync(&wacom->wireless_work);
cancel_work_sync(&wacom->battery_work); cancel_work_sync(&wacom->battery_work);
cancel_work_sync(&wacom->remote_work); cancel_work_sync(&wacom->remote_work);
cancel_work_sync(&wacom->mode_change_work);
if (hdev->bus == BUS_BLUETOOTH) if (hdev->bus == BUS_BLUETOOTH)
device_remove_file(&hdev->dev, &dev_attr_speed); device_remove_file(&hdev->dev, &dev_attr_speed);
......
This diff is collapsed.
...@@ -120,6 +120,11 @@ ...@@ -120,6 +120,11 @@
#define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b) #define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b)
#define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910) #define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910)
#define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950) #define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950)
#define WACOM_HID_WD_MODE_CHANGE (WACOM_HID_UP_WACOMDIGITIZER | 0x0980)
#define WACOM_HID_WD_MUTE_DEVICE (WACOM_HID_UP_WACOMDIGITIZER | 0x0981)
#define WACOM_HID_WD_CONTROLPANEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0982)
#define WACOM_HID_WD_ONSCREEN_KEYBOARD (WACOM_HID_UP_WACOMDIGITIZER | 0x0983)
#define WACOM_HID_WD_BUTTONCONFIG (WACOM_HID_UP_WACOMDIGITIZER | 0x0986)
#define WACOM_HID_WD_BUTTONHOME (WACOM_HID_UP_WACOMDIGITIZER | 0x0990) #define WACOM_HID_WD_BUTTONHOME (WACOM_HID_UP_WACOMDIGITIZER | 0x0990)
#define WACOM_HID_WD_BUTTONUP (WACOM_HID_UP_WACOMDIGITIZER | 0x0991) #define WACOM_HID_WD_BUTTONUP (WACOM_HID_UP_WACOMDIGITIZER | 0x0991)
#define WACOM_HID_WD_BUTTONDOWN (WACOM_HID_UP_WACOMDIGITIZER | 0x0992) #define WACOM_HID_WD_BUTTONDOWN (WACOM_HID_UP_WACOMDIGITIZER | 0x0992)
...@@ -270,6 +275,7 @@ struct wacom_shared { ...@@ -270,6 +275,7 @@ struct wacom_shared {
struct hid_device *pen; struct hid_device *pen;
struct hid_device *touch; struct hid_device *touch;
bool has_mute_touch_switch; bool has_mute_touch_switch;
bool is_touch_on;
}; };
struct hid_data { struct hid_data {
...@@ -295,6 +301,7 @@ struct hid_data { ...@@ -295,6 +301,7 @@ struct hid_data {
int bat_charging; int bat_charging;
int bat_connected; int bat_connected;
int ps_connected; int ps_connected;
bool pad_input_event_flag;
}; };
struct wacom_remote_data { struct wacom_remote_data {
...@@ -327,6 +334,9 @@ struct wacom_wac { ...@@ -327,6 +334,9 @@ struct wacom_wac {
int mode_value; int mode_value;
struct hid_data hid_data; struct hid_data hid_data;
bool has_mute_touch_switch; bool has_mute_touch_switch;
bool has_mode_change;
bool is_direct_mode;
}; };
#endif #endif
...@@ -268,6 +268,8 @@ struct hid_item { ...@@ -268,6 +268,8 @@ struct hid_item {
#define HID_CP_APPLICATIONLAUNCHBUTTONS 0x000c0180 #define HID_CP_APPLICATIONLAUNCHBUTTONS 0x000c0180
#define HID_CP_GENERICGUIAPPLICATIONCONTROLS 0x000c0200 #define HID_CP_GENERICGUIAPPLICATIONCONTROLS 0x000c0200
#define HID_DG_DEVICECONFIG 0x000d000e
#define HID_DG_DEVICESETTINGS 0x000d0023
#define HID_DG_CONFIDENCE 0x000d0047 #define HID_DG_CONFIDENCE 0x000d0047
#define HID_DG_WIDTH 0x000d0048 #define HID_DG_WIDTH 0x000d0048
#define HID_DG_HEIGHT 0x000d0049 #define HID_DG_HEIGHT 0x000d0049
...@@ -322,7 +324,7 @@ struct hid_item { ...@@ -322,7 +324,7 @@ struct hid_item {
#define HID_QUIRK_MULTI_INPUT 0x00000040 #define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 #define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 #define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 /* 0x00000200 reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
#define HID_QUIRK_ALWAYS_POLL 0x00000400 #define HID_QUIRK_ALWAYS_POLL 0x00000400
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
...@@ -541,7 +543,6 @@ struct hid_device { /* device report descriptor */ ...@@ -541,7 +543,6 @@ struct hid_device { /* device report descriptor */
struct list_head inputs; /* The list of inputs */ struct list_head inputs; /* The list of inputs */
void *hiddev; /* The hiddev structure */ void *hiddev; /* The hiddev structure */
void *hidraw; void *hidraw;
int minor; /* Hiddev minor number */
int open; /* is the device open by anyone? */ int open; /* is the device open by anyone? */
char name[128]; /* Device name */ char name[128]; /* Device name */
......
...@@ -32,6 +32,18 @@ ...@@ -32,6 +32,18 @@
* In-kernel definitions. * In-kernel definitions.
*/ */
struct hiddev {
int minor;
int exist;
int open;
struct mutex existancelock;
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
spinlock_t list_lock;
bool initialized;
};
struct hid_device; struct hid_device;
struct hid_usage; struct hid_usage;
struct hid_field; struct hid_field;
......
...@@ -14,9 +14,13 @@ ...@@ -14,9 +14,13 @@
#include <linux/types.h> #include <linux/types.h>
struct regulator;
/** /**
* struct i2chid_platform_data - used by hid over i2c implementation. * struct i2chid_platform_data - used by hid over i2c implementation.
* @hid_descriptor_address: i2c register where the HID descriptor is stored. * @hid_descriptor_address: i2c register where the HID descriptor is stored.
* @supply: regulator for powering on the device.
* @post_power_delay_ms: delay after powering on before device is usable.
* *
* Note that it is the responsibility of the platform driver (or the acpi 5.0 * Note that it is the responsibility of the platform driver (or the acpi 5.0
* driver, or the flattened device tree) to setup the irq related to the gpio in * driver, or the flattened device tree) to setup the irq related to the gpio in
...@@ -31,6 +35,8 @@ ...@@ -31,6 +35,8 @@
*/ */
struct i2c_hid_platform_data { struct i2c_hid_platform_data {
u16 hid_descriptor_address; u16 hid_descriptor_address;
struct regulator *supply;
int post_power_delay_ms;
}; };
#endif /* __LINUX_I2C_HID_H */ #endif /* __LINUX_I2C_HID_H */
...@@ -641,6 +641,7 @@ ...@@ -641,6 +641,7 @@
* e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
*/ */
#define KEY_DATA 0x277 #define KEY_DATA 0x277
#define KEY_ONSCREEN_KEYBOARD 0x278
#define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0
......
...@@ -61,9 +61,14 @@ struct input_id { ...@@ -61,9 +61,14 @@ struct input_id {
* Note that input core does not clamp reported values to the * Note that input core does not clamp reported values to the
* [minimum, maximum] limits, such task is left to userspace. * [minimum, maximum] limits, such task is left to userspace.
* *
* Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
* units per millimeter (units/mm), resolution for rotational axes * is reported in units per millimeter (units/mm), resolution
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
* in units per radian.
* When INPUT_PROP_ACCELEROMETER is set the resolution changes.
* The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
* in units per g (units/g) and in units per degree per second
* (units/deg/s) for rotational axes (ABS_RX, ABS_RY, ABS_RZ).
*/ */
struct input_absinfo { struct input_absinfo {
__s32 value; __s32 value;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment