mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-30 05:15:03 +00:00
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 ...
This commit is contained in:
commit
7af4c727c7
@ -4127,6 +4127,9 @@
|
||||
usbhid.mousepoll=
|
||||
[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=
|
||||
[UMS] The delay in seconds before a new device is
|
||||
scanned for Logical Units (default 1).
|
||||
|
@ -17,6 +17,22 @@ Required properties:
|
||||
- interrupt-parent: the phandle for the interrupt controller
|
||||
- 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:
|
||||
|
||||
i2c-hid-dev@2c {
|
||||
|
@ -301,7 +301,10 @@ them as any other INPUT_PROP_BUTTONPAD device.
|
||||
INPUT_PROP_ACCELEROMETER
|
||||
-------------------------
|
||||
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.
|
||||
|
||||
Guidelines:
|
||||
|
@ -98,6 +98,18 @@ config HID_A4TECH
|
||||
---help---
|
||||
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
|
||||
tristate "ACRUX game controller support"
|
||||
depends on HID
|
||||
@ -136,13 +148,16 @@ config HID_APPLEIR
|
||||
|
||||
config HID_ASUS
|
||||
tristate "Asus"
|
||||
depends on I2C_HID
|
||||
depends on LEDS_CLASS
|
||||
---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:
|
||||
- EeeBook X205TA
|
||||
- VivoBook E200HA
|
||||
- GL553V series
|
||||
- GL753V series
|
||||
|
||||
config HID_AUREAL
|
||||
tristate "Aureal"
|
||||
@ -215,7 +230,8 @@ config HID_CMEDIA
|
||||
|
||||
config HID_CP2112
|
||||
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---
|
||||
Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
|
||||
This is a HID device driver which registers as an i2c adapter
|
||||
@ -441,6 +457,7 @@ config HID_LOGITECH_DJ
|
||||
config HID_LOGITECH_HIDPP
|
||||
tristate "Logitech HID++ devices support"
|
||||
depends on HID_LOGITECH
|
||||
select POWER_SUPPLY
|
||||
---help---
|
||||
Support for Logitech devices relyingon the HID++ Logitech specification
|
||||
|
||||
@ -581,6 +598,12 @@ config HID_MULTITOUCH
|
||||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "N-Trig touch screen"
|
||||
depends on USB_HID
|
||||
|
@ -21,6 +21,7 @@ hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
|
||||
hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.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_ACRUX) += hid-axff.o
|
||||
obj-$(CONFIG_HID_APPLE) += hid-apple.o
|
||||
@ -62,6 +63,7 @@ obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
|
||||
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
|
||||
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.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_ORTEK) += hid-ortek.o
|
||||
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
|
||||
|
52
drivers/hid/hid-accutouch.c
Normal file
52
drivers/hid/hid-accutouch.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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");
|
||||
|
||||
#define FEATURE_REPORT_ID 0x0d
|
||||
#define INPUT_REPORT_ID 0x5d
|
||||
#define FEATURE_KBD_REPORT_ID 0x5a
|
||||
|
||||
#define INPUT_REPORT_SIZE 28
|
||||
#define FEATURE_KBD_REPORT_SIZE 16
|
||||
|
||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
||||
|
||||
#define MAX_CONTACTS 5
|
||||
|
||||
@ -63,18 +67,31 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define QUIRK_NO_INIT_REPORTS BIT(1)
|
||||
#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
|
||||
#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 | \
|
||||
QUIRK_NO_INIT_REPORTS)
|
||||
#define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
|
||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
||||
QUIRK_NO_INIT_REPORTS | \
|
||||
QUIRK_NO_CONSUMER_USAGES)
|
||||
#define I2C_TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
|
||||
QUIRK_SKIP_INPUT_MAPPING | \
|
||||
QUIRK_IS_MULTITOUCH)
|
||||
|
||||
#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 {
|
||||
unsigned long quirks;
|
||||
struct input_dev *input;
|
||||
struct asus_kbd_leds *kbd_backlight;
|
||||
bool enable_backlight;
|
||||
};
|
||||
|
||||
static void asus_report_contact_down(struct input_dev *input,
|
||||
@ -169,6 +186,148 @@ static int asus_raw_event(struct hid_device *hdev,
|
||||
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)
|
||||
{
|
||||
struct input_dev *input = hi->input;
|
||||
@ -196,9 +355,14 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
|
||||
drvdata->input = input;
|
||||
|
||||
if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
|
||||
hid_warn(hdev, "Failed to initialize backlight.\n");
|
||||
|
||||
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,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit,
|
||||
@ -213,6 +377,65 @@ static int asus_input_mapping(struct hid_device *hdev,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -305,6 +528,16 @@ err_stop_hw:
|
||||
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,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
@ -320,9 +553,13 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
|
||||
static const struct hid_device_id asus_devices[] = {
|
||||
{ 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,
|
||||
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);
|
||||
@ -332,6 +569,7 @@ static struct hid_driver asus_driver = {
|
||||
.id_table = asus_devices,
|
||||
.report_fixup = asus_report_fixup,
|
||||
.probe = asus_probe,
|
||||
.remove = asus_remove,
|
||||
.input_mapping = asus_input_mapping,
|
||||
.input_configured = asus_input_configured,
|
||||
#ifdef CONFIG_PM
|
||||
|
@ -1694,7 +1694,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
|
||||
len += sprintf(buf + len, "input");
|
||||
if (hdev->claimed & HID_CLAIMED_HIDDEV)
|
||||
len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
|
||||
hdev->minor);
|
||||
((struct hiddev *)hdev->hiddev)->minor);
|
||||
if (hdev->claimed & HID_CLAIMED_HIDRAW)
|
||||
len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
|
||||
((struct hidraw *)hdev->hidraw)->minor);
|
||||
@ -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_FOUNTAIN_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_TOUCHPAD) },
|
||||
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
|
||||
{ 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_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
|
||||
@ -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_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
|
||||
{ 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_EZKEY, USB_DEVICE_ID_BTC_8193) },
|
||||
{ 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[] = {
|
||||
{ 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_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_1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nls.h>
|
||||
@ -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.dev.parent = &hdev->dev;
|
||||
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];
|
||||
init_waitqueue_head(&dev->wait);
|
||||
|
||||
|
@ -140,9 +140,11 @@ static const struct hid_usage_entry hid_usage_table[] = {
|
||||
{0, 0x03, "LightPen"},
|
||||
{0, 0x04, "TouchScreen"},
|
||||
{0, 0x05, "TouchPad"},
|
||||
{0, 0x0e, "DeviceConfiguration"},
|
||||
{0, 0x20, "Stylus"},
|
||||
{0, 0x21, "Puck"},
|
||||
{0, 0x22, "Finger"},
|
||||
{0, 0x23, "DeviceSettings"},
|
||||
{0, 0x30, "TipPressure"},
|
||||
{0, 0x31, "BarrelPressure"},
|
||||
{0, 0x32, "InRange"},
|
||||
|
@ -173,8 +173,10 @@
|
||||
#define USB_VENDOR_ID_ASUSTEK 0x0b05
|
||||
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
|
||||
#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
|
||||
#define USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD 0x8585
|
||||
#define USB_DEVICE_ID_ASUSTEK_TOUCHPAD 0x0101
|
||||
#define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585
|
||||
#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_DEVICE_ID_ATEN_UC100KM 0x2004
|
||||
@ -184,6 +186,7 @@
|
||||
#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
|
||||
#define USB_DEVICE_ID_ATEN_CS682 0x2213
|
||||
#define USB_DEVICE_ID_ATEN_CS692 0x8021
|
||||
#define USB_DEVICE_ID_ATEN_CS1758 0x2220
|
||||
|
||||
#define USB_VENDOR_ID_ATMEL 0x03eb
|
||||
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
|
||||
@ -366,6 +369,7 @@
|
||||
#define USB_VENDOR_ID_ELO 0x04E7
|
||||
#define USB_DEVICE_ID_ELO_TS2515 0x0022
|
||||
#define USB_DEVICE_ID_ELO_TS2700 0x0020
|
||||
#define USB_DEVICE_ID_ELO_ACCUTOUCH_2216 0x0050
|
||||
|
||||
#define USB_VENDOR_ID_EMS 0x2006
|
||||
#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
|
||||
@ -548,6 +552,9 @@
|
||||
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
|
||||
#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_DEVICE_ID_ITE_LENOVO_YOGA 0x8386
|
||||
#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350
|
||||
@ -771,6 +778,9 @@
|
||||
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
|
||||
#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_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
|
||||
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
|
||||
|
@ -1150,18 +1150,26 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
||||
|
||||
/*
|
||||
* 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
|
||||
* don't unintentionally discard values sent by devices which
|
||||
* don't specify logical min and max.
|
||||
*/
|
||||
if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
|
||||
(field->logical_minimum < field->logical_maximum) &&
|
||||
(value < field->logical_minimum ||
|
||||
value > field->logical_maximum)) {
|
||||
dbg_hid("Ignoring out-of-range value %x\n", value);
|
||||
return;
|
||||
(field->logical_minimum < field->logical_maximum)) {
|
||||
if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
|
||||
(value < field->logical_minimum ||
|
||||
value > field->logical_maximum)) {
|
||||
dbg_hid("Ignoring out-of-range value %x\n", value);
|
||||
return;
|
||||
}
|
||||
value = clamp(value,
|
||||
field->logical_minimum,
|
||||
field->logical_maximum);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -692,8 +692,12 @@ static void logi_dj_ll_close(struct hid_device *hid)
|
||||
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,
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
@ -712,9 +716,9 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
|
||||
|
||||
/* special case where we should not overwrite
|
||||
* the device_index */
|
||||
if (count == 7 && !memcmp(buf, unifying_name_query,
|
||||
sizeof(unifying_name_query)))
|
||||
buf[4] |= djdev->device_index - 1;
|
||||
if (count == 7 && !memcmp(buf, unifying_pairing_query,
|
||||
sizeof(unifying_pairing_query)))
|
||||
buf[4] = (buf[4] & 0xf0) | (djdev->device_index - 1);
|
||||
else
|
||||
buf[1] = djdev->device_index;
|
||||
return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
|
||||
@ -911,9 +915,8 @@ static int logi_dj_hidpp_event(struct hid_device *hdev,
|
||||
/* special case were the device wants to know its unifying
|
||||
* name */
|
||||
if (size == HIDPP_REPORT_LONG_LENGTH &&
|
||||
!memcmp(data, unifying_name_answer,
|
||||
sizeof(unifying_name_answer)) &&
|
||||
((data[4] & 0xF0) == 0x40))
|
||||
!memcmp(data, unifying_pairing_answer,
|
||||
sizeof(unifying_pairing_answer)))
|
||||
device_index = (data[4] & 0x0F) + 1;
|
||||
else
|
||||
return false;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
|
||||
#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
|
||||
#define MT_QUIRK_FORCE_GET_FEATURE (1 << 13)
|
||||
#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_TOUCHPAD 0x03
|
||||
@ -222,7 +223,8 @@ static struct mt_class mt_classes[] = {
|
||||
*/
|
||||
{ .name = MT_CLS_3M,
|
||||
.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_width = 128,
|
||||
.sn_height = 128,
|
||||
@ -658,9 +660,17 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
||||
if (active) {
|
||||
/* this finger is in proximity of the sensor */
|
||||
int wide = (s->w > s->h);
|
||||
/* divided by two to match visual scale of touch */
|
||||
int major = max(s->w, s->h) >> 1;
|
||||
int minor = min(s->w, s->h) >> 1;
|
||||
int major = max(s->w, s->h);
|
||||
int minor = min(s->w, s->h);
|
||||
|
||||
/*
|
||||
* 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_Y, s->y);
|
||||
|
59
drivers/hid/hid-nti.c
Normal file
59
drivers/hid/hid-nti.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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");
|
File diff suppressed because it is too large
Load Diff
@ -508,66 +508,6 @@ static int i2c_hid_get_report_length(struct hid_report *report)
|
||||
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
|
||||
*/
|
||||
@ -789,9 +729,6 @@ static int i2c_hid_start(struct hid_device *hid)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
|
||||
i2c_hid_init_reports(hid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -994,6 +931,11 @@ static int i2c_hid_of_probe(struct i2c_client *client,
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1053,6 +995,24 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
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);
|
||||
|
||||
ihid->client = client;
|
||||
@ -1068,7 +1028,7 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
* real computation later. */
|
||||
ret = i2c_hid_alloc_buffers(ihid, HID_MIN_BUFFER_SIZE);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto err_regulator;
|
||||
|
||||
pm_runtime_get_noresume(&client->dev);
|
||||
pm_runtime_set_active(&client->dev);
|
||||
@ -1125,6 +1085,9 @@ err_pm:
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
err_regulator:
|
||||
regulator_disable(ihid->pdata.supply);
|
||||
|
||||
err:
|
||||
i2c_hid_free_buffers(ihid);
|
||||
kfree(ihid);
|
||||
@ -1149,6 +1112,8 @@ static int i2c_hid_remove(struct i2c_client *client)
|
||||
if (ihid->bufsize)
|
||||
i2c_hid_free_buffers(ihid);
|
||||
|
||||
regulator_disable(ihid->pdata.supply);
|
||||
|
||||
kfree(ihid);
|
||||
|
||||
return 0;
|
||||
@ -1199,6 +1164,10 @@ static int i2c_hid_suspend(struct device *dev)
|
||||
else
|
||||
hid_warn(hid, "Failed to enable irq wake: %d\n",
|
||||
wake_status);
|
||||
} else {
|
||||
ret = regulator_disable(ihid->pdata.supply);
|
||||
if (ret < 0)
|
||||
hid_warn(hid, "Failed to disable supply: %d\n", ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1212,7 +1181,13 @@ static int i2c_hid_resume(struct device *dev)
|
||||
struct hid_device *hid = ihid->hid;
|
||||
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);
|
||||
if (!wake_status)
|
||||
ihid->irq_wake_enabled = false;
|
||||
|
@ -52,6 +52,10 @@ static unsigned int hid_mousepoll_interval;
|
||||
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
|
||||
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;
|
||||
module_param_named(ignoreled, ignoreled, uint, 0644);
|
||||
MODULE_PARM_DESC(ignoreled, "Autosuspend with active leds");
|
||||
@ -753,11 +757,9 @@ void usbhid_init_reports(struct hid_device *hid)
|
||||
struct hid_report_enum *report_enum;
|
||||
int err, ret;
|
||||
|
||||
if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
|
||||
report_enum = &hid->report_enum[HID_INPUT_REPORT];
|
||||
list_for_each_entry(report, &report_enum->report_list, list)
|
||||
usbhid_submit_report(hid, report, USB_DIR_IN);
|
||||
}
|
||||
report_enum = &hid->report_enum[HID_INPUT_REPORT];
|
||||
list_for_each_entry(report, &report_enum->report_list, list)
|
||||
usbhid_submit_report(hid, report, USB_DIR_IN);
|
||||
|
||||
report_enum = &hid->report_enum[HID_FEATURE_REPORT];
|
||||
list_for_each_entry(report, &report_enum->report_list, list)
|
||||
@ -1004,10 +1006,9 @@ static int usbhid_parse(struct hid_device *hid)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
|
||||
dbg_hid("couldn't allocate rdesc memory\n");
|
||||
rdesc = kmalloc(rsize, GFP_KERNEL);
|
||||
if (!rdesc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
|
||||
|
||||
@ -1077,13 +1078,21 @@ static int usbhid_start(struct hid_device *hid)
|
||||
if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
|
||||
dev->speed == USB_SPEED_HIGH) {
|
||||
interval = fls(endpoint->bInterval*8);
|
||||
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
|
||||
hid->name, endpoint->bInterval, interval);
|
||||
pr_info("%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
|
||||
hid->name, endpoint->bInterval, interval);
|
||||
}
|
||||
|
||||
/* Change the polling interval of mice. */
|
||||
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
|
||||
interval = hid_mousepoll_interval;
|
||||
/* Change the polling interval of mice and joysticks. */
|
||||
switch (hid->collection->usage) {
|
||||
case HID_GD_MOUSE:
|
||||
if (hid_mousepoll_interval > 0)
|
||||
interval = hid_mousepoll_interval;
|
||||
break;
|
||||
case HID_GD_JOYSTICK:
|
||||
if (hid_jspoll_interval > 0)
|
||||
interval = hid_jspoll_interval;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
if (usb_endpoint_dir_in(endpoint)) {
|
||||
@ -1120,9 +1129,6 @@ static int usbhid_start(struct hid_device *hid)
|
||||
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
|
||||
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);
|
||||
|
||||
if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
|
||||
@ -1456,10 +1462,9 @@ static int hid_post_reset(struct usb_interface *intf)
|
||||
* the size of the HID report descriptor has not changed.
|
||||
*/
|
||||
rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
|
||||
if (!rdesc) {
|
||||
dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
|
||||
if (!rdesc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
status = hid_get_class_descriptor(dev,
|
||||
interface->desc.bInterfaceNumber,
|
||||
HID_DT_REPORT, rdesc, hid->dev_rsize);
|
||||
@ -1637,7 +1642,7 @@ static int __init hid_init(void)
|
||||
retval = usb_register(&hid_driver);
|
||||
if (retval)
|
||||
goto usb_register_fail;
|
||||
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
|
||||
pr_info(KBUILD_MODNAME ": " DRIVER_DESC "\n");
|
||||
|
||||
return 0;
|
||||
usb_register_fail:
|
||||
|
@ -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_CS682, 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_COMBATSTICK, 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 {
|
||||
{ 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_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_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_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT },
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -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);
|
||||
if (!q_new) {
|
||||
dbg_hid("Could not allocate quirks_list_struct\n");
|
||||
if (!q_new)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
q_new->hid_bl_item.idVendor = idVendor;
|
||||
q_new->hid_bl_item.idProduct = idProduct;
|
||||
@ -309,10 +309,9 @@ int usbhid_quirks_init(char **quirks_param)
|
||||
&idVendor, &idProduct, &quirks);
|
||||
|
||||
if (m != 3 ||
|
||||
usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
|
||||
printk(KERN_WARNING
|
||||
"Could not parse HID quirk module param %s\n",
|
||||
quirks_param[n]);
|
||||
usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
|
||||
pr_warn("Could not parse HID quirk module param %s\n",
|
||||
quirks_param[n]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,16 +47,6 @@
|
||||
#endif
|
||||
#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_usage_ref buffer[HIDDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
@ -690,6 +680,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
|
||||
case HIDIOCINITREPORT:
|
||||
usbhid_init_reports(hid);
|
||||
hiddev->initialized = true;
|
||||
r = 0;
|
||||
break;
|
||||
|
||||
@ -791,6 +782,10 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
case HIDIOCGUSAGES:
|
||||
case HIDIOCSUSAGES:
|
||||
case HIDIOCGCOLLECTIONINDEX:
|
||||
if (!hiddev->initialized) {
|
||||
usbhid_init_reports(hid);
|
||||
hiddev->initialized = true;
|
||||
}
|
||||
r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
|
||||
break;
|
||||
|
||||
@ -911,6 +906,15 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
|
||||
kfree(hiddev);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,7 @@ enum wacom_worker {
|
||||
WACOM_WORKER_WIRELESS,
|
||||
WACOM_WORKER_BATTERY,
|
||||
WACOM_WORKER_REMOTE,
|
||||
WACOM_WORKER_MODE_CHANGE,
|
||||
};
|
||||
|
||||
struct wacom;
|
||||
@ -167,6 +168,7 @@ struct wacom {
|
||||
struct work_struct remote_work;
|
||||
struct delayed_work init_work;
|
||||
struct wacom_remote *remote;
|
||||
struct work_struct mode_change_work;
|
||||
bool generic_has_leds;
|
||||
struct wacom_leds {
|
||||
struct wacom_group_leds *groups;
|
||||
@ -196,6 +198,9 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac,
|
||||
case WACOM_WORKER_REMOTE:
|
||||
schedule_work(&wacom->remote_work);
|
||||
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,
|
||||
|
||||
if (features->type == HID_GENERIC) {
|
||||
/* 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->device_type & WACOM_DEVICETYPE_DIRECT)
|
||||
input_mt_init_slots(wacom_wac->touch_input,
|
||||
@ -2093,8 +2100,10 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
|
||||
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->is_touch_on = true;
|
||||
}
|
||||
|
||||
if (wacom_wac->shared->has_mute_touch_switch &&
|
||||
wacom_wac->shared->touch_input) {
|
||||
@ -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,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
@ -2534,6 +2583,7 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
|
||||
INIT_WORK(&wacom->battery_work, wacom_battery_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 */
|
||||
error = hid_parse(hdev);
|
||||
@ -2576,6 +2626,7 @@ static void wacom_remove(struct hid_device *hdev)
|
||||
cancel_work_sync(&wacom->wireless_work);
|
||||
cancel_work_sync(&wacom->battery_work);
|
||||
cancel_work_sync(&wacom->remote_work);
|
||||
cancel_work_sync(&wacom->mode_change_work);
|
||||
if (hdev->bus == BUS_BLUETOOTH)
|
||||
device_remove_file(&hdev->dev, &dev_attr_speed);
|
||||
|
||||
|
@ -773,131 +773,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
{
|
||||
unsigned char *data = wacom_wac->data;
|
||||
struct input_dev *input;
|
||||
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
|
||||
struct wacom_remote *remote = wacom->remote;
|
||||
int bat_charging, bat_percent, touch_ring_mode;
|
||||
__u32 serial;
|
||||
int i, index = -1;
|
||||
unsigned long flags;
|
||||
|
||||
if (data[0] != WACOM_REPORT_REMOTE) {
|
||||
hid_dbg(wacom->hdev, "%s: received unknown report #%d",
|
||||
__func__, data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
serial = data[3] + (data[4] << 8) + (data[5] << 16);
|
||||
wacom_wac->id[0] = PAD_DEVICE_ID;
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
if (remote->remotes[i].serial == serial) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0 || !remote->remotes[index].registered)
|
||||
goto out;
|
||||
|
||||
input = remote->remotes[index].input;
|
||||
|
||||
input_report_key(input, BTN_0, (data[9] & 0x01));
|
||||
input_report_key(input, BTN_1, (data[9] & 0x02));
|
||||
input_report_key(input, BTN_2, (data[9] & 0x04));
|
||||
input_report_key(input, BTN_3, (data[9] & 0x08));
|
||||
input_report_key(input, BTN_4, (data[9] & 0x10));
|
||||
input_report_key(input, BTN_5, (data[9] & 0x20));
|
||||
input_report_key(input, BTN_6, (data[9] & 0x40));
|
||||
input_report_key(input, BTN_7, (data[9] & 0x80));
|
||||
|
||||
input_report_key(input, BTN_8, (data[10] & 0x01));
|
||||
input_report_key(input, BTN_9, (data[10] & 0x02));
|
||||
input_report_key(input, BTN_A, (data[10] & 0x04));
|
||||
input_report_key(input, BTN_B, (data[10] & 0x08));
|
||||
input_report_key(input, BTN_C, (data[10] & 0x10));
|
||||
input_report_key(input, BTN_X, (data[10] & 0x20));
|
||||
input_report_key(input, BTN_Y, (data[10] & 0x40));
|
||||
input_report_key(input, BTN_Z, (data[10] & 0x80));
|
||||
|
||||
input_report_key(input, BTN_BASE, (data[11] & 0x01));
|
||||
input_report_key(input, BTN_BASE2, (data[11] & 0x02));
|
||||
|
||||
if (data[12] & 0x80)
|
||||
input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
|
||||
else
|
||||
input_report_abs(input, ABS_WHEEL, 0);
|
||||
|
||||
bat_percent = data[7] & 0x7f;
|
||||
bat_charging = !!(data[7] & 0x80);
|
||||
|
||||
if (data[9] | data[10] | (data[11] & 0x03) | data[12])
|
||||
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
|
||||
else
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
|
||||
input_event(input, EV_MSC, MSC_SERIAL, serial);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
/*Which mode select (LED light) is currently on?*/
|
||||
touch_ring_mode = (data[11] & 0xC0) >> 6;
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
if (remote->remotes[i].serial == serial)
|
||||
wacom->led.groups[i].select = touch_ring_mode;
|
||||
}
|
||||
|
||||
__wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
|
||||
bat_charging, 1, bat_charging);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
{
|
||||
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
|
||||
unsigned char *data = wacom_wac->data;
|
||||
struct wacom_remote *remote = wacom->remote;
|
||||
struct wacom_remote_data remote_data;
|
||||
unsigned long flags;
|
||||
int i, ret;
|
||||
|
||||
if (data[0] != WACOM_REPORT_DEVICE_LIST)
|
||||
return;
|
||||
|
||||
memset(&remote_data, 0, sizeof(struct wacom_remote_data));
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
int j = i * 6;
|
||||
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
|
||||
bool connected = data[j+2];
|
||||
|
||||
remote_data.remote[i].serial = serial;
|
||||
remote_data.remote[i].connected = connected;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
|
||||
ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
|
||||
if (ret != sizeof(remote_data)) {
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
hid_err(wacom->hdev, "Can't queue Remote status event.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
|
||||
wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
|
||||
}
|
||||
|
||||
static inline bool report_touch_events(struct wacom_wac *wacom)
|
||||
{
|
||||
return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
|
||||
@ -1116,6 +991,131 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
{
|
||||
unsigned char *data = wacom_wac->data;
|
||||
struct input_dev *input;
|
||||
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
|
||||
struct wacom_remote *remote = wacom->remote;
|
||||
int bat_charging, bat_percent, touch_ring_mode;
|
||||
__u32 serial;
|
||||
int i, index = -1;
|
||||
unsigned long flags;
|
||||
|
||||
if (data[0] != WACOM_REPORT_REMOTE) {
|
||||
hid_dbg(wacom->hdev, "%s: received unknown report #%d",
|
||||
__func__, data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
serial = data[3] + (data[4] << 8) + (data[5] << 16);
|
||||
wacom_wac->id[0] = PAD_DEVICE_ID;
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
if (remote->remotes[i].serial == serial) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < 0 || !remote->remotes[index].registered)
|
||||
goto out;
|
||||
|
||||
input = remote->remotes[index].input;
|
||||
|
||||
input_report_key(input, BTN_0, (data[9] & 0x01));
|
||||
input_report_key(input, BTN_1, (data[9] & 0x02));
|
||||
input_report_key(input, BTN_2, (data[9] & 0x04));
|
||||
input_report_key(input, BTN_3, (data[9] & 0x08));
|
||||
input_report_key(input, BTN_4, (data[9] & 0x10));
|
||||
input_report_key(input, BTN_5, (data[9] & 0x20));
|
||||
input_report_key(input, BTN_6, (data[9] & 0x40));
|
||||
input_report_key(input, BTN_7, (data[9] & 0x80));
|
||||
|
||||
input_report_key(input, BTN_8, (data[10] & 0x01));
|
||||
input_report_key(input, BTN_9, (data[10] & 0x02));
|
||||
input_report_key(input, BTN_A, (data[10] & 0x04));
|
||||
input_report_key(input, BTN_B, (data[10] & 0x08));
|
||||
input_report_key(input, BTN_C, (data[10] & 0x10));
|
||||
input_report_key(input, BTN_X, (data[10] & 0x20));
|
||||
input_report_key(input, BTN_Y, (data[10] & 0x40));
|
||||
input_report_key(input, BTN_Z, (data[10] & 0x80));
|
||||
|
||||
input_report_key(input, BTN_BASE, (data[11] & 0x01));
|
||||
input_report_key(input, BTN_BASE2, (data[11] & 0x02));
|
||||
|
||||
if (data[12] & 0x80)
|
||||
input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f));
|
||||
else
|
||||
input_report_abs(input, ABS_WHEEL, 0);
|
||||
|
||||
bat_percent = data[7] & 0x7f;
|
||||
bat_charging = !!(data[7] & 0x80);
|
||||
|
||||
if (data[9] | data[10] | (data[11] & 0x03) | data[12])
|
||||
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
|
||||
else
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
|
||||
input_event(input, EV_MSC, MSC_SERIAL, serial);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
/*Which mode select (LED light) is currently on?*/
|
||||
touch_ring_mode = (data[11] & 0xC0) >> 6;
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
if (remote->remotes[i].serial == serial)
|
||||
wacom->led.groups[i].select = touch_ring_mode;
|
||||
}
|
||||
|
||||
__wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
|
||||
bat_charging, 1, bat_charging);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
{
|
||||
struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
|
||||
unsigned char *data = wacom_wac->data;
|
||||
struct wacom_remote *remote = wacom->remote;
|
||||
struct wacom_remote_data remote_data;
|
||||
unsigned long flags;
|
||||
int i, ret;
|
||||
|
||||
if (data[0] != WACOM_REPORT_DEVICE_LIST)
|
||||
return;
|
||||
|
||||
memset(&remote_data, 0, sizeof(struct wacom_remote_data));
|
||||
|
||||
for (i = 0; i < WACOM_MAX_REMOTES; i++) {
|
||||
int j = i * 6;
|
||||
int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4];
|
||||
bool connected = data[j+2];
|
||||
|
||||
remote_data.remote[i].serial = serial;
|
||||
remote_data.remote[i].connected = connected;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&remote->remote_lock, flags);
|
||||
|
||||
ret = kfifo_in(&remote->remote_fifo, &remote_data, sizeof(remote_data));
|
||||
if (ret != sizeof(remote_data)) {
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
hid_err(wacom->hdev, "Can't queue Remote status event.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&remote->remote_lock, flags);
|
||||
|
||||
wacom_schedule_work(wacom_wac, WACOM_WORKER_REMOTE);
|
||||
}
|
||||
|
||||
static int int_dist(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int x = x2 - x1;
|
||||
@ -1739,6 +1739,7 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_TOUCHONOFF:
|
||||
case WACOM_HID_WD_MUTE_DEVICE:
|
||||
/*
|
||||
* This usage, which is used to mute touch events, comes
|
||||
* from the pad packet, but is reported on the touch
|
||||
@ -1768,6 +1769,26 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
|
||||
wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0);
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_BUTTONCONFIG:
|
||||
wacom_map_usage(input, usage, field, EV_KEY, KEY_BUTTONCONFIG, 0);
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_ONSCREEN_KEYBOARD:
|
||||
wacom_map_usage(input, usage, field, EV_KEY, KEY_ONSCREEN_KEYBOARD, 0);
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_CONTROLPANEL:
|
||||
wacom_map_usage(input, usage, field, EV_KEY, KEY_CONTROLPANEL, 0);
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_MODE_CHANGE:
|
||||
/* do not overwrite previous data */
|
||||
if (!wacom_wac->has_mode_change) {
|
||||
wacom_wac->has_mode_change = true;
|
||||
wacom_wac->is_direct_mode = true;
|
||||
}
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (equivalent_usage & 0xfffffff0) {
|
||||
@ -1811,12 +1832,13 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
||||
struct wacom_features *features = &wacom_wac->features;
|
||||
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
||||
int i;
|
||||
bool is_touch_on = value;
|
||||
|
||||
/*
|
||||
* Avoid reporting this event and setting inrange_state if this usage
|
||||
* hasn't been mapped.
|
||||
*/
|
||||
if (!usage->type)
|
||||
if (!usage->type && equivalent_usage != WACOM_HID_WD_MODE_CHANGE)
|
||||
return;
|
||||
|
||||
if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) {
|
||||
@ -1830,14 +1852,28 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
||||
input_event(input, usage->type, usage->code, 0);
|
||||
break;
|
||||
|
||||
case WACOM_HID_WD_MUTE_DEVICE:
|
||||
if (wacom_wac->shared->touch_input && value) {
|
||||
wacom_wac->shared->is_touch_on = !wacom_wac->shared->is_touch_on;
|
||||
is_touch_on = wacom_wac->shared->is_touch_on;
|
||||
}
|
||||
|
||||
/* fall through*/
|
||||
case WACOM_HID_WD_TOUCHONOFF:
|
||||
if (wacom_wac->shared->touch_input) {
|
||||
input_report_switch(wacom_wac->shared->touch_input,
|
||||
SW_MUTE_DEVICE, !value);
|
||||
SW_MUTE_DEVICE, !is_touch_on);
|
||||
input_sync(wacom_wac->shared->touch_input);
|
||||
}
|
||||
break;
|
||||
|
||||
case WACOM_HID_WD_MODE_CHANGE:
|
||||
if (wacom_wac->is_direct_mode != value) {
|
||||
wacom_wac->is_direct_mode = value;
|
||||
wacom_schedule_work(&wacom->wacom_wac, WACOM_WORKER_MODE_CHANGE);
|
||||
}
|
||||
break;
|
||||
|
||||
case WACOM_HID_WD_BUTTONCENTER:
|
||||
for (i = 0; i < wacom->led.count; i++)
|
||||
wacom_update_led(wacom, features->numbered_buttons,
|
||||
@ -1845,6 +1881,8 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
||||
/* fall through*/
|
||||
default:
|
||||
input_event(input, usage->type, usage->code, value);
|
||||
if (value)
|
||||
wacom_wac->hid_data.pad_input_event_flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1885,9 +1923,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
|
||||
bool active = wacom_wac->hid_data.inrange_state != 0;
|
||||
|
||||
/* report prox for expresskey events */
|
||||
if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) {
|
||||
if ((wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) &&
|
||||
wacom_wac->hid_data.pad_input_event_flag) {
|
||||
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
|
||||
input_sync(input);
|
||||
if (!active)
|
||||
wacom_wac->hid_data.pad_input_event_flag = false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -2197,6 +2238,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
||||
bool prox = hid_data->tipswitch &&
|
||||
report_touch_events(wacom_wac);
|
||||
|
||||
if (wacom_wac->shared->has_mute_touch_switch &&
|
||||
!wacom_wac->shared->is_touch_on) {
|
||||
if (!wacom_wac->shared->touch_down)
|
||||
return;
|
||||
prox = 0;
|
||||
}
|
||||
|
||||
wacom_wac->hid_data.num_received++;
|
||||
if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected)
|
||||
return;
|
||||
@ -4127,7 +4175,7 @@ static const struct wacom_features wacom_features_0x300 =
|
||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x301 =
|
||||
{ "Wacom Bamboo One M", 21648, 13530, 1023, 31,
|
||||
BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
BAMBOO_PEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x302 =
|
||||
{ "Wacom Intuos PT S", 15200, 9500, 1023, 31,
|
||||
INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .touch_max = 16,
|
||||
|
@ -120,6 +120,11 @@
|
||||
#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_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_BUTTONUP (WACOM_HID_UP_WACOMDIGITIZER | 0x0991)
|
||||
#define WACOM_HID_WD_BUTTONDOWN (WACOM_HID_UP_WACOMDIGITIZER | 0x0992)
|
||||
@ -270,6 +275,7 @@ struct wacom_shared {
|
||||
struct hid_device *pen;
|
||||
struct hid_device *touch;
|
||||
bool has_mute_touch_switch;
|
||||
bool is_touch_on;
|
||||
};
|
||||
|
||||
struct hid_data {
|
||||
@ -295,6 +301,7 @@ struct hid_data {
|
||||
int bat_charging;
|
||||
int bat_connected;
|
||||
int ps_connected;
|
||||
bool pad_input_event_flag;
|
||||
};
|
||||
|
||||
struct wacom_remote_data {
|
||||
@ -327,6 +334,9 @@ struct wacom_wac {
|
||||
int mode_value;
|
||||
struct hid_data hid_data;
|
||||
bool has_mute_touch_switch;
|
||||
bool has_mode_change;
|
||||
bool is_direct_mode;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -268,6 +268,8 @@ struct hid_item {
|
||||
#define HID_CP_APPLICATIONLAUNCHBUTTONS 0x000c0180
|
||||
#define HID_CP_GENERICGUIAPPLICATIONCONTROLS 0x000c0200
|
||||
|
||||
#define HID_DG_DEVICECONFIG 0x000d000e
|
||||
#define HID_DG_DEVICESETTINGS 0x000d0023
|
||||
#define HID_DG_CONFIDENCE 0x000d0047
|
||||
#define HID_DG_WIDTH 0x000d0048
|
||||
#define HID_DG_HEIGHT 0x000d0049
|
||||
@ -322,7 +324,7 @@ struct hid_item {
|
||||
#define HID_QUIRK_MULTI_INPUT 0x00000040
|
||||
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
|
||||
#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_SKIP_OUTPUT_REPORTS 0x00010000
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
|
||||
@ -541,7 +543,6 @@ struct hid_device { /* device report descriptor */
|
||||
struct list_head inputs; /* The list of inputs */
|
||||
void *hiddev; /* The hiddev structure */
|
||||
void *hidraw;
|
||||
int minor; /* Hiddev minor number */
|
||||
|
||||
int open; /* is the device open by anyone? */
|
||||
char name[128]; /* Device name */
|
||||
|
@ -32,6 +32,18 @@
|
||||
* 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_usage;
|
||||
struct hid_field;
|
||||
|
@ -14,9 +14,13 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct regulator;
|
||||
|
||||
/**
|
||||
* struct i2chid_platform_data - used by hid over i2c implementation.
|
||||
* @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
|
||||
* driver, or the flattened device tree) to setup the irq related to the gpio in
|
||||
@ -31,6 +35,8 @@
|
||||
*/
|
||||
struct i2c_hid_platform_data {
|
||||
u16 hid_descriptor_address;
|
||||
struct regulator *supply;
|
||||
int post_power_delay_ms;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_I2C_HID_H */
|
||||
|
@ -641,6 +641,7 @@
|
||||
* e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
|
||||
*/
|
||||
#define KEY_DATA 0x277
|
||||
#define KEY_ONSCREEN_KEYBOARD 0x278
|
||||
|
||||
#define BTN_TRIGGER_HAPPY 0x2c0
|
||||
#define BTN_TRIGGER_HAPPY1 0x2c0
|
||||
|
@ -61,9 +61,14 @@ struct input_id {
|
||||
* Note that input core does not clamp reported values to the
|
||||
* [minimum, maximum] limits, such task is left to userspace.
|
||||
*
|
||||
* Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
|
||||
* units per millimeter (units/mm), resolution for rotational axes
|
||||
* (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
|
||||
* The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
|
||||
* is reported in units per millimeter (units/mm), resolution
|
||||
* 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 {
|
||||
__s32 value;
|
||||
|
Loading…
Reference in New Issue
Block a user