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 ...
This commit is contained in:
commit
1ad0bc7894
|
@ -4338,6 +4338,12 @@ S: Maintained
|
|||
F: Documentation/filesystems/cramfs.txt
|
||||
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
|
||||
M: Herbert Xu <herbert@gondor.apana.org.au>
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
|
|
|
@ -273,6 +273,15 @@ config HID_CP2112
|
|||
and gpiochip to expose these functions of the CP2112. The
|
||||
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
|
||||
tristate "Cypress mouse and barcode readers"
|
||||
depends on HID
|
||||
|
|
|
@ -27,6 +27,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
|
|||
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
|
||||
obj-$(CONFIG_HID_APPLE) += hid-apple.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_AUREAL) += hid-aureal.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\")
|
|||
struct apple_sc {
|
||||
unsigned long quirks;
|
||||
unsigned int fn_on;
|
||||
DECLARE_BITMAP(pressed_fn, 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,
|
|||
{
|
||||
struct apple_sc *asc = hid_get_drvdata(hid);
|
||||
const struct apple_key_translation *trans, *table;
|
||||
bool do_translate;
|
||||
u16 code = 0;
|
||||
|
||||
if (usage->code == KEY_FN) {
|
||||
asc->fn_on = !!value;
|
||||
|
@ -189,8 +190,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
|||
}
|
||||
|
||||
if (fnmode) {
|
||||
int do_translate;
|
||||
|
||||
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
|
||||
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
|
||||
table = macbookair_fn_keys;
|
||||
|
@ -202,25 +201,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
|||
trans = apple_find_translation (table, usage->code);
|
||||
|
||||
if (trans) {
|
||||
if (test_bit(usage->code, asc->pressed_fn))
|
||||
do_translate = 1;
|
||||
else if (trans->flags & APPLE_FLAG_FKEY)
|
||||
do_translate = (fnmode == 2 && asc->fn_on) ||
|
||||
(fnmode == 1 && !asc->fn_on);
|
||||
else
|
||||
do_translate = asc->fn_on;
|
||||
if (test_bit(trans->from, input->key))
|
||||
code = trans->from;
|
||||
else if (test_bit(trans->to, input->key))
|
||||
code = trans->to;
|
||||
|
||||
if (do_translate) {
|
||||
if (value)
|
||||
set_bit(usage->code, asc->pressed_fn);
|
||||
else
|
||||
clear_bit(usage->code, asc->pressed_fn);
|
||||
if (!code) {
|
||||
if (trans->flags & APPLE_FLAG_FKEY) {
|
||||
switch (fnmode) {
|
||||
case 1:
|
||||
do_translate = !asc->fn_on;
|
||||
break;
|
||||
case 2:
|
||||
do_translate = asc->fn_on;
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
do_translate = false;
|
||||
}
|
||||
} else {
|
||||
do_translate = asc->fn_on;
|
||||
}
|
||||
|
||||
input_event(input, usage->type, trans->to,
|
||||
value);
|
||||
|
||||
return 1;
|
||||
code = do_translate ? trans->to : trans->from;
|
||||
}
|
||||
|
||||
input_event(input, usage->type, code, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
|
||||
|
|
|
@ -1311,8 +1311,8 @@ u32 hid_field_extract(const struct hid_device *hid, u8 *report,
|
|||
unsigned offset, unsigned n)
|
||||
{
|
||||
if (n > 32) {
|
||||
hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n",
|
||||
n, current->comm);
|
||||
hid_warn_once(hid, "%s() called with n (%d) > 32! (%s)\n",
|
||||
__func__, n, current->comm);
|
||||
n = 32;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ static int cougar_probe(struct hid_device *hdev,
|
|||
error = hid_parse(hdev);
|
||||
if (error) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
goto fail;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
|
||||
|
@ -219,7 +219,7 @@ static int cougar_probe(struct hid_device *hdev,
|
|||
error = hid_hw_start(hdev, connect_mask);
|
||||
if (error) {
|
||||
hid_err(hdev, "hw start failed\n");
|
||||
goto fail;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = cougar_bind_shared_data(hdev, cougar);
|
||||
|
@ -249,8 +249,6 @@ static int cougar_probe(struct hid_device *hdev,
|
|||
|
||||
fail_stop_and_cleanup:
|
||||
hid_hw_stop(hdev);
|
||||
fail:
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
// 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)
|
|||
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[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(0x58, 0x2000),
|
||||
.driver_data = GFRM100 },
|
||||
|
@ -142,7 +136,6 @@ static struct hid_driver gfrm_driver = {
|
|||
.name = "gfrm",
|
||||
.id_table = gfrm_devices,
|
||||
.probe = gfrm_probe,
|
||||
.remove = gfrm_remove,
|
||||
.input_mapping = gfrm_input_mapping,
|
||||
.raw_event = gfrm_raw_event,
|
||||
.input_configured = gfrm_input_configured,
|
||||
|
|
|
@ -314,6 +314,7 @@
|
|||
#define USB_VENDOR_ID_CREATIVELABS 0x041e
|
||||
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
|
||||
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
|
||||
#define USB_DEVICE_ID_CREATIVE_SB0540 0x3100
|
||||
|
||||
#define USB_VENDOR_ID_CVTOUCH 0x1ff7
|
||||
#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
|
||||
|
@ -568,6 +569,7 @@
|
|||
#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_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_VENDOR_ID_HUION 0x256c
|
||||
|
@ -769,7 +771,8 @@
|
|||
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
|
||||
#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_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_SPACETRAVELLER 0xc623
|
||||
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
|
||||
|
|
|
@ -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_mute);
|
||||
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free;
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
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)
|
|||
ret = lg4ff_init(hdev);
|
||||
|
||||
if (ret)
|
||||
goto err_free;
|
||||
goto err_stop;
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop:
|
||||
hid_hw_stop(hdev);
|
||||
err_free:
|
||||
kfree(drv_data);
|
||||
return ret;
|
||||
|
@ -863,8 +866,7 @@ static void lg_remove(struct hid_device *hdev)
|
|||
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
|
||||
if (drv_data->quirks & LG_FF4)
|
||||
lg4ff_deinit(hdev);
|
||||
else
|
||||
hid_hw_stop(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
kfree(drv_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -1477,7 +1477,6 @@ int lg4ff_deinit(struct hid_device *hid)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
hid_hw_stop(hid);
|
||||
drv_data->device_props = NULL;
|
||||
|
||||
kfree(entry);
|
||||
|
|
|
@ -380,9 +380,9 @@ static const char consumer_descriptor[] = {
|
|||
0x75, 0x10, /* REPORT_SIZE (16) */
|
||||
0x95, 0x02, /* REPORT_COUNT (2) */
|
||||
0x15, 0x01, /* LOGICAL_MIN (1) */
|
||||
0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */
|
||||
0x26, 0xFF, 0x02, /* LOGICAL_MAX (767) */
|
||||
0x19, 0x01, /* USAGE_MIN (1) */
|
||||
0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */
|
||||
0x2A, 0xFF, 0x02, /* USAGE_MAX (767) */
|
||||
0x81, 0x00, /* INPUT (Data Ary Abs) */
|
||||
0xC0, /* END_COLLECTION */
|
||||
}; /* */
|
||||
|
@ -959,6 +959,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
|
|||
break;
|
||||
case 0x07:
|
||||
device_type = "eQUAD step 4 Gaming";
|
||||
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
|
||||
break;
|
||||
case 0x08:
|
||||
device_type = "eQUAD step 4 for gamepads";
|
||||
|
@ -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);
|
||||
break;
|
||||
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);
|
||||
workitem.reports_supported |= STD_KEYBOARD;
|
||||
break;
|
||||
|
@ -1734,14 +1740,14 @@ static int logi_dj_probe(struct hid_device *hdev,
|
|||
if (retval < 0) {
|
||||
hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n",
|
||||
__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;
|
||||
|
||||
logi_dj_recv_query_paired_devices_failed:
|
||||
hid_hw_close(hdev);
|
||||
return 0;
|
||||
|
||||
llopen_failed:
|
||||
switch_to_dj_mode_fail:
|
||||
|
@ -1832,9 +1838,17 @@ static const struct hid_device_id logi_dj_receivers[] = {
|
|||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
|
||||
.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) */
|
||||
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},
|
||||
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
|
||||
|
|
|
@ -68,6 +68,7 @@ MODULE_LICENSE("GPL");
|
|||
#define MT_QUIRK_STICKY_FINGERS BIT(16)
|
||||
#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17)
|
||||
#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18)
|
||||
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
|
||||
|
||||
#define MT_INPUTMODE_TOUCHSCREEN 0x02
|
||||
#define MT_INPUTMODE_TOUCHPAD 0x03
|
||||
|
@ -103,6 +104,7 @@ struct mt_usages {
|
|||
struct mt_application {
|
||||
struct list_head list;
|
||||
unsigned int application;
|
||||
unsigned int report_id;
|
||||
struct list_head mt_usages; /* mt usages list */
|
||||
|
||||
__s32 quirks;
|
||||
|
@ -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_GOOGLE 0x0111
|
||||
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
|
||||
#define MT_CLS_SMART_TECH 0x0113
|
||||
|
||||
#define MT_DEFAULT_MAXCONTACT 10
|
||||
#define MT_MAX_MAXCONTACT 250
|
||||
|
@ -263,7 +266,8 @@ static const struct mt_class mt_classes[] = {
|
|||
MT_QUIRK_HOVERING |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
MT_QUIRK_STICKY_FINGERS |
|
||||
MT_QUIRK_WIN8_PTP_BUTTONS },
|
||||
MT_QUIRK_WIN8_PTP_BUTTONS,
|
||||
.export_all_inputs = true },
|
||||
{ .name = MT_CLS_EXPORT_ALL_INPUTS,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE,
|
||||
|
@ -353,6 +357,12 @@ static const struct mt_class mt_classes[] = {
|
|||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
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,
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
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,
|
|||
mt_application->scantime = DEFAULT_ZERO;
|
||||
mt_application->raw_cc = DEFAULT_ZERO;
|
||||
mt_application->quirks = td->mtclass.quirks;
|
||||
mt_application->report_id = report->id;
|
||||
|
||||
list_add_tail(&mt_application->list, &td->applications);
|
||||
|
||||
|
@ -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,
|
||||
unsigned int application)
|
||||
struct hid_report *report)
|
||||
{
|
||||
unsigned int application = report->application;
|
||||
struct mt_application *tmp, *mt_application = NULL;
|
||||
|
||||
list_for_each_entry(tmp, &td->applications, list) {
|
||||
if (application == tmp->application) {
|
||||
mt_application = tmp;
|
||||
break;
|
||||
if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) ||
|
||||
tmp->report_id == report->id) {
|
||||
mt_application = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mt_application)
|
||||
mt_application = mt_allocate_application(td, application);
|
||||
mt_application = mt_allocate_application(td, report);
|
||||
|
||||
return mt_application;
|
||||
}
|
||||
|
@ -571,7 +587,7 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
|
|||
return NULL;
|
||||
|
||||
rdata->report = report;
|
||||
rdata->application = mt_find_application(td, report->application);
|
||||
rdata->application = mt_find_application(td, report);
|
||||
|
||||
if (!rdata->application) {
|
||||
devm_kfree(&td->hdev->dev, rdata);
|
||||
|
@ -1561,6 +1577,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|||
case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
|
||||
suffix = "Custom Media Keys";
|
||||
break;
|
||||
case HID_DG_PEN:
|
||||
suffix = "Stylus";
|
||||
break;
|
||||
default:
|
||||
suffix = "UNKNOWN";
|
||||
break;
|
||||
|
@ -2022,6 +2041,10 @@ static const struct hid_device_id mt_devices[] = {
|
|||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_SYNAPTICS, 0x8323) },
|
||||
|
||||
/* Smart Tech panels */
|
||||
{ .driver_data = MT_CLS_SMART_TECH,
|
||||
MT_USB_DEVICE(0x0b8c, 0x0092)},
|
||||
|
||||
/* Stantum panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
|
||||
|
|
|
@ -534,8 +534,7 @@ static int picolcd_probe(struct hid_device *hdev,
|
|||
data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
|
||||
if (data == NULL) {
|
||||
hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
|
||||
error = -ENOMEM;
|
||||
goto err_no_cleanup;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
@ -597,9 +596,6 @@ static int picolcd_probe(struct hid_device *hdev,
|
|||
hid_hw_stop(hdev);
|
||||
err_cleanup_data:
|
||||
kfree(data);
|
||||
err_no_cleanup:
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -635,7 +631,6 @@ static void picolcd_remove(struct hid_device *hdev)
|
|||
picolcd_exit_cir(data);
|
||||
picolcd_exit_keys(data);
|
||||
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
mutex_destroy(&data->mutex);
|
||||
/* Finally, clean up the picolcd data itself */
|
||||
kfree(data);
|
||||
|
|
|
@ -551,10 +551,14 @@ static void pcmidi_setup_extra_keys(
|
|||
|
||||
static int pcmidi_set_operational(struct pcmidi_snd *pm)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (pm->ifnum != 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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -683,7 +687,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
|
|||
spin_lock_init(&pm->rawmidi_in_lock);
|
||||
|
||||
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 */
|
||||
err = snd_card_register(card);
|
||||
|
|
|
@ -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_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_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_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 },
|
||||
|
|
|
@ -742,7 +742,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
|||
}
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
mfd_remove_devices(&hdev->dev);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
mutex_destroy(&data->mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -2811,7 +2811,6 @@ static int sony_input_configured(struct hid_device *hdev,
|
|||
sony_cancel_work_sync(sc);
|
||||
sony_remove_dev_list(sc);
|
||||
sony_release_device_id(sc);
|
||||
hid_hw_stop(hdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2876,6 +2875,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
*/
|
||||
if (!(hdev->claimed & HID_CLAIMED_INPUT)) {
|
||||
hid_err(hdev, "failed to claim input\n");
|
||||
hid_hw_stop(hdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -252,7 +252,7 @@ static __poll_t hidraw_poll(struct file *file, poll_table *wait)
|
|||
|
||||
poll_wait(file, &list->hidraw->wait, wait);
|
||||
if (list->head != list->tail)
|
||||
return EPOLLIN | EPOLLRDNORM;
|
||||
return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
|
||||
if (!list->hidraw->exist)
|
||||
return EPOLLERR | EPOLLHUP;
|
||||
return 0;
|
||||
|
@ -370,7 +370,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
|||
|
||||
mutex_lock(&minors_lock);
|
||||
dev = hidraw_table[minor];
|
||||
if (!dev) {
|
||||
if (!dev || !dev->exist) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -169,9 +169,7 @@ static const struct i2c_hid_quirks {
|
|||
__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,
|
||||
{ USB_VENDOR_ID_WEIDA, HID_ANY_ID,
|
||||
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
|
||||
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
|
||||
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
|
||||
|
|
|
@ -78,5 +78,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id);
|
|||
struct ishtp_device *ish_dev_init(struct pci_dev *pdev);
|
||||
int ish_hw_start(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_ */
|
||||
|
|
|
@ -672,7 +672,7 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id)
|
|||
*
|
||||
* 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;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#define CREATE_TRACE_POINTS
|
||||
|
@ -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
|
||||
* @pdev: pci device
|
||||
|
@ -148,7 +154,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
/* mapping IO device memory */
|
||||
hw->mem_addr = pcim_iomap_table(pdev)[0];
|
||||
ishtp->pdev = pdev;
|
||||
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
|
||||
|
||||
/* request and enable interrupt */
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
|
@ -185,7 +190,6 @@ static void ish_remove(struct pci_dev *pdev)
|
|||
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
|
||||
|
||||
ishtp_bus_remove_all_clients(ishtp_dev, false);
|
||||
pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
|
||||
ish_device_disable(ishtp_dev);
|
||||
}
|
||||
|
||||
|
@ -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 ishtp_device *dev = pci_get_drvdata(pdev);
|
||||
uint32_t fwsts;
|
||||
int ret;
|
||||
|
||||
/* Get ISH FW status */
|
||||
fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev));
|
||||
/* Check the NO_D3 flag to distinguish the resume paths */
|
||||
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);
|
||||
|
||||
/* Waiting to get resume response */
|
||||
|
@ -225,16 +225,20 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
|
|||
ret = wait_event_interruptible_timeout(dev->resume_wait,
|
||||
!dev->resume_flag,
|
||||
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
|
||||
}
|
||||
|
||||
/*
|
||||
* If in ISH FW, sensor app isn't loaded yet, or no resume response.
|
||||
* That means this platform is not S0ix compatible, or something is
|
||||
* 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)
|
||||
/*
|
||||
* If the flag is not cleared, something is wrong with ISH FW.
|
||||
* So on resume, need to go through init sequence again.
|
||||
*/
|
||||
if (dev->resume_flag)
|
||||
ish_init(dev);
|
||||
} else {
|
||||
/*
|
||||
* Resume from the D3, full reboot of ISH processor will happen,
|
||||
* so need to go through init sequence again.
|
||||
*/
|
||||
ish_init(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,23 +254,43 @@ static int __maybe_unused ish_suspend(struct device *device)
|
|||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct ishtp_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
enable_irq_wake(pdev->irq);
|
||||
/*
|
||||
* If previous suspend hasn't been asnwered then ISH is likely dead,
|
||||
* don't attempt nested notification
|
||||
*/
|
||||
if (dev->suspend_flag)
|
||||
return 0;
|
||||
if (ish_should_enter_d0i3(pdev)) {
|
||||
/*
|
||||
* If previous suspend hasn't been asnwered then ISH is likely
|
||||
* dead, don't attempt nested notification
|
||||
*/
|
||||
if (dev->suspend_flag)
|
||||
return 0;
|
||||
|
||||
dev->resume_flag = 0;
|
||||
dev->suspend_flag = 1;
|
||||
ishtp_send_suspend(dev);
|
||||
dev->resume_flag = 0;
|
||||
dev->suspend_flag = 1;
|
||||
ishtp_send_suspend(dev);
|
||||
|
||||
/* 25 ms should be enough for live ISH to flush all IPC buf */
|
||||
if (dev->suspend_flag)
|
||||
wait_event_interruptible_timeout(dev->suspend_wait,
|
||||
!dev->suspend_flag,
|
||||
msecs_to_jiffies(25));
|
||||
/* 25 ms should be enough for live ISH to flush all IPC buf */
|
||||
if (dev->suspend_flag)
|
||||
wait_event_interruptible_timeout(dev->suspend_wait,
|
||||
!dev->suspend_flag,
|
||||
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;
|
||||
}
|
||||
|
@ -288,7 +312,6 @@ static int __maybe_unused ish_resume(struct device *device)
|
|||
ish_resume_device = device;
|
||||
dev->resume_flag = 1;
|
||||
|
||||
disable_irq_wake(pdev->irq);
|
||||
schedule_work(&resume_work);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -428,7 +428,7 @@ static __poll_t hiddev_poll(struct file *file, poll_table *wait)
|
|||
|
||||
poll_wait(file, &list->hiddev->wait, wait);
|
||||
if (list->head != list->tail)
|
||||
return EPOLLIN | EPOLLRDNORM;
|
||||
return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
|
||||
if (!list->hiddev->exist)
|
||||
return EPOLLERR | EPOLLHUP;
|
||||
return 0;
|
||||
|
|
|
@ -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,
|
||||
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_wac *wacom_wac = &wacom->wacom_wac;
|
||||
|
@ -149,7 +149,8 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
|
|||
if (flush)
|
||||
wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
|
||||
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;
|
||||
}
|
||||
|
@ -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_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 */
|
||||
if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
|
||||
|
@ -2718,14 +2719,12 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
wacom_wac->features = *((struct wacom_features *)id->driver_data);
|
||||
features = &wacom_wac->features;
|
||||
|
||||
if (features->check_for_hid_type && features->hid_type != hdev->type) {
|
||||
error = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
if (features->check_for_hid_type && features->hid_type != hdev->type)
|
||||
return -ENODEV;
|
||||
|
||||
error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
|
||||
if (error)
|
||||
goto fail;
|
||||
return error;
|
||||
|
||||
wacom_wac->hid_data.inputmode = -1;
|
||||
wacom_wac->mode_report = -1;
|
||||
|
@ -2743,12 +2742,12 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
error = hid_parse(hdev);
|
||||
if (error) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
goto fail;
|
||||
return error;
|
||||
}
|
||||
|
||||
error = wacom_parse_and_register(wacom, false);
|
||||
if (error)
|
||||
goto fail;
|
||||
return error;
|
||||
|
||||
if (hdev->bus == BUS_BLUETOOTH) {
|
||||
error = device_create_file(&hdev->dev, &dev_attr_speed);
|
||||
|
@ -2759,10 +2758,6 @@ static int wacom_probe(struct hid_device *hdev,
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void wacom_remove(struct hid_device *hdev)
|
||||
|
@ -2791,8 +2786,6 @@ static void wacom_remove(struct hid_device *hdev)
|
|||
wacom_release_resources(wacom);
|
||||
|
||||
kfifo_free(&wacom_wac->pen_fifo);
|
||||
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
@ -251,7 +251,7 @@ static int wacom_dtu_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;
|
||||
unsigned short prox, pressure = 0;
|
||||
|
||||
|
@ -483,6 +483,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
|
|||
int ring1 = 0, ring2 = 0;
|
||||
int strip1 = 0, strip2 = 0;
|
||||
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 */
|
||||
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
|
||||
|
@ -512,10 +514,32 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
|
|||
keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
|
||||
((data[4] & 0xE0) ? 1<<1 : 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) {
|
||||
nkeys = 3;
|
||||
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_Y, be16_to_cpup((__be16 *)&data[6]));
|
||||
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)
|
|||
if (features->type == WACOM_22HD) {
|
||||
nkeys = 3;
|
||||
keys = data[9] & 0x07;
|
||||
|
||||
info = !!(data[9] & 0x01);
|
||||
wrench = !!(data[9] & 0x02);
|
||||
}
|
||||
} else {
|
||||
buttons = ((data[6] & 0x10) << 5) |
|
||||
|
@ -572,7 +599,7 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
|
|||
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;
|
||||
|
||||
wacom_report_numbered_buttons(input, nbuttons, buttons);
|
||||
|
@ -580,6 +607,18 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
|
|||
for (i = 0; i < nkeys; 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_RY, strip2);
|
||||
|
||||
|
@ -1483,6 +1522,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
|||
int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
|
||||
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) {
|
||||
current_num_contacts = data[63];
|
||||
num_contacts_left = 10;
|
||||
|
@ -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 == 0x357 || hdev->product == 0x358 || /* 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);
|
||||
|
||||
if (hdev->product == 0x357 || hdev->product == 0x358 ||
|
||||
hdev->product == 0x392)
|
||||
value = wacom_offset_rotation(input, usage, value, 3, 16);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
|
@ -3815,6 +3860,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
|||
/* fall through */
|
||||
|
||||
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 MTTPC:
|
||||
case MTTPC_B:
|
||||
|
@ -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_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_THROTTLE, 0, 71, 0, 0);
|
||||
break;
|
||||
|
@ -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_PROG2, 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_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
|
||||
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,
|
|||
__set_bit(KEY_PROG1, input_dev->keybit);
|
||||
__set_bit(KEY_PROG2, 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 */
|
||||
|
||||
case WACOM_21UX2:
|
||||
|
|
|
@ -1154,29 +1154,32 @@ int hid_pidff_init(struct hid_device *hid);
|
|||
#define hid_pidff_init NULL
|
||||
#endif
|
||||
|
||||
#define dbg_hid(format, arg...) \
|
||||
#define dbg_hid(fmt, ...) \
|
||||
do { \
|
||||
if (hid_debug) \
|
||||
printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \
|
||||
printk(KERN_DEBUG "%s: " fmt, __FILE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define hid_printk(level, hid, fmt, arg...) \
|
||||
dev_printk(level, &(hid)->dev, fmt, ##arg)
|
||||
#define hid_emerg(hid, fmt, arg...) \
|
||||
dev_emerg(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_crit(hid, fmt, arg...) \
|
||||
dev_crit(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_alert(hid, fmt, arg...) \
|
||||
dev_alert(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_err(hid, fmt, arg...) \
|
||||
dev_err(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_notice(hid, fmt, arg...) \
|
||||
dev_notice(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_warn(hid, fmt, arg...) \
|
||||
dev_warn(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_info(hid, fmt, arg...) \
|
||||
dev_info(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_dbg(hid, fmt, arg...) \
|
||||
dev_dbg(&(hid)->dev, fmt, ##arg)
|
||||
#define hid_err(hid, fmt, ...) \
|
||||
dev_err(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_notice(hid, fmt, ...) \
|
||||
dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_warn(hid, fmt, ...) \
|
||||
dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_info(hid, fmt, ...) \
|
||||
dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_dbg(hid, fmt, ...) \
|
||||
dev_dbg(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define hid_err_once(hid, fmt, ...) \
|
||||
dev_err_once(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_notice_once(hid, fmt, ...) \
|
||||
dev_notice_once(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#define hid_warn_once(hid, fmt, ...) \
|
||||
dev_warn_once(&(hid)->dev, fmt, ##__VA_ARGS__)
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue