mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112', 'for-4.12/hid-core-null-state-handling', 'for-4.12/hiddev', 'for-4.12/i2c-hid', 'for-4.12/innomedia', 'for-4.12/logitech-hidpp-battery-power-supply', 'for-4.12/multitouch', 'for-4.12/nti', 'for-4.12/upstream' and 'for-4.12/wacom' into for-linus
This commit is contained in:
parent
d529a4ad91
c846fe9ce9
ac34b970a9
c3883fe064
733aca9030
d3d9adfe30
9547837bdc
a4bf6153b3
e9d0a26d34
07e88a35dc
959d973e98
149f6f6b8f
commit
18fc2163b8
2444 changed files with 74682 additions and 35199 deletions
|
|
@ -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
|
||||
|
|
@ -215,7 +227,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 +454,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 +595,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 <[email protected]");
|
||||
MODULE_DESCRIPTION("Elo Accutouch HID TouchScreen driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -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);
|
||||
|
|
@ -1891,6 +1891,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 +1992,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"},
|
||||
|
|
|
|||
|
|
@ -367,6 +367,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
|
||||
|
|
@ -549,6 +550,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
|
||||
|
|
@ -772,6 +776,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 <[email protected]>");
|
||||
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");
|
||||
|
|
@ -108,13 +108,12 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
|
|||
struct rc_dev *rdev;
|
||||
int ret = 0;
|
||||
|
||||
rdev = rc_allocate_device();
|
||||
rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
|
||||
if (!rdev)
|
||||
return -ENOMEM;
|
||||
|
||||
rdev->priv = data;
|
||||
rdev->driver_type = RC_DRIVER_IR_RAW;
|
||||
rdev->allowed_protocols = RC_BIT_ALL;
|
||||
rdev->allowed_protocols = RC_BIT_ALL_IR_DECODER;
|
||||
rdev->open = picolcd_cir_open;
|
||||
rdev->close = picolcd_cir_close;
|
||||
rdev->input_name = data->hdev->name;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -162,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 }
|
||||
};
|
||||
|
|
@ -241,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;
|
||||
|
|
@ -310,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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,16 +46,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;
|
||||
|
|
@ -689,6 +679,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;
|
||||
|
||||
|
|
@ -790,6 +781,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;
|
||||
|
||||
|
|
@ -910,6 +905,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
|
||||
|
|
|
|||
Loading…
Reference in a new issue