Commit f39fdf2a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:

 - support for new Wacom "MobileStudio Pro" class of tablets from Jason
   Gerecke

 - Microsoft Surface 3 support from Benjamin Tissoires and Microsoft
   Surface 4 support from Daniel Keller

 - uDraw PS3 tablet support from Bastien Nocera

 - timeout scheduling fixes for intel-ish-hid from Even Xu

 - HID_QUIRK_MULTI_INPUT in order to simplify LED handling from Benjamin
   Tissoires

 - support for Sony DS4 dongle and various other fixes to Sony driver
   from Roderick Colenbrander

 - other assorted smaller fixes and device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (63 commits)
  HID: fix missing irq field
  HID: i2c-hid: fix build
  HID: i2c-hid: Disable IRQ before freeing buffers
  HID: usbhid: fix improper return value
  HID: wacom: generic: Don't sync input on empty input packets
  HID: wacom: generic: Pad supports more than buttons
  HID: wacom: generic: Send data only when the interface is defined
  HID: wacom: generic: Don't return a value for wacom_wac_event
  HID: intel_ish-hid: use %pUL for uuid formatting
  HID: cp2112: explicitly require irqchip support in gpiolib
  HID: asus: Add i2c touchpad support
  HID: intel-ish-hid: Fix potential race condition
  HID: sony: Support DS4 dongle
  HID: sony: Comply to Linux gamepad spec for DS4
  HID: sony: Make the DS4 touchpad a separate device
  HID: sony: Fix memory issue when connecting device using both Bluetooth and USB
  HID: cp2112: add IRQ chip handling
  HID: i2c-hid: force the IRQ level trigger only when not set
  HID: multitouch: do not retrieve all reports for all devices
  HID: multitouch: enable the Surface 3 Type Cover to report multitouch data
  ...
parents 775a2e29 96e132eb
...@@ -12488,6 +12488,12 @@ S: Maintained ...@@ -12488,6 +12488,12 @@ S: Maintained
F: Documentation/filesystems/udf.txt F: Documentation/filesystems/udf.txt
F: fs/udf/ F: fs/udf/
UDRAW TABLET
M: Bastien Nocera <hadess@hadess.net>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-udraw.c
UFS FILESYSTEM UFS FILESYSTEM
M: Evgeniy Dushistov <dushistov@mail.ru> M: Evgeniy Dushistov <dushistov@mail.ru>
S: Maintained S: Maintained
......
...@@ -138,7 +138,7 @@ config HID_ASUS ...@@ -138,7 +138,7 @@ config HID_ASUS
tristate "Asus" tristate "Asus"
depends on I2C_HID depends on I2C_HID
---help--- ---help---
Support for Asus notebook built-in keyboard via i2c. Support for Asus notebook built-in keyboard and touchpad via i2c.
Supported devices: Supported devices:
- EeeBook X205TA - EeeBook X205TA
...@@ -214,7 +214,7 @@ config HID_CMEDIA ...@@ -214,7 +214,7 @@ config HID_CMEDIA
config HID_CP2112 config HID_CP2112
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
depends on USB_HID && I2C && GPIOLIB depends on USB_HID && I2C && GPIOLIB && GPIOLIB_IRQCHIP
---help--- ---help---
Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
This is a HID device driver which registers as an i2c adapter This is a HID device driver which registers as an i2c adapter
...@@ -512,6 +512,14 @@ config HID_MAGICMOUSE ...@@ -512,6 +512,14 @@ config HID_MAGICMOUSE
Say Y here if you want support for the multi-touch features of the Say Y here if you want support for the multi-touch features of the
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
config HID_MAYFLASH
tristate "Mayflash game controller adapter force feedback"
depends on HID
select INPUT_FF_MEMLESS
---help---
Say Y here if you have HJZ Mayflash PS3 game controller adapters
and want to enable force feedback support.
config HID_MICROSOFT config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices" tristate "Microsoft non-fully HID-compliant devices"
depends on HID depends on HID
...@@ -861,6 +869,13 @@ config THRUSTMASTER_FF ...@@ -861,6 +869,13 @@ config THRUSTMASTER_FF
a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT
Rumble Force or Force Feedback Wheel. Rumble Force or Force Feedback Wheel.
config HID_UDRAW_PS3
tristate "THQ PS3 uDraw tablet"
depends on HID
---help---
Say Y here if you want to use the THQ uDraw gaming tablet for
the PS3.
config HID_WACOM config HID_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)" tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on HID depends on HID
......
...@@ -58,6 +58,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o ...@@ -58,6 +58,7 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
...@@ -96,6 +97,7 @@ obj-$(CONFIG_HID_TIVO) += hid-tivo.o ...@@ -96,6 +97,7 @@ obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
obj-$(CONFIG_HID_UDRAW_PS3) += hid-udraw-ps3.o
obj-$(CONFIG_HID_LED) += hid-led.o obj-$(CONFIG_HID_LED) += hid-led.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
......
...@@ -11,6 +11,12 @@ ...@@ -11,6 +11,12 @@
* This module based on hid-ortek by * This module based on hid-ortek by
* Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com> * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
* Copyright (c) 2011 Jiri Kosina * Copyright (c) 2011 Jiri Kosina
*
* This module has been updated to add support for Asus i2c touchpad.
*
* Copyright (c) 2016 Brendan McGrath <redmcg@redmandi.dyndns.org>
* Copyright (c) 2016 Victor Vlasenko <victor.vlasenko@sysgears.com>
* Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
*/ */
/* /*
...@@ -20,16 +26,287 @@ ...@@ -20,16 +26,287 @@
* any later version. * any later version.
*/ */
#include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/input/mt.h>
#include "hid-ids.h" #include "hid-ids.h"
MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>");
MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>");
MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
#define FEATURE_REPORT_ID 0x0d
#define INPUT_REPORT_ID 0x5d
#define INPUT_REPORT_SIZE 28
#define MAX_CONTACTS 5
#define MAX_X 2794
#define MAX_Y 1758
#define MAX_TOUCH_MAJOR 8
#define MAX_PRESSURE 128
#define CONTACT_DATA_SIZE 5
#define BTN_LEFT_MASK 0x01
#define CONTACT_TOOL_TYPE_MASK 0x80
#define CONTACT_X_MSB_MASK 0xf0
#define CONTACT_Y_MSB_MASK 0x0f
#define CONTACT_TOUCH_MAJOR_MASK 0x07
#define CONTACT_PRESSURE_MASK 0x7f
#define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
#define QUIRK_NO_INIT_REPORTS BIT(1)
#define QUIRK_SKIP_INPUT_MAPPING BIT(2)
#define QUIRK_IS_MULTITOUCH BIT(3)
#define NOTEBOOK_QUIRKS QUIRK_FIX_NOTEBOOK_REPORT
#define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
QUIRK_SKIP_INPUT_MAPPING | \
QUIRK_IS_MULTITOUCH)
#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
struct asus_drvdata {
unsigned long quirks;
struct input_dev *input;
};
static void asus_report_contact_down(struct input_dev *input,
int toolType, u8 *data)
{
int touch_major, pressure;
int x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1];
int y = MAX_Y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]);
if (toolType == MT_TOOL_PALM) {
touch_major = MAX_TOUCH_MAJOR;
pressure = MAX_PRESSURE;
} else {
touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK;
pressure = data[4] & CONTACT_PRESSURE_MASK;
}
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major);
input_report_abs(input, ABS_MT_PRESSURE, pressure);
}
/* Required for Synaptics Palm Detection */
static void asus_report_tool_width(struct input_dev *input)
{
struct input_mt *mt = input->mt;
struct input_mt_slot *oldest;
int oldid, count, i;
oldest = NULL;
oldid = mt->trkid;
count = 0;
for (i = 0; i < mt->num_slots; ++i) {
struct input_mt_slot *ps = &mt->slots[i];
int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
if (id < 0)
continue;
if ((id - oldid) & TRKID_SGN) {
oldest = ps;
oldid = id;
}
count++;
}
if (oldest) {
input_report_abs(input, ABS_TOOL_WIDTH,
input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR));
}
}
static void asus_report_input(struct input_dev *input, u8 *data)
{
int i;
u8 *contactData = data + 2;
for (i = 0; i < MAX_CONTACTS; i++) {
bool down = !!(data[1] & BIT(i+3));
int toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ?
MT_TOOL_PALM : MT_TOOL_FINGER;
input_mt_slot(input, i);
input_mt_report_slot_state(input, toolType, down);
if (down) {
asus_report_contact_down(input, toolType, contactData);
contactData += CONTACT_DATA_SIZE;
}
}
input_report_key(input, BTN_LEFT, data[1] & BTN_LEFT_MASK);
asus_report_tool_width(input);
input_mt_sync_frame(input);
input_sync(input);
}
static int asus_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & QUIRK_IS_MULTITOUCH &&
data[0] == INPUT_REPORT_ID &&
size == INPUT_REPORT_SIZE) {
asus_report_input(drvdata->input, data);
return 1;
}
return 0;
}
static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & QUIRK_IS_MULTITOUCH) {
int ret;
struct input_dev *input = hi->input;
input_set_abs_params(input, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);
input_set_abs_params(input, ABS_TOOL_WIDTH, 0, MAX_TOUCH_MAJOR, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0);
input_set_abs_params(input, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 0, 0);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
ret = input_mt_init_slots(input, MAX_CONTACTS, INPUT_MT_POINTER);
if (ret) {
hid_err(hdev, "Asus input mt init slots failed: %d\n", ret);
return ret;
}
drvdata->input = input;
}
return 0;
}
static int asus_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit,
int *max)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & QUIRK_SKIP_INPUT_MAPPING) {
/* Don't map anything from the HID report.
* We do it all manually in asus_input_configured
*/
return -1;
}
return 0;
}
static int asus_start_multitouch(struct hid_device *hdev)
{
int ret;
const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 };
unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
if (!dmabuf) {
ret = -ENOMEM;
hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret);
return ret;
}
ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
kfree(dmabuf);
if (ret != sizeof(buf)) {
hid_err(hdev, "Asus failed to start multitouch: %d\n", ret);
return ret;
}
return 0;
}
static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
{
struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
return asus_start_multitouch(hdev);
return 0;
}
static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct asus_drvdata *drvdata;
drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (drvdata == NULL) {
hid_err(hdev, "Can't alloc Asus descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, drvdata);
drvdata->quirks = id->driver_data;
if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "Asus hid parse failed: %d\n", ret);
return ret;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "Asus hw start failed: %d\n", ret);
return ret;
}
if (!drvdata->input) {
hid_err(hdev, "Asus input not registered\n");
ret = -ENOMEM;
goto err_stop_hw;
}
drvdata->input->name = "Asus TouchPad";
if (drvdata->quirks & QUIRK_IS_MULTITOUCH) {
ret = asus_start_multitouch(hdev);
if (ret)
goto err_stop_hw;
}
return 0;
err_stop_hw:
hid_hw_stop(hdev);
return ret;
}
static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) { struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
if (drvdata->quirks & QUIRK_FIX_NOTEBOOK_REPORT &&
*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) {
hid_info(hdev, "Fixing up Asus notebook report descriptor\n"); hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
rdesc[55] = 0xdd; rdesc[55] = 0xdd;
} }
...@@ -37,15 +314,25 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -37,15 +314,25 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
} }
static const struct hid_device_id asus_devices[] = { static const struct hid_device_id asus_devices[] = {
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD), NOTEBOOK_QUIRKS},
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_TOUCHPAD), TOUCHPAD_QUIRKS },
{ } { }
}; };
MODULE_DEVICE_TABLE(hid, asus_devices); MODULE_DEVICE_TABLE(hid, asus_devices);
static struct hid_driver asus_driver = { static struct hid_driver asus_driver = {
.name = "asus", .name = "asus",
.id_table = asus_devices, .id_table = asus_devices,
.report_fixup = asus_report_fixup .report_fixup = asus_report_fixup,
.probe = asus_probe,
.input_mapping = asus_input_mapping,
.input_configured = asus_input_configured,
#ifdef CONFIG_PM
.reset_resume = asus_reset_resume,
#endif
.raw_event = asus_raw_event
}; };
module_hid_driver(asus_driver); module_hid_driver(asus_driver);
......
...@@ -727,8 +727,9 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) ...@@ -727,8 +727,9 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
(hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 || hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP || hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->product == USB_DEVICE_ID_MS_POWER_COVER) &&
hid->group == HID_GROUP_MULTITOUCH) hid->group == HID_GROUP_MULTITOUCH)
hid->group = HID_GROUP_GENERIC; hid->group = HID_GROUP_GENERIC;
...@@ -1857,6 +1858,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1857,6 +1858,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_TOUCHPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
...@@ -1883,6 +1885,9 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1883,6 +1885,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
#if IS_ENABLED(CONFIG_HID_MAYFLASH)
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3) },
#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
...@@ -1983,8 +1988,9 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1983,8 +1988,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
...@@ -2059,6 +2065,9 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -2059,6 +2065,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) },
...@@ -2086,6 +2095,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -2086,6 +2095,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf
*/ */
#include <linux/gpio.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -168,6 +169,12 @@ struct cp2112_device { ...@@ -168,6 +169,12 @@ struct cp2112_device {
struct gpio_chip gc; struct gpio_chip gc;
u8 *in_out_buffer; u8 *in_out_buffer;
spinlock_t lock; spinlock_t lock;
struct gpio_desc *desc[8];
bool gpio_poll;
struct delayed_work gpio_poll_worker;
unsigned long irq_mask;
u8 gpio_prev_state;
}; };
static int gpio_push_pull = 0xFF; static int gpio_push_pull = 0xFF;
...@@ -233,7 +240,7 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -233,7 +240,7 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
} }
static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) static int cp2112_gpio_get_all(struct gpio_chip *chip)
{ {
struct cp2112_device *dev = gpiochip_get_data(chip); struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev; struct hid_device *hdev = dev->hdev;
...@@ -252,7 +259,7 @@ static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -252,7 +259,7 @@ static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
goto exit; goto exit;
} }
ret = (buf[1] >> offset) & 1; ret = buf[1];
exit: exit:
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -260,6 +267,17 @@ static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset) ...@@ -260,6 +267,17 @@ static int cp2112_gpio_get(struct gpio_chip *chip, unsigned offset)
return ret; return ret;
} }
static int cp2112_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
int ret;
ret = cp2112_gpio_get_all(chip);
if (ret < 0)
return ret;
return (ret >> offset) & 1;
}
static int cp2112_gpio_direction_output(struct gpio_chip *chip, static int cp2112_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value) unsigned offset, int value)
{ {
...@@ -1041,6 +1059,166 @@ static void chmod_sysfs_attrs(struct hid_device *hdev) ...@@ -1041,6 +1059,166 @@ static void chmod_sysfs_attrs(struct hid_device *hdev)
} }
} }
static void cp2112_gpio_irq_ack(struct irq_data *d)
{
}
static void cp2112_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc);
__clear_bit(d->hwirq, &dev->irq_mask);
}
static void cp2112_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc);
__set_bit(d->hwirq, &dev->irq_mask);
}
static void cp2112_gpio_poll_callback(struct work_struct *work)
{
struct cp2112_device *dev = container_of(work, struct cp2112_device,
gpio_poll_worker.work);
struct irq_data *d;
u8 gpio_mask;
u8 virqs = (u8)dev->irq_mask;
u32 irq_type;
int irq, virq, ret;
ret = cp2112_gpio_get_all(&dev->gc);
if (ret == -ENODEV) /* the hardware has been disconnected */
return;
if (ret < 0)
goto exit;
gpio_mask = ret;
while (virqs) {
virq = ffs(virqs) - 1;
virqs &= ~BIT(virq);
if (!dev->gc.to_irq)
break;
irq = dev->gc.to_irq(&dev->gc, virq);
d = irq_get_irq_data(irq);
if (!d)
continue;
irq_type = irqd_get_trigger_type(d);
if (gpio_mask & BIT(virq)) {
/* Level High */
if (irq_type & IRQ_TYPE_LEVEL_HIGH)
handle_nested_irq(irq);
if ((irq_type & IRQ_TYPE_EDGE_RISING) &&
!(dev->gpio_prev_state & BIT(virq)))
handle_nested_irq(irq);
} else {
/* Level Low */
if (irq_type & IRQ_TYPE_LEVEL_LOW)
handle_nested_irq(irq);
if ((irq_type & IRQ_TYPE_EDGE_FALLING) &&
(dev->gpio_prev_state & BIT(virq)))
handle_nested_irq(irq);
}
}
dev->gpio_prev_state = gpio_mask;
exit:
if (dev->gpio_poll)
schedule_delayed_work(&dev->gpio_poll_worker, 10);
}
static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc);
INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
cp2112_gpio_direction_input(gc, d->hwirq);
if (!dev->gpio_poll) {
dev->gpio_poll = true;
schedule_delayed_work(&dev->gpio_poll_worker, 0);
}
cp2112_gpio_irq_unmask(d);
return 0;
}
static void cp2112_gpio_irq_shutdown(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc);
cancel_delayed_work_sync(&dev->gpio_poll_worker);
}
static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
{
return 0;
}
static struct irq_chip cp2112_gpio_irqchip = {
.name = "cp2112-gpio",
.irq_startup = cp2112_gpio_irq_startup,
.irq_shutdown = cp2112_gpio_irq_shutdown,
.irq_ack = cp2112_gpio_irq_ack,
.irq_mask = cp2112_gpio_irq_mask,
.irq_unmask = cp2112_gpio_irq_unmask,
.irq_set_type = cp2112_gpio_irq_type,
};
static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
int pin)
{
int ret;
if (dev->desc[pin])
return -EINVAL;
dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
"HID/I2C:Event");
if (IS_ERR(dev->desc[pin])) {
dev_err(dev->gc.parent, "Failed to request GPIO\n");
return PTR_ERR(dev->desc[pin]);
}
ret = gpiochip_lock_as_irq(&dev->gc, pin);
if (ret) {
dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
goto err_desc;
}
ret = gpiod_to_irq(dev->desc[pin]);
if (ret < 0) {
dev_err(dev->gc.parent, "Failed to translate GPIO to IRQ\n");
goto err_lock;
}
return ret;
err_lock:
gpiochip_unlock_as_irq(&dev->gc, pin);
err_desc:
gpiochip_free_own_desc(dev->desc[pin]);
dev->desc[pin] = NULL;
return ret;
}
static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
struct cp2112_device *dev; struct cp2112_device *dev;
...@@ -1163,8 +1341,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1163,8 +1341,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
chmod_sysfs_attrs(hdev); chmod_sysfs_attrs(hdev);
hid_hw_power(hdev, PM_HINT_NORMAL); hid_hw_power(hdev, PM_HINT_NORMAL);
ret = gpiochip_irqchip_add(&dev->gc, &cp2112_gpio_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev->gc.parent, "failed to add IRQ chip\n");
goto err_sysfs_remove;
}
return ret; return ret;
err_sysfs_remove:
sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
err_gpiochip_remove: err_gpiochip_remove:
gpiochip_remove(&dev->gc); gpiochip_remove(&dev->gc);
err_free_i2c: err_free_i2c:
...@@ -1181,10 +1368,22 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1181,10 +1368,22 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
static void cp2112_remove(struct hid_device *hdev) static void cp2112_remove(struct hid_device *hdev)
{ {
struct cp2112_device *dev = hid_get_drvdata(hdev); struct cp2112_device *dev = hid_get_drvdata(hdev);
int i;
sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group); sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
gpiochip_remove(&dev->gc);
i2c_del_adapter(&dev->adap); i2c_del_adapter(&dev->adap);
if (dev->gpio_poll) {
dev->gpio_poll = false;
cancel_delayed_work_sync(&dev->gpio_poll_worker);
}
for (i = 0; i < ARRAY_SIZE(dev->desc); i++) {
gpiochip_unlock_as_irq(&dev->gc, i);
gpiochip_free_own_desc(dev->desc[i]);
}
gpiochip_remove(&dev->gc);
/* i2c_del_adapter has finished removing all i2c devices from our /* i2c_del_adapter has finished removing all i2c devices from our
* adapter. Well behaved devices should no longer call our cp2112_xfer * adapter. Well behaved devices should no longer call our cp2112_xfer
* and should have waited for any pending calls to finish. It has also * and should have waited for any pending calls to finish. It has also
......
...@@ -171,6 +171,7 @@ ...@@ -171,6 +171,7 @@
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b #define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
#define USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD 0x8585 #define USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD 0x8585
#define USB_DEVICE_ID_ASUSTEK_TOUCHPAD 0x0101
#define USB_VENDOR_ID_ATEN 0x0557 #define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004
...@@ -315,8 +316,10 @@ ...@@ -315,8 +316,10 @@
#define USB_VENDOR_ID_DMI 0x0c0b #define USB_VENDOR_ID_DMI 0x0c0b
#define USB_DEVICE_ID_DMI_ENC 0x5fab #define USB_DEVICE_ID_DMI_ENC 0x5fab
#define USB_VENDOR_ID_DRAGONRISE 0x0079 #define USB_VENDOR_ID_DRAGONRISE 0x0079
#define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800 #define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800
#define USB_DEVICE_ID_DRAGONRISE_PS3 0x1801
#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE 0x1843
#define USB_VENDOR_ID_DWAV 0x0eef #define USB_VENDOR_ID_DWAV 0x0eef
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
...@@ -718,8 +721,9 @@ ...@@ -718,8 +721,9 @@
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e4
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 0x07e8
#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9 #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de
#define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_DEVICE_ID_MS_POWER_COVER 0x07da
#define USB_VENDOR_ID_MOJO 0x8282 #define USB_VENDOR_ID_MOJO 0x8282
...@@ -903,6 +907,8 @@ ...@@ -903,6 +907,8 @@
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0
#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 #define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
...@@ -959,6 +965,9 @@ ...@@ -959,6 +965,9 @@
#define USB_VENDOR_ID_THINGM 0x27b8 #define USB_VENDOR_ID_THINGM 0x27b8
#define USB_DEVICE_ID_BLINK1 0x01ed #define USB_DEVICE_ID_BLINK1 0x01ed
#define USB_VENDOR_ID_THQ 0x20d6
#define USB_DEVICE_ID_THQ_PS3_UDRAW 0xcb17
#define USB_VENDOR_ID_THRUSTMASTER 0x044f #define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TIVO 0x150a #define USB_VENDOR_ID_TIVO 0x150a
...@@ -1034,6 +1043,10 @@ ...@@ -1034,6 +1043,10 @@
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 #define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
#define USB_VENDOR_ID_WEIDA 0x2575
#define USB_DEVICE_ID_WEIDA_8752 0xC300
#define USB_DEVICE_ID_WEIDA_8755 0xC301
#define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888
......
...@@ -253,6 +253,7 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) ...@@ -253,6 +253,7 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
case ABS_RX: case ABS_RX:
case ABS_RY: case ABS_RY:
case ABS_RZ: case ABS_RZ:
case ABS_WHEEL:
case ABS_TILT_X: case ABS_TILT_X:
case ABS_TILT_Y: case ABS_TILT_Y:
if (field->unit == 0x14) { /* If degrees */ if (field->unit == 0x14) { /* If degrees */
...@@ -1468,6 +1469,31 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid, ...@@ -1468,6 +1469,31 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
kfree(hidinput); kfree(hidinput);
} }
static struct hid_input *hidinput_match(struct hid_report *report)
{
struct hid_device *hid = report->device;
struct hid_input *hidinput;
list_for_each_entry(hidinput, &hid->inputs, list) {
if (hidinput->report &&
hidinput->report->id == report->id)
return hidinput;
}
return NULL;
}
static inline void hidinput_configure_usages(struct hid_input *hidinput,
struct hid_report *report)
{
int i, j;
for (i = 0; i < report->maxfield; i++)
for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
}
/* /*
* Register the input device; print a message. * Register the input device; print a message.
* Configure the input layer interface * Configure the input layer interface
...@@ -1478,8 +1504,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1478,8 +1504,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
{ {
struct hid_driver *drv = hid->driver; struct hid_driver *drv = hid->driver;
struct hid_report *report; struct hid_report *report;
struct hid_input *hidinput = NULL; struct hid_input *next, *hidinput = NULL;
int i, j, k; int i, k;
INIT_LIST_HEAD(&hid->inputs); INIT_LIST_HEAD(&hid->inputs);
INIT_WORK(&hid->led_work, hidinput_led_worker); INIT_WORK(&hid->led_work, hidinput_led_worker);
...@@ -1509,43 +1535,40 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1509,43 +1535,40 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (!report->maxfield) if (!report->maxfield)
continue; continue;
/*
* Find the previous hidinput report attached
* to this report id.
*/
if (hid->quirks & HID_QUIRK_MULTI_INPUT)
hidinput = hidinput_match(report);
if (!hidinput) { if (!hidinput) {
hidinput = hidinput_allocate(hid); hidinput = hidinput_allocate(hid);
if (!hidinput) if (!hidinput)
goto out_unwind; goto out_unwind;
} }
for (i = 0; i < report->maxfield; i++) hidinput_configure_usages(hidinput, report);
for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
!hidinput_has_been_populated(hidinput))
continue;
if (hid->quirks & HID_QUIRK_MULTI_INPUT) { if (hid->quirks & HID_QUIRK_MULTI_INPUT)
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
* the same interface. Some devices (e.g. Happ's
* UGCI) cram a lot of unrelated inputs into the
* same interface. */
hidinput->report = report; hidinput->report = report;
if (drv->input_configured &&
drv->input_configured(hid, hidinput))
goto out_cleanup;
if (input_register_device(hidinput->input))
goto out_cleanup;
hidinput = NULL;
}
} }
} }
if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
!hidinput_has_been_populated(hidinput)) { if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
/* no need to register an input device not populated */ !hidinput_has_been_populated(hidinput)) {
hidinput_cleanup_hidinput(hid, hidinput); /* no need to register an input device not populated */
hidinput = NULL; hidinput_cleanup_hidinput(hid, hidinput);
continue;
}
if (drv->input_configured &&
drv->input_configured(hid, hidinput))
goto out_unwind;
if (input_register_device(hidinput->input))
goto out_unwind;
hidinput->registered = true;
} }
if (list_empty(&hid->inputs)) { if (list_empty(&hid->inputs)) {
...@@ -1553,20 +1576,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) ...@@ -1553,20 +1576,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
goto out_unwind; goto out_unwind;
} }
if (hidinput) {
if (drv->input_configured &&
drv->input_configured(hid, hidinput))
goto out_cleanup;
if (input_register_device(hidinput->input))
goto out_cleanup;
}
return 0; return 0;
out_cleanup:
list_del(&hidinput->list);
input_free_device(hidinput->input);
kfree(hidinput);
out_unwind: out_unwind:
/* unwind the ones we already registered */ /* unwind the ones we already registered */
hidinput_disconnect(hid); hidinput_disconnect(hid);
...@@ -1583,7 +1594,10 @@ void hidinput_disconnect(struct hid_device *hid) ...@@ -1583,7 +1594,10 @@ void hidinput_disconnect(struct hid_device *hid)
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
list_del(&hidinput->list); list_del(&hidinput->list);
input_unregister_device(hidinput->input); if (hidinput->registered)
input_unregister_device(hidinput->input);
else
input_free_device(hidinput->input);
kfree(hidinput); kfree(hidinput);
} }
......
/*
* Force feedback support for Mayflash game controller adapters.
*
* These devices are manufactured by Mayflash but identify themselves
* using the vendor ID of DragonRise Inc.
*
* Tested with:
* 0079:1801 "DragonRise Inc. Mayflash PS3 Game Controller Adapter"
*
* The following adapters probably work too, but need to be tested:
* 0079:1800 "DragonRise Inc. Mayflash WIIU Game Controller Adapter"
* 0079:1843 "DragonRise Inc. Mayflash GameCube Game Controller Adapter"
*
* Copyright (c) 2016 Marcel Hasler <mahasler@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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
struct mf_device {
struct hid_report *report;
};
static int mf_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct mf_device *mf = data;
int strong, weak;
strong = effect->u.rumble.strong_magnitude;
weak = effect->u.rumble.weak_magnitude;
dbg_hid("Called with 0x%04x 0x%04x.\n", strong, weak);
strong = strong * 0xff / 0xffff;
weak = weak * 0xff / 0xffff;
dbg_hid("Running with 0x%02x 0x%02x.\n", strong, weak);
mf->report->field[0]->value[0] = weak;
mf->report->field[0]->value[1] = strong;
hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT);
return 0;
}
static int mf_init(struct hid_device *hid)
{
struct mf_device *mf;
struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct list_head *report_ptr;
struct hid_report *report;
struct list_head *input_ptr = &hid->inputs;
struct hid_input *input;
struct input_dev *dev;
int error;
/* Setup each of the four inputs */
list_for_each(report_ptr, report_list) {
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1 || report->field[0]->report_count < 2) {
hid_err(hid, "Invalid report, this should never happen!\n");
return -ENODEV;
}
if (list_is_last(input_ptr, &hid->inputs)) {
hid_err(hid, "Missing input, this should never happen!\n");
return -ENODEV;
}
input_ptr = input_ptr->next;
input = list_entry(input_ptr, struct hid_input, list);
mf = kzalloc(sizeof(struct mf_device), GFP_KERNEL);
if (!mf)
return -ENOMEM;
dev = input->input;
set_bit(FF_RUMBLE, dev->ffbit);
error = input_ff_create_memless(dev, mf, mf_play);
if (error) {
kfree(mf);
return error;
}
mf->report = report;
mf->report->field[0]->value[0] = 0x00;
mf->report->field[0]->value[1] = 0x00;
hid_hw_request(hid, mf->report, HID_REQ_SET_REPORT);
}
hid_info(hid, "Force feedback for HJZ Mayflash game controller "
"adapters by Marcel Hasler <mahasler@gmail.com>\n");
return 0;
}
static int mf_probe(struct hid_device *hid, const struct hid_device_id *id)
{
int error;
dev_dbg(&hid->dev, "Mayflash HID hardware probe...\n");
/* Split device into four inputs */
hid->quirks |= HID_QUIRK_MULTI_INPUT;
error = hid_parse(hid);
if (error) {
hid_err(hid, "HID parse failed.\n");
return error;
}
error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (error) {
hid_err(hid, "HID hw start failed\n");
return error;
}
error = mf_init(hid);
if (error) {
hid_err(hid, "Force feedback init failed.\n");
hid_hw_stop(hid);
return error;
}
return 0;
}
static const struct hid_device_id mf_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), },
{ }
};
MODULE_DEVICE_TABLE(hid, mf_devices);
static struct hid_driver mf_driver = {
.name = "hid_mf",
.id_table = mf_devices,
.probe = mf_probe,
};
module_hid_driver(mf_driver);
MODULE_LICENSE("GPL");
...@@ -280,9 +280,11 @@ static const struct hid_device_id ms_devices[] = { ...@@ -280,9 +280,11 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4),
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
......
...@@ -108,6 +108,7 @@ struct mt_device { ...@@ -108,6 +108,7 @@ struct mt_device {
int cc_value_index; /* contact count value index in the field */ int cc_value_index; /* contact count value index in the field */
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */ unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned long initial_quirks; /* initial quirks state */
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 inputmode_index; /* InputMode HID feature index in the report */
__s16 maxcontact_report_id; /* Maximum Contact Number HID feature, __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
...@@ -318,13 +319,10 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) ...@@ -318,13 +319,10 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
u8 *buf; u8 *buf;
/* /*
* Only fetch the feature report if initial reports are not already * Do not fetch the feature report if the device has been explicitly
* been retrieved. Currently this is only done for Windows 8 touch * marked as non-capable.
* devices.
*/ */
if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS)) if (td->initial_quirks & HID_QUIRK_NO_INIT_REPORTS)
return;
if (td->mtclass.name != MT_CLS_WIN_8)
return; return;
buf = hid_alloc_report_buf(report, GFP_KERNEL); buf = hid_alloc_report_buf(report, GFP_KERNEL);
...@@ -567,6 +565,14 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -567,6 +565,14 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_BUTTON: case HID_UP_BUTTON:
code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE); code = BTN_MOUSE + ((usage->hid - 1) & HID_USAGE);
/*
* MS PTP spec says that external buttons left and right have
* usages 2 and 3.
*/
if (cls->name == MT_CLS_WIN_8 &&
field->application == HID_DG_TOUCHPAD &&
(usage->hid & HID_USAGE) > 1)
code--;
hid_map_usage(hi, usage, bit, max, EV_KEY, code); hid_map_usage(hi, usage, bit, max, EV_KEY, code);
input_set_capability(hi->input, EV_KEY, code); input_set_capability(hi->input, EV_KEY, code);
return 1; return 1;
...@@ -842,7 +848,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -842,7 +848,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (!td->mtclass.export_all_inputs && if (!td->mtclass.export_all_inputs &&
field->application != HID_DG_TOUCHSCREEN && field->application != HID_DG_TOUCHSCREEN &&
field->application != HID_DG_PEN && field->application != HID_DG_PEN &&
field->application != HID_DG_TOUCHPAD) field->application != HID_DG_TOUCHPAD &&
field->application != HID_GD_KEYBOARD &&
field->application != HID_CP_CONSUMER_CONTROL)
return -1; return -1;
/* /*
...@@ -1083,36 +1091,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1083,36 +1091,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
} }
/* This allows the driver to correctly support devices
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
/*
* This allows the driver to handle different input sensors
* that emits events through different reports on the same HID
* device.
*/
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
/*
* Handle special quirks for Windows 8 certified devices.
*/
if (id->group == HID_GROUP_MULTITOUCH_WIN_8)
/*
* Some multitouch screens do not like to be polled for input
* reports. Fortunately, the Win8 spec says that all touches
* should be sent during each report, making the initialization
* of input reports unnecessary.
*
* In addition some touchpads do not behave well if we read
* all feature reports from them. Instead we prevent
* initial report fetching and then selectively fetch each
* report we are interested in.
*/
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
if (!td) { if (!td) {
dev_err(&hdev->dev, "cannot allocate multitouch data\n"); dev_err(&hdev->dev, "cannot allocate multitouch data\n");
...@@ -1136,6 +1114,39 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1136,6 +1114,39 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true; td->serial_maybe = true;
/*
* Store the initial quirk state
*/
td->initial_quirks = hdev->quirks;
/* This allows the driver to correctly support devices
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
/*
* This allows the driver to handle different input sensors
* that emits events through different reports on the same HID
* device.
*/
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
/*
* Some multitouch screens do not like to be polled for input
* reports. Fortunately, the Win8 spec says that all touches
* should be sent during each report, making the initialization
* of input reports unnecessary. For Win7 devices, well, let's hope
* they will still be happy (this is only be a problem if a touch
* was already there while probing the device).
*
* In addition some touchpads do not behave well if we read
* all feature reports from them. Instead we prevent
* initial report fetching and then selectively fetch each
* report we are interested in.
*/
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret != 0) if (ret != 0)
return ret; return ret;
...@@ -1204,8 +1215,11 @@ static int mt_resume(struct hid_device *hdev) ...@@ -1204,8 +1215,11 @@ static int mt_resume(struct hid_device *hdev)
static void mt_remove(struct hid_device *hdev) static void mt_remove(struct hid_device *hdev)
{ {
struct mt_device *td = hid_get_drvdata(hdev);
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
hid_hw_stop(hdev); hid_hw_stop(hdev);
hdev->quirks = td->initial_quirks;
} }
/* /*
......
...@@ -795,6 +795,12 @@ static const struct hid_device_id sensor_hub_devices[] = { ...@@ -795,6 +795,12 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
USB_DEVICE_ID_MS_TYPE_COVER_2), USB_DEVICE_ID_MS_TYPE_COVER_2),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
0x07bd), /* Microsoft Surface 3 */
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROCHIP,
0x0f01), /* MM7150 */
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
USB_DEVICE_ID_STM_HID_SENSOR), USB_DEVICE_ID_STM_HID_SENSOR),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
......
This diff is collapsed.
This diff is collapsed.
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm.h> #include <linux/pm.h>
...@@ -37,10 +38,15 @@ ...@@ -37,10 +38,15 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/i2c/i2c-hid.h> #include <linux/i2c/i2c-hid.h>
#include "../hid-ids.h"
/* quirks to control the device */
#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
/* flags */ /* flags */
#define I2C_HID_STARTED 0 #define I2C_HID_STARTED 0
#define I2C_HID_RESET_PENDING 1 #define I2C_HID_RESET_PENDING 1
...@@ -143,10 +149,9 @@ struct i2c_hid { ...@@ -143,10 +149,9 @@ struct i2c_hid {
char *argsbuf; /* Command arguments buffer */ char *argsbuf; /* Command arguments buffer */
unsigned long flags; /* device flags */ unsigned long flags; /* device flags */
unsigned long quirks; /* Various quirks */
wait_queue_head_t wait; /* For waiting the interrupt */ wait_queue_head_t wait; /* For waiting the interrupt */
struct gpio_desc *desc;
int irq;
struct i2c_hid_platform_data pdata; struct i2c_hid_platform_data pdata;
...@@ -154,6 +159,39 @@ struct i2c_hid { ...@@ -154,6 +159,39 @@ struct i2c_hid {
struct mutex reset_lock; struct mutex reset_lock;
}; };
static const struct i2c_hid_quirks {
__u16 idVendor;
__u16 idProduct;
__u32 quirks;
} i2c_hid_quirks[] = {
{ USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ 0, 0 }
};
/*
* i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device
* @idVendor: the 16-bit vendor ID
* @idProduct: the 16-bit product ID
*
* Returns: a u32 quirks value.
*/
static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
{
u32 quirks = 0;
int n;
for (n = 0; i2c_hid_quirks[n].idVendor; n++)
if (i2c_hid_quirks[n].idVendor == idVendor &&
(i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID ||
i2c_hid_quirks[n].idProduct == idProduct))
quirks = i2c_hid_quirks[n].quirks;
return quirks;
}
static int __i2c_hid_command(struct i2c_client *client, static int __i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command, u8 reportID, const struct i2c_hid_cmd *command, u8 reportID,
u8 reportType, u8 *args, int args_len, u8 reportType, u8 *args, int args_len,
...@@ -346,11 +384,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) ...@@ -346,11 +384,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
i2c_hid_dbg(ihid, "%s\n", __func__); i2c_hid_dbg(ihid, "%s\n", __func__);
/*
* Some devices require to send a command to wakeup before power on.
* The call will get a return value (EREMOTEIO) but device will be
* triggered and activated. After that, it goes like a normal device.
*/
if (power_state == I2C_HID_PWR_ON &&
ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
/* Device was already activated */
if (!ret)
goto set_pwr_exit;
}
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
0, NULL, 0, NULL, 0); 0, NULL, 0, NULL, 0);
if (ret) if (ret)
dev_err(&client->dev, "failed to change power setting.\n"); dev_err(&client->dev, "failed to change power setting.\n");
set_pwr_exit:
return ret; return ret;
} }
...@@ -716,9 +770,11 @@ static int i2c_hid_start(struct hid_device *hid) ...@@ -716,9 +770,11 @@ static int i2c_hid_start(struct hid_device *hid)
i2c_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize); i2c_hid_find_max_report(hid, HID_FEATURE_REPORT, &bufsize);
if (bufsize > ihid->bufsize) { if (bufsize > ihid->bufsize) {
disable_irq(client->irq);
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
ret = i2c_hid_alloc_buffers(ihid, bufsize); ret = i2c_hid_alloc_buffers(ihid, bufsize);
enable_irq(client->irq);
if (ret) if (ret)
return ret; return ret;
...@@ -806,18 +862,21 @@ static struct hid_ll_driver i2c_hid_ll_driver = { ...@@ -806,18 +862,21 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
static int i2c_hid_init_irq(struct i2c_client *client) static int i2c_hid_init_irq(struct i2c_client *client)
{ {
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
unsigned long irqflags = 0;
int ret; int ret;
dev_dbg(&client->dev, "Requesting IRQ: %d\n", ihid->irq); dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
ret = request_threaded_irq(ihid->irq, NULL, i2c_hid_irq, if (!irq_get_trigger_type(client->irq))
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags = IRQF_TRIGGER_LOW;
client->name, ihid);
ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
irqflags | IRQF_ONESHOT, client->name, ihid);
if (ret < 0) { if (ret < 0) {
dev_warn(&client->dev, dev_warn(&client->dev,
"Could not register for %s interrupt, irq = %d," "Could not register for %s interrupt, irq = %d,"
" ret = %d\n", " ret = %d\n",
client->name, ihid->irq, ret); client->name, client->irq, ret);
return ret; return ret;
} }
...@@ -864,14 +923,6 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid) ...@@ -864,14 +923,6 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* Default GPIO mapping */
static const struct acpi_gpio_params i2c_hid_irq_gpio = { 0, 0, true };
static const struct acpi_gpio_mapping i2c_hid_acpi_gpios[] = {
{ "gpios", &i2c_hid_irq_gpio, 1 },
{ },
};
static int i2c_hid_acpi_pdata(struct i2c_client *client, static int i2c_hid_acpi_pdata(struct i2c_client *client,
struct i2c_hid_platform_data *pdata) struct i2c_hid_platform_data *pdata)
{ {
...@@ -882,7 +933,6 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, ...@@ -882,7 +933,6 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
union acpi_object *obj; union acpi_object *obj;
struct acpi_device *adev; struct acpi_device *adev;
acpi_handle handle; acpi_handle handle;
int ret;
handle = ACPI_HANDLE(&client->dev); handle = ACPI_HANDLE(&client->dev);
if (!handle || acpi_bus_get_device(handle, &adev)) if (!handle || acpi_bus_get_device(handle, &adev))
...@@ -898,9 +948,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, ...@@ -898,9 +948,7 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
pdata->hid_descriptor_address = obj->integer.value; pdata->hid_descriptor_address = obj->integer.value;
ACPI_FREE(obj); ACPI_FREE(obj);
/* GPIOs are optional */ return 0;
ret = acpi_dev_add_driver_gpios(adev, i2c_hid_acpi_gpios);
return ret < 0 && ret != -ENXIO ? ret : 0;
} }
static const struct acpi_device_id i2c_hid_acpi_match[] = { static const struct acpi_device_id i2c_hid_acpi_match[] = {
...@@ -964,6 +1012,19 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -964,6 +1012,19 @@ static int i2c_hid_probe(struct i2c_client *client,
dbg_hid("HID probe called for i2c 0x%02x\n", client->addr); dbg_hid("HID probe called for i2c 0x%02x\n", client->addr);
if (!client->irq) {
dev_err(&client->dev,
"HID over i2c has not been provided an Int IRQ\n");
return -EINVAL;
}
if (client->irq < 0) {
if (client->irq != -EPROBE_DEFER)
dev_err(&client->dev,
"HID over i2c doesn't have a valid IRQ\n");
return client->irq;
}
ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL); ihid = kzalloc(sizeof(struct i2c_hid), GFP_KERNEL);
if (!ihid) if (!ihid)
return -ENOMEM; return -ENOMEM;
...@@ -983,23 +1044,6 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -983,23 +1044,6 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->pdata = *platform_data; ihid->pdata = *platform_data;
} }
if (client->irq > 0) {
ihid->irq = client->irq;
} else if (ACPI_COMPANION(&client->dev)) {
ihid->desc = gpiod_get(&client->dev, NULL, GPIOD_IN);
if (IS_ERR(ihid->desc)) {
dev_err(&client->dev, "Failed to get GPIO interrupt\n");
return PTR_ERR(ihid->desc);
}
ihid->irq = gpiod_to_irq(ihid->desc);
if (ihid->irq < 0) {
gpiod_put(ihid->desc);
dev_err(&client->dev, "Failed to convert GPIO to IRQ\n");
return ihid->irq;
}
}
i2c_set_clientdata(client, ihid); i2c_set_clientdata(client, ihid);
ihid->client = client; ihid->client = client;
...@@ -1050,6 +1094,8 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1050,6 +1094,8 @@ static int i2c_hid_probe(struct i2c_client *client,
client->name, hid->vendor, hid->product); client->name, hid->vendor, hid->product);
strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
ret = hid_add_device(hid); ret = hid_add_device(hid);
if (ret) { if (ret) {
if (ret != -ENODEV) if (ret != -ENODEV)
...@@ -1064,16 +1110,13 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1064,16 +1110,13 @@ static int i2c_hid_probe(struct i2c_client *client,
hid_destroy_device(hid); hid_destroy_device(hid);
err_irq: err_irq:
free_irq(ihid->irq, ihid); free_irq(client->irq, ihid);
err_pm: err_pm:
pm_runtime_put_noidle(&client->dev); pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
err: err:
if (ihid->desc)
gpiod_put(ihid->desc);
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
kfree(ihid); kfree(ihid);
return ret; return ret;
...@@ -1092,18 +1135,13 @@ static int i2c_hid_remove(struct i2c_client *client) ...@@ -1092,18 +1135,13 @@ static int i2c_hid_remove(struct i2c_client *client)
hid = ihid->hid; hid = ihid->hid;
hid_destroy_device(hid); hid_destroy_device(hid);
free_irq(ihid->irq, ihid); free_irq(client->irq, ihid);
if (ihid->bufsize) if (ihid->bufsize)
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
if (ihid->desc)
gpiod_put(ihid->desc);
kfree(ihid); kfree(ihid);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev));
return 0; return 0;
} }
...@@ -1142,11 +1180,11 @@ static int i2c_hid_suspend(struct device *dev) ...@@ -1142,11 +1180,11 @@ static int i2c_hid_suspend(struct device *dev)
/* Save some power */ /* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
disable_irq(ihid->irq); disable_irq(client->irq);
} }
if (device_may_wakeup(&client->dev)) { if (device_may_wakeup(&client->dev)) {
wake_status = enable_irq_wake(ihid->irq); wake_status = enable_irq_wake(client->irq);
if (!wake_status) if (!wake_status)
ihid->irq_wake_enabled = true; ihid->irq_wake_enabled = true;
else else
...@@ -1166,7 +1204,7 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1166,7 +1204,7 @@ static int i2c_hid_resume(struct device *dev)
int wake_status; int wake_status;
if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) { if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
wake_status = disable_irq_wake(ihid->irq); wake_status = disable_irq_wake(client->irq);
if (!wake_status) if (!wake_status)
ihid->irq_wake_enabled = false; ihid->irq_wake_enabled = false;
else else
...@@ -1179,7 +1217,7 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1179,7 +1217,7 @@ static int i2c_hid_resume(struct device *dev)
pm_runtime_set_active(dev); pm_runtime_set_active(dev);
pm_runtime_enable(dev); pm_runtime_enable(dev);
enable_irq(ihid->irq); enable_irq(client->irq);
ret = i2c_hid_hwreset(client); ret = i2c_hid_hwreset(client);
if (ret) if (ret)
return ret; return ret;
...@@ -1197,19 +1235,17 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1197,19 +1235,17 @@ static int i2c_hid_resume(struct device *dev)
static int i2c_hid_runtime_suspend(struct device *dev) static int i2c_hid_runtime_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_hid *ihid = i2c_get_clientdata(client);
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
disable_irq(ihid->irq); disable_irq(client->irq);
return 0; return 0;
} }
static int i2c_hid_runtime_resume(struct device *dev) static int i2c_hid_runtime_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct i2c_hid *ihid = i2c_get_clientdata(client);
enable_irq(ihid->irq); enable_irq(client->irq);
i2c_hid_set_power(client, I2C_HID_PWR_ON); i2c_hid_set_power(client, I2C_HID_PWR_ON);
return 0; return 0;
} }
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include "client.h" #include "client.h"
#include "hw-ish.h" #include "hw-ish.h"
#include "utils.h"
#include "hbm.h" #include "hbm.h"
/* For FW reset flow */ /* For FW reset flow */
...@@ -310,6 +309,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev) ...@@ -310,6 +309,7 @@ static int write_ipc_from_queue(struct ishtp_device *dev)
((uint32_t)tv_utc.tv_usec); ((uint32_t)tv_utc.tv_usec);
ts_format.ts1_source = HOST_SYSTEM_TIME_USEC; ts_format.ts1_source = HOST_SYSTEM_TIME_USEC;
ts_format.ts2_source = HOST_UTC_TIME_USEC; ts_format.ts2_source = HOST_UTC_TIME_USEC;
ts_format.reserved = 0;
time_update.primary_host_time = usec_system; time_update.primary_host_time = usec_system;
time_update.secondary_host_time = usec_utc; time_update.secondary_host_time = usec_utc;
...@@ -427,6 +427,59 @@ static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code, ...@@ -427,6 +427,59 @@ static int ipc_send_mng_msg(struct ishtp_device *dev, uint32_t msg_code,
sizeof(uint32_t) + size); sizeof(uint32_t) + size);
} }
#define WAIT_FOR_FW_RDY 0x1
#define WAIT_FOR_INPUT_RDY 0x2
/**
* timed_wait_for_timeout() - wait special event with timeout
* @dev: ISHTP device pointer
* @condition: indicate the condition for waiting
* @timeinc: time slice for every wait cycle, in ms
* @timeout: time in ms for timeout
*
* This function will check special event to be ready in a loop, the loop
* period is specificd in timeinc. Wait timeout will causes failure.
*
* Return: 0 for success else failure code
*/
static int timed_wait_for_timeout(struct ishtp_device *dev, int condition,
unsigned int timeinc, unsigned int timeout)
{
bool complete = false;
int ret;
do {
if (condition == WAIT_FOR_FW_RDY) {
complete = ishtp_fw_is_ready(dev);
} else if (condition == WAIT_FOR_INPUT_RDY) {
complete = ish_is_input_ready(dev);
} else {
ret = -EINVAL;
goto out;
}
if (!complete) {
unsigned long left_time;
left_time = msleep_interruptible(timeinc);
timeout -= (timeinc - left_time);
}
} while (!complete && timeout > 0);
if (complete)
ret = 0;
else
ret = -EBUSY;
out:
return ret;
}
#define TIME_SLICE_FOR_FW_RDY_MS 100
#define TIME_SLICE_FOR_INPUT_RDY_MS 100
#define TIMEOUT_FOR_FW_RDY_MS 2000
#define TIMEOUT_FOR_INPUT_RDY_MS 2000
/** /**
* ish_fw_reset_handler() - FW reset handler * ish_fw_reset_handler() - FW reset handler
* @dev: ishtp device pointer * @dev: ishtp device pointer
...@@ -456,8 +509,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) ...@@ -456,8 +509,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
ishtp_reset_handler(dev); ishtp_reset_handler(dev);
if (!ish_is_input_ready(dev)) if (!ish_is_input_ready(dev))
timed_wait_for_timeout(WAIT_FOR_SEND_SLICE, timed_wait_for_timeout(dev, WAIT_FOR_INPUT_RDY,
ish_is_input_ready(dev), (2 * HZ)); TIME_SLICE_FOR_INPUT_RDY_MS, TIMEOUT_FOR_INPUT_RDY_MS);
/* ISH FW is dead */ /* ISH FW is dead */
if (!ish_is_input_ready(dev)) if (!ish_is_input_ready(dev))
...@@ -472,8 +525,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) ...@@ -472,8 +525,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
sizeof(uint32_t)); sizeof(uint32_t));
/* Wait for ISH FW'es ILUP and ISHTP_READY */ /* Wait for ISH FW'es ILUP and ISHTP_READY */
timed_wait_for_timeout(WAIT_FOR_SEND_SLICE, ishtp_fw_is_ready(dev), timed_wait_for_timeout(dev, WAIT_FOR_FW_RDY,
(2 * HZ)); TIME_SLICE_FOR_FW_RDY_MS, TIMEOUT_FOR_FW_RDY_MS);
if (!ishtp_fw_is_ready(dev)) { if (!ishtp_fw_is_ready(dev)) {
/* ISH FW is dead */ /* ISH FW is dead */
uint32_t ish_status; uint32_t ish_status;
...@@ -487,6 +540,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev) ...@@ -487,6 +540,8 @@ static int ish_fw_reset_handler(struct ishtp_device *dev)
return 0; return 0;
} }
#define TIMEOUT_FOR_HW_RDY_MS 300
/** /**
* ish_fw_reset_work_fn() - FW reset worker function * ish_fw_reset_work_fn() - FW reset worker function
* @unused: not used * @unused: not used
...@@ -500,7 +555,7 @@ static void fw_reset_work_fn(struct work_struct *unused) ...@@ -500,7 +555,7 @@ static void fw_reset_work_fn(struct work_struct *unused)
rv = ish_fw_reset_handler(ishtp_dev); rv = ish_fw_reset_handler(ishtp_dev);
if (!rv) { if (!rv) {
/* ISH is ILUP & ISHTP-ready. Restart ISHTP */ /* ISH is ILUP & ISHTP-ready. Restart ISHTP */
schedule_timeout(HZ / 3); msleep_interruptible(TIMEOUT_FOR_HW_RDY_MS);
ishtp_dev->recvd_hw_ready = 1; ishtp_dev->recvd_hw_ready = 1;
wake_up_interruptible(&ishtp_dev->wait_hw_ready); wake_up_interruptible(&ishtp_dev->wait_hw_ready);
......
/*
* Utility macros of ISH
*
* Copyright (c) 2014-2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifndef UTILS__H
#define UTILS__H
#define WAIT_FOR_SEND_SLICE (HZ / 10)
#define WAIT_FOR_CONNECT_SLICE (HZ / 10)
/*
* Waits for specified event when a thread that triggers event can't signal
* Also, waits *at_least* `timeinc` after condition is satisfied
*/
#define timed_wait_for(timeinc, condition) \
do { \
int completed = 0; \
do { \
unsigned long j; \
int done = 0; \
\
completed = (condition); \
for (j = jiffies, done = 0; !done; ) { \
schedule_timeout(timeinc); \
if (time_is_before_eq_jiffies(j + timeinc)) \
done = 1; \
} \
} while (!(completed)); \
} while (0)
/*
* Waits for specified event when a thread that triggers event
* can't signal with timeout (use whenever we may hang)
*/
#define timed_wait_for_timeout(timeinc, condition, timeout) \
do { \
int t = timeout; \
do { \
unsigned long j; \
int done = 0; \
\
for (j = jiffies, done = 0; !done; ) { \
schedule_timeout(timeinc); \
if (time_is_before_eq_jiffies(j + timeinc)) \
done = 1; \
} \
t -= timeinc; \
if (t <= 0) \
break; \
} while (!(condition)); \
} while (0)
#endif /* UTILS__H */
...@@ -585,14 +585,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev) ...@@ -585,14 +585,7 @@ int ishtp_bus_new_client(struct ishtp_device *dev)
*/ */
i = dev->fw_client_presentation_num - 1; i = dev->fw_client_presentation_num - 1;
device_uuid = dev->fw_clients[i].props.protocol_name; device_uuid = dev->fw_clients[i].props.protocol_name;
dev_name = kasprintf(GFP_KERNEL, dev_name = kasprintf(GFP_KERNEL, "{%pUL}", device_uuid.b);
"{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
device_uuid.b[3], device_uuid.b[2], device_uuid.b[1],
device_uuid.b[0], device_uuid.b[5], device_uuid.b[4],
device_uuid.b[7], device_uuid.b[6], device_uuid.b[8],
device_uuid.b[9], device_uuid.b[10], device_uuid.b[11],
device_uuid.b[12], device_uuid.b[13], device_uuid.b[14],
device_uuid.b[15]);
if (!dev_name) if (!dev_name)
return -ENOMEM; return -ENOMEM;
......
...@@ -378,11 +378,10 @@ static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev, ...@@ -378,11 +378,10 @@ static void ishtp_hbm_cl_disconnect_res(struct ishtp_device *dev,
list_for_each_entry(cl, &dev->cl_list, link) { list_for_each_entry(cl, &dev->cl_list, link) {
if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) { if (!rs->status && ishtp_hbm_cl_addr_equal(cl, rs)) {
cl->state = ISHTP_CL_DISCONNECTED; cl->state = ISHTP_CL_DISCONNECTED;
wake_up_interruptible(&cl->wait_ctrl_res);
break; break;
} }
} }
if (cl)
wake_up_interruptible(&cl->wait_ctrl_res);
spin_unlock_irqrestore(&dev->cl_list_lock, flags); spin_unlock_irqrestore(&dev->cl_list_lock, flags);
} }
...@@ -431,11 +430,10 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev, ...@@ -431,11 +430,10 @@ static void ishtp_hbm_cl_connect_res(struct ishtp_device *dev,
cl->state = ISHTP_CL_DISCONNECTED; cl->state = ISHTP_CL_DISCONNECTED;
cl->status = -ENODEV; cl->status = -ENODEV;
} }
wake_up_interruptible(&cl->wait_ctrl_res);
break; break;
} }
} }
if (cl)
wake_up_interruptible(&cl->wait_ctrl_res);
spin_unlock_irqrestore(&dev->cl_list_lock, flags); spin_unlock_irqrestore(&dev->cl_list_lock, flags);
} }
......
...@@ -1459,7 +1459,7 @@ static int hid_post_reset(struct usb_interface *intf) ...@@ -1459,7 +1459,7 @@ static int hid_post_reset(struct usb_interface *intf)
rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL); rdesc = kmalloc(hid->dev_rsize, GFP_KERNEL);
if (!rdesc) { if (!rdesc) {
dbg_hid("couldn't allocate rdesc memory (post_reset)\n"); dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
return 1; return -ENOMEM;
} }
status = hid_get_class_descriptor(dev, status = hid_get_class_descriptor(dev,
interface->desc.bInterfaceNumber, interface->desc.bInterfaceNumber,
...@@ -1467,13 +1467,13 @@ static int hid_post_reset(struct usb_interface *intf) ...@@ -1467,13 +1467,13 @@ static int hid_post_reset(struct usb_interface *intf)
if (status < 0) { if (status < 0) {
dbg_hid("reading report descriptor failed (post_reset)\n"); dbg_hid("reading report descriptor failed (post_reset)\n");
kfree(rdesc); kfree(rdesc);
return 1; return status;
} }
status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize); status = memcmp(rdesc, hid->dev_rdesc, hid->dev_rsize);
kfree(rdesc); kfree(rdesc);
if (status != 0) { if (status != 0) {
dbg_hid("report descriptor changed\n"); dbg_hid("report descriptor changed\n");
return 1; return -EPERM;
} }
/* No need to do another reset or clear a halted endpoint */ /* No need to do another reset or clear a halted endpoint */
......
...@@ -82,6 +82,8 @@ static const struct hid_blacklist { ...@@ -82,6 +82,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
...@@ -101,8 +103,9 @@ static const struct hid_blacklist { ...@@ -101,8 +103,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
......
...@@ -210,7 +210,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, ...@@ -210,7 +210,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
struct wacom_wac *wacom_wac); struct wacom_wac *wacom_wac);
void wacom_wac_usage_mapping(struct hid_device *hdev, void wacom_wac_usage_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage); struct hid_field *field, struct hid_usage *usage);
int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value); struct hid_usage *usage, __s32 value);
void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report);
void wacom_battery_work(struct work_struct *work); void wacom_battery_work(struct work_struct *work);
......
...@@ -122,6 +122,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, ...@@ -122,6 +122,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
struct hid_data *hid_data = &wacom->wacom_wac.hid_data; struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
u8 *data; u8 *data;
int ret; int ret;
int n;
switch (usage->hid) { switch (usage->hid) {
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
...@@ -159,22 +160,48 @@ static void wacom_feature_mapping(struct hid_device *hdev, ...@@ -159,22 +160,48 @@ static void wacom_feature_mapping(struct hid_device *hdev,
case HID_UP_DIGITIZER: case HID_UP_DIGITIZER:
if (field->report->id == 0x0B && if (field->report->id == 0x0B &&
(field->application == WACOM_G9_DIGITIZER || (field->application == WACOM_HID_G9_PEN ||
field->application == WACOM_G11_DIGITIZER)) { field->application == WACOM_HID_G11_PEN)) {
wacom->wacom_wac.mode_report = field->report->id; wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 0; wacom->wacom_wac.mode_value = 0;
} }
break; break;
case WACOM_G9_PAGE: case WACOM_HID_WD_DATAMODE:
case WACOM_G11_PAGE: wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 2;
break;
case WACOM_HID_UP_G9:
case WACOM_HID_UP_G11:
if (field->report->id == 0x03 && if (field->report->id == 0x03 &&
(field->application == WACOM_G9_TOUCHSCREEN || (field->application == WACOM_HID_G9_TOUCHSCREEN ||
field->application == WACOM_G11_TOUCHSCREEN)) { field->application == WACOM_HID_G11_TOUCHSCREEN)) {
wacom->wacom_wac.mode_report = field->report->id; wacom->wacom_wac.mode_report = field->report->id;
wacom->wacom_wac.mode_value = 0; wacom->wacom_wac.mode_value = 0;
} }
break; break;
case WACOM_HID_WD_OFFSETLEFT:
case WACOM_HID_WD_OFFSETTOP:
case WACOM_HID_WD_OFFSETRIGHT:
case WACOM_HID_WD_OFFSETBOTTOM:
/* read manually */
n = hid_report_len(field->report);
data = hid_alloc_report_buf(field->report, GFP_KERNEL);
if (!data)
break;
data[0] = field->report->id;
ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
data, n, WAC_CMD_RETRIES);
if (ret == n) {
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
data, n, 0);
} else {
hid_warn(hdev, "%s: could not retrieve sensor offsets\n",
__func__);
}
kfree(data);
break;
} }
} }
...@@ -240,6 +267,30 @@ static void wacom_usage_mapping(struct hid_device *hdev, ...@@ -240,6 +267,30 @@ static void wacom_usage_mapping(struct hid_device *hdev,
features->touch_max = 1; features->touch_max = 1;
} }
/*
* ISDv4 devices which predate HID's adoption of the
* HID_DG_BARELSWITCH2 usage use 0x000D0000 in its
* position instead. We can accurately detect if a
* usage with that value should be HID_DG_BARRELSWITCH2
* based on the surrounding usages, which have remained
* constant across generations.
*/
if (features->type == HID_GENERIC &&
usage->hid == 0x000D0000 &&
field->application == HID_DG_PEN &&
field->physical == HID_DG_STYLUS) {
int i = usage->usage_index;
if (i-4 >= 0 && i+1 < field->maxusage &&
field->usage[i-4].hid == HID_DG_TIPSWITCH &&
field->usage[i-3].hid == HID_DG_BARRELSWITCH &&
field->usage[i-2].hid == HID_DG_ERASER &&
field->usage[i-1].hid == HID_DG_INVERT &&
field->usage[i+1].hid == HID_DG_INRANGE) {
usage->hid = HID_DG_BARRELSWITCH2;
}
}
switch (usage->hid) { switch (usage->hid) {
case HID_GD_X: case HID_GD_X:
features->x_max = field->logical_maximum; features->x_max = field->logical_maximum;
...@@ -689,11 +740,6 @@ static int wacom_add_shared_data(struct hid_device *hdev) ...@@ -689,11 +740,6 @@ static int wacom_add_shared_data(struct hid_device *hdev)
return retval; return retval;
} }
if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
wacom_wac->shared->touch = hdev;
else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
wacom_wac->shared->pen = hdev;
out: out:
mutex_unlock(&wacom_udev_list_lock); mutex_unlock(&wacom_udev_list_lock);
return retval; return retval;
...@@ -1916,6 +1962,19 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) ...@@ -1916,6 +1962,19 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
/* shift everything including the terminator */ /* shift everything including the terminator */
memmove(gap, gap+1, strlen(gap)); memmove(gap, gap+1, strlen(gap));
} }
/* strip off excessive prefixing */
if (strstr(name, "Wacom Co.,Ltd. Wacom ") == name) {
int n = strlen(name);
int x = strlen("Wacom Co.,Ltd. ");
memmove(name, name+x, n-x+1);
}
if (strstr(name, "Wacom Co., Ltd. Wacom ") == name) {
int n = strlen(name);
int x = strlen("Wacom Co., Ltd. ");
memmove(name, name+x, n-x+1);
}
/* get rid of trailing whitespace */ /* get rid of trailing whitespace */
if (name[strlen(name)-1] == ' ') if (name[strlen(name)-1] == ' ')
name[strlen(name)-1] = '\0'; name[strlen(name)-1] = '\0';
...@@ -1977,6 +2036,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) ...@@ -1977,6 +2036,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
if (error) if (error)
goto fail; goto fail;
error = wacom_add_shared_data(hdev);
if (error)
goto fail;
/* /*
* Bamboo Pad has a generic hid handling for the Pen, and we switch it * Bamboo Pad has a generic hid handling for the Pen, and we switch it
* into debug mode for the touch part. * into debug mode for the touch part.
...@@ -2017,9 +2080,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) ...@@ -2017,9 +2080,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
wacom_update_name(wacom, wireless ? " (WL)" : ""); wacom_update_name(wacom, wireless ? " (WL)" : "");
error = wacom_add_shared_data(hdev); if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
if (error) wacom_wac->shared->touch = hdev;
goto fail; else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
wacom_wac->shared->pen = hdev;
if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) && if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) { (features->quirks & WACOM_QUIRK_BATTERY)) {
......
This diff is collapsed.
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
/* device quirks */ /* device quirks */
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001
#define WACOM_QUIRK_SENSE 0x0002
#define WACOM_QUIRK_BATTERY 0x0008 #define WACOM_QUIRK_BATTERY 0x0008
/* device types */ /* device types */
...@@ -84,23 +85,66 @@ ...@@ -84,23 +85,66 @@
#define WACOM_DEVICETYPE_WL_MONITOR 0x0008 #define WACOM_DEVICETYPE_WL_MONITOR 0x0008
#define WACOM_DEVICETYPE_DIRECT 0x0010 #define WACOM_DEVICETYPE_DIRECT 0x0010
#define WACOM_VENDORDEFINED_PEN 0xff0d0001 #define WACOM_HID_UP_WACOMDIGITIZER 0xff0d0000
#define WACOM_G9_PAGE 0xff090000 #define WACOM_HID_SP_PAD 0x00040000
#define WACOM_G9_DIGITIZER (WACOM_G9_PAGE | 0x02) #define WACOM_HID_SP_BUTTON 0x00090000
#define WACOM_G9_TOUCHSCREEN (WACOM_G9_PAGE | 0x11) #define WACOM_HID_SP_DIGITIZER 0x000d0000
#define WACOM_G11_PAGE 0xff110000 #define WACOM_HID_SP_DIGITIZERINFO 0x00100000
#define WACOM_G11_DIGITIZER (WACOM_G11_PAGE | 0x02) #define WACOM_HID_WD_DIGITIZER (WACOM_HID_UP_WACOMDIGITIZER | 0x01)
#define WACOM_G11_TOUCHSCREEN (WACOM_G11_PAGE | 0x11) #define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36)
#define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39)
#define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c)
#define WACOM_HID_WD_TOOLTYPE (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
#define WACOM_HID_WD_DISTANCE (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
#define WACOM_HID_WD_TOUCHSTRIP (WACOM_HID_UP_WACOMDIGITIZER | 0x0136)
#define WACOM_HID_WD_TOUCHSTRIP2 (WACOM_HID_UP_WACOMDIGITIZER | 0x0137)
#define WACOM_HID_WD_TOUCHRING (WACOM_HID_UP_WACOMDIGITIZER | 0x0138)
#define WACOM_HID_WD_TOUCHRINGSTATUS (WACOM_HID_UP_WACOMDIGITIZER | 0x0139)
#define WACOM_HID_WD_ACCELEROMETER_X (WACOM_HID_UP_WACOMDIGITIZER | 0x0401)
#define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402)
#define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403)
#define WACOM_HID_WD_BATTERY_CHARGING (WACOM_HID_UP_WACOMDIGITIZER | 0x0404)
#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_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)
#define WACOM_HID_WD_BUTTONLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0993)
#define WACOM_HID_WD_BUTTONRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0994)
#define WACOM_HID_WD_BUTTONCENTER (WACOM_HID_UP_WACOMDIGITIZER | 0x0995)
#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0996)
#define WACOM_HID_WD_FINGERWHEEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0d03)
#define WACOM_HID_WD_OFFSETLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d30)
#define WACOM_HID_WD_OFFSETTOP (WACOM_HID_UP_WACOMDIGITIZER | 0x0d31)
#define WACOM_HID_WD_OFFSETRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d32)
#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
#define WACOM_HID_UP_G9 0xff090000
#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02)
#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11)
#define WACOM_HID_UP_G11 0xff110000
#define WACOM_HID_G11_PEN (WACOM_HID_UP_G11 | 0x02)
#define WACOM_HID_G11_TOUCHSCREEN (WACOM_HID_UP_G11 | 0x11)
#define WACOM_PAD_FIELD(f) (((f)->physical == HID_DG_TABLETFUNCTIONKEY) || \
((f)->physical == WACOM_HID_WD_DIGITIZERFNKEYS) || \
((f)->physical == WACOM_HID_WD_DIGITIZERINFO))
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
((f)->physical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_STYLUS) || \
((f)->physical == HID_DG_PEN) || \ ((f)->physical == HID_DG_PEN) || \
((f)->application == HID_DG_PEN) || \ ((f)->application == HID_DG_PEN) || \
((f)->application == HID_DG_DIGITIZER) || \ ((f)->application == HID_DG_DIGITIZER) || \
((f)->application == WACOM_VENDORDEFINED_PEN)) ((f)->application == WACOM_HID_WD_DIGITIZER) || \
((f)->application == WACOM_HID_G9_PEN) || \
((f)->application == WACOM_HID_G11_PEN))
#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
((f)->physical == HID_DG_FINGER) || \ ((f)->physical == HID_DG_FINGER) || \
((f)->application == HID_DG_TOUCHSCREEN)) ((f)->application == HID_DG_TOUCHSCREEN) || \
((f)->application == WACOM_HID_G9_TOUCHSCREEN) || \
((f)->application == WACOM_HID_G11_TOUCHSCREEN))
enum { enum {
PENPARTNER = 0, PENPARTNER = 0,
...@@ -167,8 +211,10 @@ struct wacom_features { ...@@ -167,8 +211,10 @@ struct wacom_features {
int x_resolution; int x_resolution;
int y_resolution; int y_resolution;
int numbered_buttons; int numbered_buttons;
int x_min; int offset_left;
int y_min; int offset_right;
int offset_top;
int offset_bottom;
int device_type; int device_type;
int x_phy; int x_phy;
int y_phy; int y_phy;
...@@ -186,6 +232,7 @@ struct wacom_features { ...@@ -186,6 +232,7 @@ struct wacom_features {
int pktlen; int pktlen;
bool check_for_hid_type; bool check_for_hid_type;
int hid_type; int hid_type;
bool input_event_flag;
}; };
struct wacom_shared { struct wacom_shared {
...@@ -202,6 +249,7 @@ struct wacom_shared { ...@@ -202,6 +249,7 @@ struct wacom_shared {
struct hid_data { struct hid_data {
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
__s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 inputmode_index; /* InputMode HID feature index in the report */
bool sense_state;
bool inrange_state; bool inrange_state;
bool invert_state; bool invert_state;
bool tipswitch; bool tipswitch;
...@@ -217,6 +265,10 @@ struct hid_data { ...@@ -217,6 +265,10 @@ struct hid_data {
int last_slot_field; int last_slot_field;
int num_expected; int num_expected;
int num_received; int num_received;
int battery_capacity;
int bat_charging;
int bat_connected;
int ps_connected;
}; };
struct wacom_remote_data { struct wacom_remote_data {
...@@ -234,7 +286,7 @@ struct wacom_wac { ...@@ -234,7 +286,7 @@ struct wacom_wac {
unsigned char data[WACOM_PKGLEN_MAX]; unsigned char data[WACOM_PKGLEN_MAX];
int tool[2]; int tool[2];
int id[2]; int id[2];
__u32 serial[2]; __u64 serial[2];
bool reporting_data; bool reporting_data;
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared; struct wacom_shared *shared;
......
...@@ -231,7 +231,11 @@ struct hid_item { ...@@ -231,7 +231,11 @@ struct hid_item {
#define HID_DG_TAP 0x000d0035 #define HID_DG_TAP 0x000d0035
#define HID_DG_TABLETFUNCTIONKEY 0x000d0039 #define HID_DG_TABLETFUNCTIONKEY 0x000d0039
#define HID_DG_PROGRAMCHANGEKEY 0x000d003a #define HID_DG_PROGRAMCHANGEKEY 0x000d003a
#define HID_DG_BATTERYSTRENGTH 0x000d003b
#define HID_DG_INVERT 0x000d003c #define HID_DG_INVERT 0x000d003c
#define HID_DG_TILT_X 0x000d003d
#define HID_DG_TILT_Y 0x000d003e
#define HID_DG_TWIST 0x000d0041
#define HID_DG_TIPSWITCH 0x000d0042 #define HID_DG_TIPSWITCH 0x000d0042
#define HID_DG_TIPSWITCH2 0x000d0043 #define HID_DG_TIPSWITCH2 0x000d0043
#define HID_DG_BARRELSWITCH 0x000d0044 #define HID_DG_BARRELSWITCH 0x000d0044
...@@ -479,6 +483,7 @@ struct hid_input { ...@@ -479,6 +483,7 @@ struct hid_input {
struct list_head list; struct list_head list;
struct hid_report *report; struct hid_report *report;
struct input_dev *input; struct input_dev *input;
bool registered;
}; };
enum hid_type { enum hid_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment