Commit 1ad0bc78 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:

 - syzbot memory corruption fixes for hidraw, Prodikeys, Logitech and
   Sony drivers from Alan Stern and Roderick Colenbrander

 - stuck 'fn' key fix for hid-apple from Joao Moreno

 - proper propagation of EPOLLOUT from hiddev and hidraw, from Fabian
   Henneke

 - fixes for handling power management for intel-ish devices with NO_D3
   flag set, from Zhang Lixu

 - extension of supported usage range for customer page, as some
   Logitech devices are actually making use of it. From Olivier Gay.

 - hid-multitouch is no longer filtering mice node creation, from
   Benjamin Tissoires

 - MobileStudio Pro 13 support, from Ping Cheng

 - a few other device ID additions and assorted smaller fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (27 commits)
  HID: core: fix dmesg flooding if report field larger than 32bit
  HID: core: Add printk_once variants to hid_warn() etc
  HID: core: reformat and reduce hid_printk macros
  HID: prodikeys: Fix general protection fault during probe
  HID: wacom: add new MobileStudio Pro 13 support
  HID: sony: Fix memory corruption issue on cleanup.
  HID: i2c-hid: modify quirks for weida's devices
  HID: apple: Fix stuck function keys when using FN
  HID: sb0540: add support for Creative SB0540 IR receivers
  HID: Add quirk for HP X500 PIXART OEM mouse
  HID: logitech-dj: Fix crash when initial logi_dj_recv_query_paired_devices fails
  hid-logitech-dj: add the new Lightspeed receiver
  HID: logitech-dj: add support of the G700(s) receiver
  HID: multitouch: add support for the Smart Tech panel
  HID: multitouch: do not filter mice nodes
  HID: do not call hid_set_drvdata(hdev, NULL) in drivers
  HID: wacom: do not call hid_set_drvdata(hdev, NULL)
  HID: logitech: Fix general protection fault caused by Logitech driver
  HID: hidraw: Fix invalid read in hidraw_ioctl
  HID: wacom: support named keys on older devices
  ...
parents 1b5fb415 8ca06d6f
...@@ -4338,6 +4338,12 @@ S: Maintained ...@@ -4338,6 +4338,12 @@ S: Maintained
F: Documentation/filesystems/cramfs.txt F: Documentation/filesystems/cramfs.txt
F: fs/cramfs/ F: fs/cramfs/
CREATIVE SB0540
M: Bastien Nocera <hadess@hadess.net>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-creative-sb0540.c
CRYPTO API CRYPTO API
M: Herbert Xu <herbert@gondor.apana.org.au> M: Herbert Xu <herbert@gondor.apana.org.au>
M: "David S. Miller" <davem@davemloft.net> M: "David S. Miller" <davem@davemloft.net>
......
...@@ -273,6 +273,15 @@ config HID_CP2112 ...@@ -273,6 +273,15 @@ config HID_CP2112
and gpiochip to expose these functions of the CP2112. The and gpiochip to expose these functions of the CP2112. The
customizable USB descriptor fields are exposed as sysfs attributes. customizable USB descriptor fields are exposed as sysfs attributes.
config HID_CREATIVE_SB0540
tristate "Creative SB0540 infrared receiver"
depends on USB_HID
help
Support for Creative infrared SB0540-compatible remote controls, such
as the RM-1500 and RM-1800 remotes.
Say Y here if you want support for Creative SB0540 infrared receiver.
config HID_CYPRESS config HID_CYPRESS
tristate "Cypress mouse and barcode readers" tristate "Cypress mouse and barcode readers"
depends on HID depends on HID
......
...@@ -27,6 +27,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o ...@@ -27,6 +27,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
obj-$(CONFIG_HID_ASUS) += hid-asus.o obj-$(CONFIG_HID_ASUS) += hid-asus.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
......
...@@ -54,7 +54,6 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") ...@@ -54,7 +54,6 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
struct apple_sc { struct apple_sc {
unsigned long quirks; unsigned long quirks;
unsigned int fn_on; unsigned int fn_on;
DECLARE_BITMAP(pressed_fn, KEY_CNT);
DECLARE_BITMAP(pressed_numlock, KEY_CNT); DECLARE_BITMAP(pressed_numlock, KEY_CNT);
}; };
...@@ -181,6 +180,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, ...@@ -181,6 +180,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
{ {
struct apple_sc *asc = hid_get_drvdata(hid); struct apple_sc *asc = hid_get_drvdata(hid);
const struct apple_key_translation *trans, *table; const struct apple_key_translation *trans, *table;
bool do_translate;
u16 code = 0;
if (usage->code == KEY_FN) { if (usage->code == KEY_FN) {
asc->fn_on = !!value; asc->fn_on = !!value;
...@@ -189,8 +190,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, ...@@ -189,8 +190,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
} }
if (fnmode) { if (fnmode) {
int do_translate;
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys; table = macbookair_fn_keys;
...@@ -202,25 +201,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, ...@@ -202,25 +201,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
trans = apple_find_translation (table, usage->code); trans = apple_find_translation (table, usage->code);
if (trans) { if (trans) {
if (test_bit(usage->code, asc->pressed_fn)) if (test_bit(trans->from, input->key))
do_translate = 1; code = trans->from;
else if (trans->flags & APPLE_FLAG_FKEY) else if (test_bit(trans->to, input->key))
do_translate = (fnmode == 2 && asc->fn_on) || code = trans->to;
(fnmode == 1 && !asc->fn_on);
else if (!code) {
do_translate = asc->fn_on; if (trans->flags & APPLE_FLAG_FKEY) {
switch (fnmode) {
if (do_translate) { case 1:
if (value) do_translate = !asc->fn_on;
set_bit(usage->code, asc->pressed_fn); break;
else case 2:
clear_bit(usage->code, asc->pressed_fn); do_translate = asc->fn_on;
break;
input_event(input, usage->type, trans->to, default:
value); /* should never happen */
do_translate = false;
return 1; }
} else {
do_translate = asc->fn_on;
}
code = do_translate ? trans->to : trans->from;
} }
input_event(input, usage->type, code, value);
return 1;
} }
if (asc->quirks & APPLE_NUMLOCK_EMULATION && if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
......
...@@ -1311,8 +1311,8 @@ u32 hid_field_extract(const struct hid_device *hid, u8 *report, ...@@ -1311,8 +1311,8 @@ u32 hid_field_extract(const struct hid_device *hid, u8 *report,
unsigned offset, unsigned n) unsigned offset, unsigned n)
{ {
if (n > 32) { if (n > 32) {
hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n", hid_warn_once(hid, "%s() called with n (%d) > 32! (%s)\n",
n, current->comm); __func__, n, current->comm);
n = 32; n = 32;
} }
......
...@@ -207,7 +207,7 @@ static int cougar_probe(struct hid_device *hdev, ...@@ -207,7 +207,7 @@ static int cougar_probe(struct hid_device *hdev,
error = hid_parse(hdev); error = hid_parse(hdev);
if (error) { if (error) {
hid_err(hdev, "parse failed\n"); hid_err(hdev, "parse failed\n");
goto fail; return error;
} }
if (hdev->collection->usage == COUGAR_VENDOR_USAGE) { if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
...@@ -219,7 +219,7 @@ static int cougar_probe(struct hid_device *hdev, ...@@ -219,7 +219,7 @@ static int cougar_probe(struct hid_device *hdev,
error = hid_hw_start(hdev, connect_mask); error = hid_hw_start(hdev, connect_mask);
if (error) { if (error) {
hid_err(hdev, "hw start failed\n"); hid_err(hdev, "hw start failed\n");
goto fail; return error;
} }
error = cougar_bind_shared_data(hdev, cougar); error = cougar_bind_shared_data(hdev, cougar);
...@@ -249,8 +249,6 @@ static int cougar_probe(struct hid_device *hdev, ...@@ -249,8 +249,6 @@ static int cougar_probe(struct hid_device *hdev,
fail_stop_and_cleanup: fail_stop_and_cleanup:
hid_hw_stop(hdev); hid_hw_stop(hdev);
fail:
hid_set_drvdata(hdev, NULL);
return error; return error;
} }
......
// SPDX-License-Identifier: GPL-2.0
/*
* HID driver for the Creative SB0540 receiver
*
* Copyright (C) 2019 Red Hat Inc. All Rights Reserved
*
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
MODULE_DESCRIPTION("HID Creative SB0540 receiver");
MODULE_LICENSE("GPL");
static const unsigned short creative_sb0540_key_table[] = {
KEY_POWER,
KEY_RESERVED, /* text: 24bit */
KEY_RESERVED, /* 24bit wheel up */
KEY_RESERVED, /* 24bit wheel down */
KEY_RESERVED, /* text: CMSS */
KEY_RESERVED, /* CMSS wheel Up */
KEY_RESERVED, /* CMSS wheel Down */
KEY_RESERVED, /* text: EAX */
KEY_RESERVED, /* EAX wheel up */
KEY_RESERVED, /* EAX wheel down */
KEY_RESERVED, /* text: 3D Midi */
KEY_RESERVED, /* 3D Midi wheel up */
KEY_RESERVED, /* 3D Midi wheel down */
KEY_MUTE,
KEY_VOLUMEUP,
KEY_VOLUMEDOWN,
KEY_UP,
KEY_LEFT,
KEY_RIGHT,
KEY_REWIND,
KEY_OK,
KEY_FASTFORWARD,
KEY_DOWN,
KEY_AGAIN, /* text: Return, symbol: Jump to */
KEY_PLAY, /* text: Start */
KEY_ESC, /* text: Cancel */
KEY_RECORD,
KEY_OPTION,
KEY_MENU, /* text: Display */
KEY_PREVIOUS,
KEY_PLAYPAUSE,
KEY_NEXT,
KEY_SLOW,
KEY_STOP,
KEY_NUMERIC_1,
KEY_NUMERIC_2,
KEY_NUMERIC_3,
KEY_NUMERIC_4,
KEY_NUMERIC_5,
KEY_NUMERIC_6,
KEY_NUMERIC_7,
KEY_NUMERIC_8,
KEY_NUMERIC_9,
KEY_NUMERIC_0
};
/*
* Codes and keys from lirc's
* remotes/creative/lircd.conf.alsa_usb
* order and size must match creative_sb0540_key_table[] above
*/
static const unsigned short creative_sb0540_codes[] = {
0x619E,
0x916E,
0x926D,
0x936C,
0x718E,
0x946B,
0x956A,
0x8C73,
0x9669,
0x9768,
0x9867,
0x9966,
0x9A65,
0x6E91,
0x629D,
0x639C,
0x7B84,
0x6B94,
0x728D,
0x8778,
0x817E,
0x758A,
0x8D72,
0x8E71,
0x8877,
0x7C83,
0x738C,
0x827D,
0x7689,
0x7F80,
0x7986,
0x7A85,
0x7D82,
0x857A,
0x8B74,
0x8F70,
0x906F,
0x8A75,
0x847B,
0x7887,
0x8976,
0x837C,
0x7788,
0x807F
};
struct creative_sb0540 {
struct input_dev *input_dev;
struct hid_device *hid;
unsigned short keymap[ARRAY_SIZE(creative_sb0540_key_table)];
};
static inline u64 reverse(u64 data, int bits)
{
int i;
u64 c;
c = 0;
for (i = 0; i < bits; i++) {
c |= (u64) (((data & (((u64) 1) << i)) ? 1 : 0))
<< (bits - 1 - i);
}
return (c);
}
static int get_key(struct creative_sb0540 *creative_sb0540, u64 keycode)
{
int i;
for (i = 0; i < ARRAY_SIZE(creative_sb0540_codes); i++) {
if (creative_sb0540_codes[i] == keycode)
return creative_sb0540->keymap[i];
}
return 0;
}
static int creative_sb0540_raw_event(struct hid_device *hid,
struct hid_report *report, u8 *data, int len)
{
struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
u64 code, main_code;
int key;
if (len != 6)
return 0;
/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
code = reverse(data[5], 8);
main_code = (code << 8) + ((~code) & 0xff);
/*
* Flip to get values in the same format as
* remotes/creative/lircd.conf.alsa_usb in lirc
*/
main_code = ((main_code & 0xff) << 8) +
((main_code & 0xff00) >> 8);
key = get_key(creative_sb0540, main_code);
if (key == 0 || key == KEY_RESERVED) {
hid_err(hid, "Could not get a key for main_code %llX\n",
main_code);
return 0;
}
input_report_key(creative_sb0540->input_dev, key, 1);
input_report_key(creative_sb0540->input_dev, key, 0);
input_sync(creative_sb0540->input_dev);
/* let hidraw and hiddev handle the report */
return 0;
}
static int creative_sb0540_input_configured(struct hid_device *hid,
struct hid_input *hidinput)
{
struct input_dev *input_dev = hidinput->input;
struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
int i;
creative_sb0540->input_dev = input_dev;
input_dev->keycode = creative_sb0540->keymap;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(creative_sb0540->keymap);
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
memcpy(creative_sb0540->keymap, creative_sb0540_key_table,
sizeof(creative_sb0540->keymap));
for (i = 0; i < ARRAY_SIZE(creative_sb0540_key_table); i++)
set_bit(creative_sb0540->keymap[i], input_dev->keybit);
clear_bit(KEY_RESERVED, input_dev->keybit);
return 0;
}
static int creative_sb0540_input_mapping(struct hid_device *hid,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
/*
* We are remapping the keys ourselves, so ignore the hid-input
* keymap processing.
*/
return -1;
}
static int creative_sb0540_probe(struct hid_device *hid,
const struct hid_device_id *id)
{
int ret;
struct creative_sb0540 *creative_sb0540;
creative_sb0540 = devm_kzalloc(&hid->dev,
sizeof(struct creative_sb0540), GFP_KERNEL);
if (!creative_sb0540)
return -ENOMEM;
creative_sb0540->hid = hid;
/* force input as some remotes bypass the input registration */
hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
hid_set_drvdata(hid, creative_sb0540);
ret = hid_parse(hid);
if (ret) {
hid_err(hid, "parse failed\n");
return ret;
}
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hid, "hw start failed\n");
return ret;
}
return ret;
}
static const struct hid_device_id creative_sb0540_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB0540) },
{ }
};
MODULE_DEVICE_TABLE(hid, creative_sb0540_devices);
static struct hid_driver creative_sb0540_driver = {
.name = "creative-sb0540",
.id_table = creative_sb0540_devices,
.raw_event = creative_sb0540_raw_event,
.input_configured = creative_sb0540_input_configured,
.probe = creative_sb0540_probe,
.input_mapping = creative_sb0540_input_mapping,
};
module_hid_driver(creative_sb0540_driver);
...@@ -123,12 +123,6 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -123,12 +123,6 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret; return ret;
} }
static void gfrm_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id gfrm_devices[] = { static const struct hid_device_id gfrm_devices[] = {
{ HID_BLUETOOTH_DEVICE(0x58, 0x2000), { HID_BLUETOOTH_DEVICE(0x58, 0x2000),
.driver_data = GFRM100 }, .driver_data = GFRM100 },
...@@ -142,7 +136,6 @@ static struct hid_driver gfrm_driver = { ...@@ -142,7 +136,6 @@ static struct hid_driver gfrm_driver = {
.name = "gfrm", .name = "gfrm",
.id_table = gfrm_devices, .id_table = gfrm_devices,
.probe = gfrm_probe, .probe = gfrm_probe,
.remove = gfrm_remove,
.input_mapping = gfrm_input_mapping, .input_mapping = gfrm_input_mapping,
.raw_event = gfrm_raw_event, .raw_event = gfrm_raw_event,
.input_configured = gfrm_input_configured, .input_configured = gfrm_input_configured,
......
...@@ -314,6 +314,7 @@ ...@@ -314,6 +314,7 @@
#define USB_VENDOR_ID_CREATIVELABS 0x041e #define USB_VENDOR_ID_CREATIVELABS 0x041e
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c #define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
#define USB_DEVICE_ID_CREATIVE_SB0540 0x3100
#define USB_VENDOR_ID_CVTOUCH 0x1ff7 #define USB_VENDOR_ID_CVTOUCH 0x1ff7
#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013 #define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
...@@ -568,6 +569,7 @@ ...@@ -568,6 +569,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941 0x0941
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
...@@ -769,7 +771,8 @@ ...@@ -769,7 +771,8 @@
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532 #define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED 0xc539 #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623 #define USB_DEVICE_ID_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 #define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
......
...@@ -866,8 +866,6 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev) ...@@ -866,8 +866,6 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev)
led_classdev_unregister(&data_pointer->led_micmute); led_classdev_unregister(&data_pointer->led_micmute);
led_classdev_unregister(&data_pointer->led_mute); led_classdev_unregister(&data_pointer->led_mute);
hid_set_drvdata(hdev, NULL);
} }
static void lenovo_remove_cptkbd(struct hid_device *hdev) static void lenovo_remove_cptkbd(struct hid_device *hdev)
......
...@@ -818,7 +818,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -818,7 +818,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!buf) { if (!buf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_free; goto err_stop;
} }
ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf), ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
...@@ -850,9 +850,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -850,9 +850,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = lg4ff_init(hdev); ret = lg4ff_init(hdev);
if (ret) if (ret)
goto err_free; goto err_stop;
return 0; return 0;
err_stop:
hid_hw_stop(hdev);
err_free: err_free:
kfree(drv_data); kfree(drv_data);
return ret; return ret;
...@@ -863,8 +866,7 @@ static void lg_remove(struct hid_device *hdev) ...@@ -863,8 +866,7 @@ static void lg_remove(struct hid_device *hdev)
struct lg_drv_data *drv_data = hid_get_drvdata(hdev); struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
if (drv_data->quirks & LG_FF4) if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev); lg4ff_deinit(hdev);
else hid_hw_stop(hdev);
hid_hw_stop(hdev);
kfree(drv_data); kfree(drv_data);
} }
......
...@@ -1477,7 +1477,6 @@ int lg4ff_deinit(struct hid_device *hid) ...@@ -1477,7 +1477,6 @@ int lg4ff_deinit(struct hid_device *hid)
} }
} }
#endif #endif
hid_hw_stop(hid);
drv_data->device_props = NULL; drv_data->device_props = NULL;
kfree(entry); kfree(entry);
......
...@@ -380,9 +380,9 @@ static const char consumer_descriptor[] = { ...@@ -380,9 +380,9 @@ static const char consumer_descriptor[] = {
0x75, 0x10, /* REPORT_SIZE (16) */ 0x75, 0x10, /* REPORT_SIZE (16) */
0x95, 0x02, /* REPORT_COUNT (2) */ 0x95, 0x02, /* REPORT_COUNT (2) */
0x15, 0x01, /* LOGICAL_MIN (1) */ 0x15, 0x01, /* LOGICAL_MIN (1) */
0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */ 0x26, 0xFF, 0x02, /* LOGICAL_MAX (767) */
0x19, 0x01, /* USAGE_MIN (1) */ 0x19, 0x01, /* USAGE_MIN (1) */
0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */ 0x2A, 0xFF, 0x02, /* USAGE_MAX (767) */
0x81, 0x00, /* INPUT (Data Ary Abs) */ 0x81, 0x00, /* INPUT (Data Ary Abs) */
0xC0, /* END_COLLECTION */ 0xC0, /* END_COLLECTION */
}; /* */ }; /* */
...@@ -959,6 +959,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -959,6 +959,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break; break;
case 0x07: case 0x07:
device_type = "eQUAD step 4 Gaming"; device_type = "eQUAD step 4 Gaming";
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x08: case 0x08:
device_type = "eQUAD step 4 for gamepads"; device_type = "eQUAD step 4 for gamepads";
...@@ -968,7 +969,12 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev, ...@@ -968,7 +969,12 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break; break;
case 0x0c: case 0x0c:
device_type = "eQUAD Lightspeed"; device_type = "eQUAD Lightspeed 1";
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
workitem.reports_supported |= STD_KEYBOARD;
break;
case 0x0d:
device_type = "eQUAD Lightspeed 1_1";
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem); logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
workitem.reports_supported |= STD_KEYBOARD; workitem.reports_supported |= STD_KEYBOARD;
break; break;
...@@ -1734,14 +1740,14 @@ static int logi_dj_probe(struct hid_device *hdev, ...@@ -1734,14 +1740,14 @@ static int logi_dj_probe(struct hid_device *hdev,
if (retval < 0) { if (retval < 0) {
hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n", hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n",
__func__, retval); __func__, retval);
goto logi_dj_recv_query_paired_devices_failed; /*
* This can happen with a KVM, let the probe succeed,
* logi_dj_recv_queue_unknown_work will retry later.
*/
} }
} }
return retval; return 0;
logi_dj_recv_query_paired_devices_failed:
hid_hw_close(hdev);
llopen_failed: llopen_failed:
switch_to_dj_mode_fail: switch_to_dj_mode_fail:
...@@ -1832,9 +1838,17 @@ static const struct hid_device_id logi_dj_receivers[] = { ...@@ -1832,9 +1838,17 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
.driver_data = recvr_type_hidpp}, .driver_data = recvr_type_hidpp},
{ /* Logitech G700(s) receiver (0xc531) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
0xc531),
.driver_data = recvr_type_gaming_hidpp},
{ /* Logitech lightspeed receiver (0xc539) */ { /* Logitech lightspeed receiver (0xc539) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED), USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1),
.driver_data = recvr_type_gaming_hidpp},
{ /* Logitech lightspeed receiver (0xc53f) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
.driver_data = recvr_type_gaming_hidpp}, .driver_data = recvr_type_gaming_hidpp},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
......
...@@ -68,6 +68,7 @@ MODULE_LICENSE("GPL"); ...@@ -68,6 +68,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_STICKY_FINGERS BIT(16) #define MT_QUIRK_STICKY_FINGERS BIT(16)
#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17)
#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) #define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18)
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
#define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03 #define MT_INPUTMODE_TOUCHPAD 0x03
...@@ -103,6 +104,7 @@ struct mt_usages { ...@@ -103,6 +104,7 @@ struct mt_usages {
struct mt_application { struct mt_application {
struct list_head list; struct list_head list;
unsigned int application; unsigned int application;
unsigned int report_id;
struct list_head mt_usages; /* mt usages list */ struct list_head mt_usages; /* mt usages list */
__s32 quirks; __s32 quirks;
...@@ -203,6 +205,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); ...@@ -203,6 +205,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_VTL 0x0110 #define MT_CLS_VTL 0x0110
#define MT_CLS_GOOGLE 0x0111 #define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
#define MT_CLS_SMART_TECH 0x0113
#define MT_DEFAULT_MAXCONTACT 10 #define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250 #define MT_MAX_MAXCONTACT 250
...@@ -263,7 +266,8 @@ static const struct mt_class mt_classes[] = { ...@@ -263,7 +266,8 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_HOVERING | MT_QUIRK_HOVERING |
MT_QUIRK_CONTACT_CNT_ACCURATE | MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_STICKY_FINGERS | MT_QUIRK_STICKY_FINGERS |
MT_QUIRK_WIN8_PTP_BUTTONS }, MT_QUIRK_WIN8_PTP_BUTTONS,
.export_all_inputs = true },
{ .name = MT_CLS_EXPORT_ALL_INPUTS, { .name = MT_CLS_EXPORT_ALL_INPUTS,
.quirks = MT_QUIRK_ALWAYS_VALID | .quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE, MT_QUIRK_CONTACT_CNT_ACCURATE,
...@@ -353,6 +357,12 @@ static const struct mt_class mt_classes[] = { ...@@ -353,6 +357,12 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE | MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_WIN8_PTP_BUTTONS, MT_QUIRK_WIN8_PTP_BUTTONS,
}, },
{ .name = MT_CLS_SMART_TECH,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_IGNORE_DUPLICATES |
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_SEPARATE_APP_REPORT,
},
{ } { }
}; };
...@@ -509,8 +519,9 @@ static struct mt_usages *mt_allocate_usage(struct hid_device *hdev, ...@@ -509,8 +519,9 @@ static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
} }
static struct mt_application *mt_allocate_application(struct mt_device *td, static struct mt_application *mt_allocate_application(struct mt_device *td,
unsigned int application) struct hid_report *report)
{ {
unsigned int application = report->application;
struct mt_application *mt_application; struct mt_application *mt_application;
mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application), mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
...@@ -535,6 +546,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td, ...@@ -535,6 +546,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
mt_application->scantime = DEFAULT_ZERO; mt_application->scantime = DEFAULT_ZERO;
mt_application->raw_cc = DEFAULT_ZERO; mt_application->raw_cc = DEFAULT_ZERO;
mt_application->quirks = td->mtclass.quirks; mt_application->quirks = td->mtclass.quirks;
mt_application->report_id = report->id;
list_add_tail(&mt_application->list, &td->applications); list_add_tail(&mt_application->list, &td->applications);
...@@ -542,19 +554,23 @@ static struct mt_application *mt_allocate_application(struct mt_device *td, ...@@ -542,19 +554,23 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
} }
static struct mt_application *mt_find_application(struct mt_device *td, static struct mt_application *mt_find_application(struct mt_device *td,
unsigned int application) struct hid_report *report)
{ {
unsigned int application = report->application;
struct mt_application *tmp, *mt_application = NULL; struct mt_application *tmp, *mt_application = NULL;
list_for_each_entry(tmp, &td->applications, list) { list_for_each_entry(tmp, &td->applications, list) {
if (application == tmp->application) { if (application == tmp->application) {
mt_application = tmp; if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) ||
break; tmp->report_id == report->id) {
mt_application = tmp;
break;
}
} }
} }
if (!mt_application) if (!mt_application)
mt_application = mt_allocate_application(td, application); mt_application = mt_allocate_application(td, report);
return mt_application; return mt_application;
} }
...@@ -571,7 +587,7 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td, ...@@ -571,7 +587,7 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
return NULL; return NULL;
rdata->report = report; rdata->report = report;
rdata->application = mt_find_application(td, report->application); rdata->application = mt_find_application(td, report);
if (!rdata->application) { if (!rdata->application) {
devm_kfree(&td->hdev->dev, rdata); devm_kfree(&td->hdev->dev, rdata);
...@@ -1561,6 +1577,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -1561,6 +1577,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
case HID_VD_ASUS_CUSTOM_MEDIA_KEYS: case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
suffix = "Custom Media Keys"; suffix = "Custom Media Keys";
break; break;
case HID_DG_PEN:
suffix = "Stylus";
break;
default: default:
suffix = "UNKNOWN"; suffix = "UNKNOWN";
break; break;
...@@ -2022,6 +2041,10 @@ static const struct hid_device_id mt_devices[] = { ...@@ -2022,6 +2041,10 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_SYNAPTICS, 0x8323) }, USB_VENDOR_ID_SYNAPTICS, 0x8323) },
/* Smart Tech panels */
{ .driver_data = MT_CLS_SMART_TECH,
MT_USB_DEVICE(0x0b8c, 0x0092)},
/* Stantum panels */ /* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE, { .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
......
...@@ -534,8 +534,7 @@ static int picolcd_probe(struct hid_device *hdev, ...@@ -534,8 +534,7 @@ static int picolcd_probe(struct hid_device *hdev,
data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL); data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
if (data == NULL) { if (data == NULL) {
hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n"); hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
error = -ENOMEM; return -ENOMEM;
goto err_no_cleanup;
} }
spin_lock_init(&data->lock); spin_lock_init(&data->lock);
...@@ -597,9 +596,6 @@ static int picolcd_probe(struct hid_device *hdev, ...@@ -597,9 +596,6 @@ static int picolcd_probe(struct hid_device *hdev,
hid_hw_stop(hdev); hid_hw_stop(hdev);
err_cleanup_data: err_cleanup_data:
kfree(data); kfree(data);
err_no_cleanup:
hid_set_drvdata(hdev, NULL);
return error; return error;
} }
...@@ -635,7 +631,6 @@ static void picolcd_remove(struct hid_device *hdev) ...@@ -635,7 +631,6 @@ static void picolcd_remove(struct hid_device *hdev)
picolcd_exit_cir(data); picolcd_exit_cir(data);
picolcd_exit_keys(data); picolcd_exit_keys(data);
hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex); mutex_destroy(&data->mutex);
/* Finally, clean up the picolcd data itself */ /* Finally, clean up the picolcd data itself */
kfree(data); kfree(data);
......
...@@ -551,10 +551,14 @@ static void pcmidi_setup_extra_keys( ...@@ -551,10 +551,14 @@ static void pcmidi_setup_extra_keys(
static int pcmidi_set_operational(struct pcmidi_snd *pm) static int pcmidi_set_operational(struct pcmidi_snd *pm)
{ {
int rc;
if (pm->ifnum != 1) if (pm->ifnum != 1)
return 0; /* only set up ONCE for interace 1 */ return 0; /* only set up ONCE for interace 1 */
pcmidi_get_output_report(pm); rc = pcmidi_get_output_report(pm);
if (rc < 0)
return rc;
pcmidi_submit_output_report(pm, 0xc1); pcmidi_submit_output_report(pm, 0xc1);
return 0; return 0;
} }
...@@ -683,7 +687,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) ...@@ -683,7 +687,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
spin_lock_init(&pm->rawmidi_in_lock); spin_lock_init(&pm->rawmidi_in_lock);
init_sustain_timers(pm); init_sustain_timers(pm);
pcmidi_set_operational(pm); err = pcmidi_set_operational(pm);
if (err < 0) {
pk_error("failed to find output report\n");
goto fail_register;
}
/* register it */ /* register it */
err = snd_card_register(card); err = snd_card_register(card);
......
...@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
......
...@@ -742,7 +742,6 @@ static void sensor_hub_remove(struct hid_device *hdev) ...@@ -742,7 +742,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
} }
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
mfd_remove_devices(&hdev->dev); mfd_remove_devices(&hdev->dev);
hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex); mutex_destroy(&data->mutex);
} }
......
...@@ -2811,7 +2811,6 @@ static int sony_input_configured(struct hid_device *hdev, ...@@ -2811,7 +2811,6 @@ static int sony_input_configured(struct hid_device *hdev,
sony_cancel_work_sync(sc); sony_cancel_work_sync(sc);
sony_remove_dev_list(sc); sony_remove_dev_list(sc);
sony_release_device_id(sc); sony_release_device_id(sc);
hid_hw_stop(hdev);
return ret; return ret;
} }
...@@ -2876,6 +2875,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -2876,6 +2875,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/ */
if (!(hdev->claimed & HID_CLAIMED_INPUT)) { if (!(hdev->claimed & HID_CLAIMED_INPUT)) {
hid_err(hdev, "failed to claim input\n"); hid_err(hdev, "failed to claim input\n");
hid_hw_stop(hdev);
return -ENODEV; return -ENODEV;
} }
......
...@@ -252,7 +252,7 @@ static __poll_t hidraw_poll(struct file *file, poll_table *wait) ...@@ -252,7 +252,7 @@ static __poll_t hidraw_poll(struct file *file, poll_table *wait)
poll_wait(file, &list->hidraw->wait, wait); poll_wait(file, &list->hidraw->wait, wait);
if (list->head != list->tail) if (list->head != list->tail)
return EPOLLIN | EPOLLRDNORM; return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
if (!list->hidraw->exist) if (!list->hidraw->exist)
return EPOLLERR | EPOLLHUP; return EPOLLERR | EPOLLHUP;
return 0; return 0;
...@@ -370,7 +370,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ...@@ -370,7 +370,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&minors_lock); mutex_lock(&minors_lock);
dev = hidraw_table[minor]; dev = hidraw_table[minor];
if (!dev) { if (!dev || !dev->exist) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
......
...@@ -169,9 +169,7 @@ static const struct i2c_hid_quirks { ...@@ -169,9 +169,7 @@ static const struct i2c_hid_quirks {
__u16 idProduct; __u16 idProduct;
__u32 quirks; __u32 quirks;
} i2c_hid_quirks[] = { } i2c_hid_quirks[] = {
{ USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752, { USB_VENDOR_ID_WEIDA, HID_ANY_ID,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET | I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
......
...@@ -78,5 +78,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id); ...@@ -78,5 +78,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id);
struct ishtp_device *ish_dev_init(struct pci_dev *pdev); struct ishtp_device *ish_dev_init(struct pci_dev *pdev);
int ish_hw_start(struct ishtp_device *dev); int ish_hw_start(struct ishtp_device *dev);
void ish_device_disable(struct ishtp_device *dev); void ish_device_disable(struct ishtp_device *dev);
int ish_disable_dma(struct ishtp_device *dev);
#endif /* _ISHTP_HW_ISH_H_ */ #endif /* _ISHTP_HW_ISH_H_ */
...@@ -672,7 +672,7 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id) ...@@ -672,7 +672,7 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id)
* *
* Return: 0 for success else error code. * Return: 0 for success else error code.
*/ */
static int ish_disable_dma(struct ishtp_device *dev) int ish_disable_dma(struct ishtp_device *dev)
{ {
unsigned int dma_delay; unsigned int dma_delay;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/suspend.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
...@@ -98,6 +99,11 @@ static const struct pci_device_id ish_invalid_pci_ids[] = { ...@@ -98,6 +99,11 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
{} {}
}; };
static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
{
return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID;
}
/** /**
* ish_probe() - PCI driver probe callback * ish_probe() - PCI driver probe callback
* @pdev: pci device * @pdev: pci device
...@@ -148,7 +154,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -148,7 +154,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* mapping IO device memory */ /* mapping IO device memory */
hw->mem_addr = pcim_iomap_table(pdev)[0]; hw->mem_addr = pcim_iomap_table(pdev)[0];
ishtp->pdev = pdev; ishtp->pdev = pdev;
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
/* request and enable interrupt */ /* request and enable interrupt */
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
...@@ -185,7 +190,6 @@ static void ish_remove(struct pci_dev *pdev) ...@@ -185,7 +190,6 @@ static void ish_remove(struct pci_dev *pdev)
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev); struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
ishtp_bus_remove_all_clients(ishtp_dev, false); ishtp_bus_remove_all_clients(ishtp_dev, false);
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
ish_device_disable(ishtp_dev); ish_device_disable(ishtp_dev);
} }
...@@ -207,17 +211,13 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) ...@@ -207,17 +211,13 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
{ {
struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct pci_dev *pdev = to_pci_dev(ish_resume_device);
struct ishtp_device *dev = pci_get_drvdata(pdev); struct ishtp_device *dev = pci_get_drvdata(pdev);
uint32_t fwsts;
int ret; int ret;
/* Get ISH FW status */ /* Check the NO_D3 flag to distinguish the resume paths */
fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev)); if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) {
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
disable_irq_wake(pdev->irq);
/*
* If currently, in ISH FW, sensor app is loaded or beyond that,
* it means ISH isn't powered off, in this case, send a resume message.
*/
if (fwsts >= FWSTS_SENSOR_APP_LOADED) {
ishtp_send_resume(dev); ishtp_send_resume(dev);
/* Waiting to get resume response */ /* Waiting to get resume response */
...@@ -225,16 +225,20 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) ...@@ -225,16 +225,20 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
ret = wait_event_interruptible_timeout(dev->resume_wait, ret = wait_event_interruptible_timeout(dev->resume_wait,
!dev->resume_flag, !dev->resume_flag,
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
}
/* /*
* If in ISH FW, sensor app isn't loaded yet, or no resume response. * If the flag is not cleared, something is wrong with ISH FW.
* That means this platform is not S0ix compatible, or something is * So on resume, need to go through init sequence again.
* wrong with ISH FW. So on resume, full reboot of ISH processor will */
* happen, so need to go through init sequence again. if (dev->resume_flag)
*/ ish_init(dev);
if (dev->resume_flag) } else {
/*
* Resume from the D3, full reboot of ISH processor will happen,
* so need to go through init sequence again.
*/
ish_init(dev); ish_init(dev);
}
} }
/** /**
...@@ -250,23 +254,43 @@ static int __maybe_unused ish_suspend(struct device *device) ...@@ -250,23 +254,43 @@ static int __maybe_unused ish_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device); struct pci_dev *pdev = to_pci_dev(device);
struct ishtp_device *dev = pci_get_drvdata(pdev); struct ishtp_device *dev = pci_get_drvdata(pdev);
enable_irq_wake(pdev->irq); if (ish_should_enter_d0i3(pdev)) {
/* /*
* If previous suspend hasn't been asnwered then ISH is likely dead, * If previous suspend hasn't been asnwered then ISH is likely
* don't attempt nested notification * dead, don't attempt nested notification
*/ */
if (dev->suspend_flag) if (dev->suspend_flag)
return 0; return 0;
dev->resume_flag = 0; dev->resume_flag = 0;
dev->suspend_flag = 1; dev->suspend_flag = 1;
ishtp_send_suspend(dev); ishtp_send_suspend(dev);
/* 25 ms should be enough for live ISH to flush all IPC buf */ /* 25 ms should be enough for live ISH to flush all IPC buf */
if (dev->suspend_flag) if (dev->suspend_flag)
wait_event_interruptible_timeout(dev->suspend_wait, wait_event_interruptible_timeout(dev->suspend_wait,
!dev->suspend_flag, !dev->suspend_flag,
msecs_to_jiffies(25)); msecs_to_jiffies(25));
if (dev->suspend_flag) {
/*
* It looks like FW halt, clear the DMA bit, and put
* ISH into D3, and FW would reset on resume.
*/
ish_disable_dma(dev);
} else {
/* Set the NO_D3 flag, the ISH would enter D0i3 */
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
enable_irq_wake(pdev->irq);
}
} else {
/*
* Clear the DMA bit before putting ISH into D3,
* or ISH FW would reset automatically.
*/
ish_disable_dma(dev);
}
return 0; return 0;
} }
...@@ -288,7 +312,6 @@ static int __maybe_unused ish_resume(struct device *device) ...@@ -288,7 +312,6 @@ static int __maybe_unused ish_resume(struct device *device)
ish_resume_device = device; ish_resume_device = device;
dev->resume_flag = 1; dev->resume_flag = 1;
disable_irq_wake(pdev->irq);
schedule_work(&resume_work); schedule_work(&resume_work);
return 0; return 0;
......
...@@ -428,7 +428,7 @@ static __poll_t hiddev_poll(struct file *file, poll_table *wait) ...@@ -428,7 +428,7 @@ static __poll_t hiddev_poll(struct file *file, poll_table *wait)
poll_wait(file, &list->hiddev->wait, wait); poll_wait(file, &list->hiddev->wait, wait);
if (list->head != list->tail) if (list->head != list->tail)
return EPOLLIN | EPOLLRDNORM; return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
if (!list->hiddev->exist) if (!list->hiddev->exist)
return EPOLLERR | EPOLLHUP; return EPOLLERR | EPOLLHUP;
return 0; return 0;
......
...@@ -88,7 +88,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev, ...@@ -88,7 +88,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
} }
static int wacom_wac_pen_serial_enforce(struct hid_device *hdev, static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
struct hid_report *report, u8 *raw_data, int size) struct hid_report *report, u8 *raw_data, int report_size)
{ {
struct wacom *wacom = hid_get_drvdata(hdev); struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_wac *wacom_wac = &wacom->wacom_wac;
...@@ -149,7 +149,8 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev, ...@@ -149,7 +149,8 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
if (flush) if (flush)
wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo); wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
else if (insert) else if (insert)
wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo, raw_data, size); wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo,
raw_data, report_size);
return insert && !flush; return insert && !flush;
} }
...@@ -2176,7 +2177,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) ...@@ -2176,7 +2177,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
{ {
struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom_wac->features; struct wacom_features *features = &wacom_wac->features;
char name[WACOM_NAME_MAX]; char name[WACOM_NAME_MAX - 20]; /* Leave some room for suffixes */
/* Generic devices name unspecified */ /* Generic devices name unspecified */
if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
...@@ -2718,14 +2719,12 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -2718,14 +2719,12 @@ static int wacom_probe(struct hid_device *hdev,
wacom_wac->features = *((struct wacom_features *)id->driver_data); wacom_wac->features = *((struct wacom_features *)id->driver_data);
features = &wacom_wac->features; features = &wacom_wac->features;
if (features->check_for_hid_type && features->hid_type != hdev->type) { if (features->check_for_hid_type && features->hid_type != hdev->type)
error = -ENODEV; return -ENODEV;
goto fail;
}
error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL); error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
if (error) if (error)
goto fail; return error;
wacom_wac->hid_data.inputmode = -1; wacom_wac->hid_data.inputmode = -1;
wacom_wac->mode_report = -1; wacom_wac->mode_report = -1;
...@@ -2743,12 +2742,12 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -2743,12 +2742,12 @@ static int wacom_probe(struct hid_device *hdev,
error = hid_parse(hdev); error = hid_parse(hdev);
if (error) { if (error) {
hid_err(hdev, "parse failed\n"); hid_err(hdev, "parse failed\n");
goto fail; return error;
} }
error = wacom_parse_and_register(wacom, false); error = wacom_parse_and_register(wacom, false);
if (error) if (error)
goto fail; return error;
if (hdev->bus == BUS_BLUETOOTH) { if (hdev->bus == BUS_BLUETOOTH) {
error = device_create_file(&hdev->dev, &dev_attr_speed); error = device_create_file(&hdev->dev, &dev_attr_speed);
...@@ -2759,10 +2758,6 @@ static int wacom_probe(struct hid_device *hdev, ...@@ -2759,10 +2758,6 @@ static int wacom_probe(struct hid_device *hdev,
} }
return 0; return 0;
fail:
hid_set_drvdata(hdev, NULL);
return error;
} }
static void wacom_remove(struct hid_device *hdev) static void wacom_remove(struct hid_device *hdev)
...@@ -2791,8 +2786,6 @@ static void wacom_remove(struct hid_device *hdev) ...@@ -2791,8 +2786,6 @@ static void wacom_remove(struct hid_device *hdev)
wacom_release_resources(wacom); wacom_release_resources(wacom);
kfifo_free(&wacom_wac->pen_fifo); kfifo_free(&wacom_wac->pen_fifo);
hid_set_drvdata(hdev, NULL);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -251,7 +251,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom) ...@@ -251,7 +251,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
static int wacom_dtus_irq(struct wacom_wac *wacom) static int wacom_dtus_irq(struct wacom_wac *wacom)
{ {
char *data = wacom->data; unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input; struct input_dev *input = wacom->pen_input;
unsigned short prox, pressure = 0; unsigned short prox, pressure = 0;
...@@ -483,6 +483,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -483,6 +483,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
int ring1 = 0, ring2 = 0; int ring1 = 0, ring2 = 0;
int strip1 = 0, strip2 = 0; int strip1 = 0, strip2 = 0;
bool prox = false; bool prox = false;
bool wrench = false, keyboard = false, mute_touch = false, menu = false,
info = false;
/* pad packets. Works as a second tool and is always in prox */ /* pad packets. Works as a second tool and is always in prox */
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD || if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
...@@ -512,10 +514,32 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -512,10 +514,32 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
keys = ((data[3] & 0x1C) ? 1<<2 : 0) | keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
((data[4] & 0xE0) ? 1<<1 : 0) | ((data[4] & 0xE0) ? 1<<1 : 0) |
((data[4] & 0x07) ? 1<<0 : 0); ((data[4] & 0x07) ? 1<<0 : 0);
keyboard = !!(data[4] & 0xE0);
info = !!(data[3] & 0x1C);
if (features->oPid) {
mute_touch = !!(data[4] & 0x07);
if (mute_touch)
wacom->shared->is_touch_on =
!wacom->shared->is_touch_on;
} else {
wrench = !!(data[4] & 0x07);
}
} else if (features->type == WACOM_27QHD) { } else if (features->type == WACOM_27QHD) {
nkeys = 3; nkeys = 3;
keys = data[2] & 0x07; keys = data[2] & 0x07;
wrench = !!(data[2] & 0x01);
keyboard = !!(data[2] & 0x02);
if (features->oPid) {
mute_touch = !!(data[2] & 0x04);
if (mute_touch)
wacom->shared->is_touch_on =
!wacom->shared->is_touch_on;
} else {
menu = !!(data[2] & 0x04);
}
input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4])); input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6])); input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8])); input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
...@@ -561,6 +585,9 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -561,6 +585,9 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
if (features->type == WACOM_22HD) { if (features->type == WACOM_22HD) {
nkeys = 3; nkeys = 3;
keys = data[9] & 0x07; keys = data[9] & 0x07;
info = !!(data[9] & 0x01);
wrench = !!(data[9] & 0x02);
} }
} else { } else {
buttons = ((data[6] & 0x10) << 5) | buttons = ((data[6] & 0x10) << 5) |
...@@ -572,7 +599,7 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -572,7 +599,7 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
strip2 = ((data[3] & 0x1f) << 8) | data[4]; strip2 = ((data[3] & 0x1f) << 8) | data[4];
} }
prox = (buttons & ~(~0 << nbuttons)) | (keys & ~(~0 << nkeys)) | prox = (buttons & ~(~0U << nbuttons)) | (keys & ~(~0U << nkeys)) |
(ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2; (ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
wacom_report_numbered_buttons(input, nbuttons, buttons); wacom_report_numbered_buttons(input, nbuttons, buttons);
...@@ -580,6 +607,18 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -580,6 +607,18 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
for (i = 0; i < nkeys; i++) for (i = 0; i < nkeys; i++)
input_report_key(input, KEY_PROG1 + i, keys & (1 << i)); input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
input_report_key(input, KEY_BUTTONCONFIG, wrench);
input_report_key(input, KEY_ONSCREEN_KEYBOARD, keyboard);
input_report_key(input, KEY_CONTROLPANEL, menu);
input_report_key(input, KEY_INFO, info);
if (wacom->shared && wacom->shared->touch_input) {
input_report_switch(wacom->shared->touch_input,
SW_MUTE_DEVICE,
!wacom->shared->is_touch_on);
input_sync(wacom->shared->touch_input);
}
input_report_abs(input, ABS_RX, strip1); input_report_abs(input, ABS_RX, strip1);
input_report_abs(input, ABS_RY, strip2); input_report_abs(input, ABS_RY, strip2);
...@@ -1483,6 +1522,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) ...@@ -1483,6 +1522,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET; int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
int y_offset = 2; int y_offset = 2;
if (wacom->shared->has_mute_touch_switch &&
!wacom->shared->is_touch_on) {
if (!wacom->shared->touch_down)
return 0;
}
if (wacom->features.type == WACOM_27QHDT) { if (wacom->features.type == WACOM_27QHDT) {
current_num_contacts = data[63]; current_num_contacts = data[63];
num_contacts_left = 10; num_contacts_left = 10;
...@@ -2051,14 +2096,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -2051,14 +2096,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */ (hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */ hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */
hdev->product == 0x392 || /* Intuos Pro 2 */ hdev->product == 0x392 || /* Intuos Pro 2 */
hdev->product == 0x399)) { /* MobileStudio Pro */ hdev->product == 0x398 || hdev->product == 0x399)) { /* MobileStudio Pro */
value = (field->logical_maximum - value); value = (field->logical_maximum - value);
if (hdev->product == 0x357 || hdev->product == 0x358 || if (hdev->product == 0x357 || hdev->product == 0x358 ||
hdev->product == 0x392) hdev->product == 0x392)
value = wacom_offset_rotation(input, usage, value, 3, 16); value = wacom_offset_rotation(input, usage, value, 3, 16);
else if (hdev->product == 0x34d || hdev->product == 0x34e || else if (hdev->product == 0x34d || hdev->product == 0x34e ||
hdev->product == 0x399) hdev->product == 0x398 || hdev->product == 0x399)
value = wacom_offset_rotation(input, usage, value, 1, 2); value = wacom_offset_rotation(input, usage, value, 1, 2);
} }
else { else {
...@@ -3815,6 +3860,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, ...@@ -3815,6 +3860,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
/* fall through */ /* fall through */
case WACOM_27QHDT: case WACOM_27QHDT:
if (wacom_wac->shared->touch->product == 0x32C ||
wacom_wac->shared->touch->product == 0xF6) {
input_dev->evbit[0] |= BIT_MASK(EV_SW);
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
wacom_wac->shared->has_mute_touch_switch = true;
}
/* fall through */
case MTSCREEN: case MTSCREEN:
case MTTPC: case MTTPC:
case MTTPC_B: case MTTPC_B:
...@@ -4050,6 +4103,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, ...@@ -4050,6 +4103,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit);
__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
__set_bit(KEY_INFO, input_dev->keybit);
if (!features->oPid)
__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
break; break;
...@@ -4058,6 +4117,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, ...@@ -4058,6 +4117,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit);
__set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
if (!features->oPid)
__set_bit(KEY_CONTROLPANEL, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0); input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */ input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0); input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
...@@ -4071,6 +4136,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, ...@@ -4071,6 +4136,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit);
__set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
__set_bit(KEY_INFO, input_dev->keybit);
/* fall through */ /* fall through */
case WACOM_21UX2: case WACOM_21UX2:
......
...@@ -1154,29 +1154,32 @@ int hid_pidff_init(struct hid_device *hid); ...@@ -1154,29 +1154,32 @@ int hid_pidff_init(struct hid_device *hid);
#define hid_pidff_init NULL #define hid_pidff_init NULL
#endif #endif
#define dbg_hid(format, arg...) \ #define dbg_hid(fmt, ...) \
do { \ do { \
if (hid_debug) \ if (hid_debug) \
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \ printk(KERN_DEBUG "%s: " fmt, __FILE__, ##__VA_ARGS__); \
} while (0) } while (0)
#define hid_printk(level, hid, fmt, arg...) \ #define hid_err(hid, fmt, ...) \
dev_printk(level, &(hid)->dev, fmt, ##arg) dev_err(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_emerg(hid, fmt, arg...) \ #define hid_notice(hid, fmt, ...) \
dev_emerg(&(hid)->dev, fmt, ##arg) dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_crit(hid, fmt, arg...) \ #define hid_warn(hid, fmt, ...) \
dev_crit(&(hid)->dev, fmt, ##arg) dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_alert(hid, fmt, arg...) \ #define hid_info(hid, fmt, ...) \
dev_alert(&(hid)->dev, fmt, ##arg) dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_err(hid, fmt, arg...) \ #define hid_dbg(hid, fmt, ...) \
dev_err(&(hid)->dev, fmt, ##arg) dev_dbg(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_notice(hid, fmt, arg...) \
dev_notice(&(hid)->dev, fmt, ##arg) #define hid_err_once(hid, fmt, ...) \
#define hid_warn(hid, fmt, arg...) \ dev_err_once(&(hid)->dev, fmt, ##__VA_ARGS__)
dev_warn(&(hid)->dev, fmt, ##arg) #define hid_notice_once(hid, fmt, ...) \
#define hid_info(hid, fmt, arg...) \ dev_notice_once(&(hid)->dev, fmt, ##__VA_ARGS__)
dev_info(&(hid)->dev, fmt, ##arg) #define hid_warn_once(hid, fmt, ...) \
#define hid_dbg(hid, fmt, arg...) \ dev_warn_once(&(hid)->dev, fmt, ##__VA_ARGS__)
dev_dbg(&(hid)->dev, fmt, ##arg) #define hid_info_once(hid, fmt, ...) \
dev_info_once(&(hid)->dev, fmt, ##__VA_ARGS__)
#define hid_dbg_once(hid, fmt, ...) \
dev_dbg_once(&(hid)->dev, fmt, ##__VA_ARGS__)
#endif #endif
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