mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-18 08:35:08 +08:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - Fix in i2c-hid driver for Elan touchpad quirk regression (Jim Broadus) - Quirk preventing ASUS Claymore from accidentally suspending whole system (Luke D. Jones) - Updates to the existing FW reporting mechanism, MP2 FW status checks, adding proper power management support for amd-sfh (Basavaraj Natikar) - Regression fix for an issue in HID core that got uncovered by recent USB core cleanup leading to issues when transfer_buffer_length is not in line with wLength (Alan Stern) - Memory leak fix in USB HID core (Anirudh Rayabharam) - Improvement of stylus battery reporting (Dmitry Torokhov) - Power management improvement for Goodix driver (Douglas Anderson) - High-resolution scroll support for Magicmouse devices (José Expósito) - Support for GHLive PS4 dongles (Daniel Nguyen) - Support proper EV_MSC emissions to hid-apple (Vincent Lefevre) * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (31 commits) HID: usbhid: Simplify code in hid_submit_ctrl() HID: usbhid: Fix warning caused by 0-length input reports HID: usbhid: Fix flood of "control queue full" messages HID: sony: Fix more ShanWan clone gamepads to not rumble when plugged in. HID: sony: support for the ghlive ps4 dongles HID: thrustmaster: clean up Makefile and adapt quirks HID: i2c-hid: Fix Elan touchpad regression HID: asus: Prevent Claymore sending suspend event HID: amd_sfh: Add dyndbg prints for debugging HID: amd_sfh: Add support for PM suspend and resume HID: amd_sfh: Move hid probe after sensor is enabled HID: amd_sfh: Add command response to check command status HID: amd_sfh: Fix period data field to enable sensor HID: logitech-hidpp: battery: provide CAPACITY property for newer devices HID: thrustmaster: Fix memory leak in thrustmaster_interrupts() HID: thrustmaster: Fix memory leak in remove HID: thrustmaster: Fix memory leaks in probe HID: elo: update the reference count of the usb device structure HID: logitech-hidpp: Use 'atomic_inc_return' instead of hand-writing it HID: apple: Add missing scan code event for keys handled by hid-apple ...
This commit is contained in:
commit
83ec916974
@ -259,10 +259,11 @@ config HID_PRODIKEYS
|
||||
and some additional multimedia keys.
|
||||
|
||||
config HID_CMEDIA
|
||||
tristate "CMedia CM6533 HID audio jack controls"
|
||||
tristate "CMedia audio chips"
|
||||
depends on HID
|
||||
help
|
||||
Support for CMedia CM6533 HID audio jack controls.
|
||||
Support for CMedia CM6533 HID audio jack controls
|
||||
and HS100B mute buttons.
|
||||
|
||||
config HID_CP2112
|
||||
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
|
||||
@ -952,7 +953,7 @@ config HID_SONY
|
||||
* Buzz controllers
|
||||
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
|
||||
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
|
||||
* Guitar Hero Live PS3 and Wii U guitar dongles
|
||||
* Guitar Hero Live PS3, Wii U and PS4 guitar dongles
|
||||
* Guitar Hero PS3 and PC guitar dongles
|
||||
|
||||
config SONY_FF
|
||||
|
@ -115,7 +115,6 @@ obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o
|
||||
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
|
||||
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
|
||||
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o hid-thrustmaster.o
|
||||
obj-$(CONFIG_HID_TMINIT) += hid-tminit.o
|
||||
obj-$(CONFIG_HID_TIVO) += hid-tivo.o
|
||||
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
|
||||
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "amd_sfh_pcie.h"
|
||||
#include "amd_sfh_hid.h"
|
||||
|
||||
#define AMD_SFH_IDLE_LOOP 200
|
||||
|
||||
struct request_list {
|
||||
struct hid_device *hid;
|
||||
@ -123,14 +122,24 @@ static void amd_sfh_work_buffer(struct work_struct *work)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cli_data->num_hid_devices; i++) {
|
||||
report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i],
|
||||
in_data);
|
||||
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
|
||||
in_data->input_report[i], report_size, 0);
|
||||
if (cli_data->sensor_sts[i] == SENSOR_ENABLED) {
|
||||
report_size = get_input_report
|
||||
(i, cli_data->sensor_idx[i], cli_data->report_id[i], in_data);
|
||||
hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT,
|
||||
in_data->input_report[i], report_size, 0);
|
||||
}
|
||||
}
|
||||
schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
||||
}
|
||||
|
||||
u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
|
||||
{
|
||||
if (mp2->mp2_ops->response)
|
||||
sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts);
|
||||
|
||||
return sensor_sts;
|
||||
}
|
||||
|
||||
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
{
|
||||
struct amd_input_data *in_data = &privdata->in_data;
|
||||
@ -139,8 +148,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
struct device *dev;
|
||||
u32 feature_report_size;
|
||||
u32 input_report_size;
|
||||
int rc, i, status;
|
||||
u8 cl_idx;
|
||||
int rc, i;
|
||||
|
||||
dev = &privdata->pdev->dev;
|
||||
|
||||
@ -155,7 +164,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8,
|
||||
&cl_data->sensor_dma_addr[i],
|
||||
GFP_KERNEL);
|
||||
cl_data->sensor_sts[i] = 0;
|
||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||
cl_data->sensor_requested_cnt[i] = 0;
|
||||
cl_data->cur_hid_dev = i;
|
||||
cl_idx = cl_data->sensor_idx[i];
|
||||
@ -184,7 +193,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP);
|
||||
info.period = AMD_SFH_IDLE_LOOP;
|
||||
info.sensor_idx = cl_idx;
|
||||
info.dma_address = cl_data->sensor_dma_addr[i];
|
||||
|
||||
@ -195,13 +204,27 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
goto cleanup;
|
||||
}
|
||||
rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
|
||||
if (rc)
|
||||
return rc;
|
||||
privdata->mp2_ops->start(privdata, info);
|
||||
cl_data->sensor_sts[i] = 1;
|
||||
status = amd_sfh_wait_for_response
|
||||
(privdata, cl_data->sensor_idx[i], SENSOR_ENABLED);
|
||||
if (status == SENSOR_ENABLED) {
|
||||
cl_data->sensor_sts[i] = SENSOR_ENABLED;
|
||||
rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data);
|
||||
if (rc) {
|
||||
privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
|
||||
status = amd_sfh_wait_for_response
|
||||
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||
if (status != SENSOR_ENABLED)
|
||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||
dev_dbg(dev, "sid 0x%x status 0x%x\n",
|
||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
dev_dbg(dev, "sid 0x%x status 0x%x\n",
|
||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
||||
}
|
||||
schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP));
|
||||
return 0;
|
||||
@ -224,10 +247,19 @@ int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
|
||||
{
|
||||
struct amdtp_cl_data *cl_data = privdata->cl_data;
|
||||
struct amd_input_data *in_data = cl_data->in_data;
|
||||
int i;
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++)
|
||||
privdata->mp2_ops->stop(privdata, i);
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
|
||||
privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
|
||||
status = amd_sfh_wait_for_response
|
||||
(privdata, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||
if (status != SENSOR_ENABLED)
|
||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||
dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x status 0x%x\n",
|
||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
cancel_delayed_work_sync(&cl_data->work);
|
||||
cancel_delayed_work_sync(&cl_data->work_buffer);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -31,6 +32,20 @@ static int sensor_mask_override = -1;
|
||||
module_param_named(sensor_mask, sensor_mask_override, int, 0444);
|
||||
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
|
||||
|
||||
static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
|
||||
{
|
||||
union cmd_response cmd_resp;
|
||||
|
||||
/* Get response with status within a max of 800 ms timeout */
|
||||
if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
|
||||
(cmd_resp.response_v2.response == sensor_sts &&
|
||||
cmd_resp.response_v2.status == 0 && (sid == 0xff ||
|
||||
cmd_resp.response_v2.sensor_id == sid)), 500, 800000))
|
||||
return cmd_resp.response_v2.response;
|
||||
|
||||
return SENSOR_DISABLED;
|
||||
}
|
||||
|
||||
static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
|
||||
{
|
||||
union sfh_cmd_base cmd_base;
|
||||
@ -183,6 +198,7 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = {
|
||||
.start = amd_start_sensor_v2,
|
||||
.stop = amd_stop_sensor_v2,
|
||||
.stop_all = amd_stop_all_sensor_v2,
|
||||
.response = amd_sfh_wait_response_v2,
|
||||
};
|
||||
|
||||
static const struct amd_mp2_ops amd_sfh_ops = {
|
||||
@ -248,6 +264,58 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
|
||||
return amd_sfh_hid_client_init(privdata);
|
||||
}
|
||||
|
||||
static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
|
||||
struct amdtp_cl_data *cl_data = mp2->cl_data;
|
||||
struct amd_mp2_sensor_info info;
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
if (cl_data->sensor_sts[i] == SENSOR_DISABLED) {
|
||||
info.period = AMD_SFH_IDLE_LOOP;
|
||||
info.sensor_idx = cl_data->sensor_idx[i];
|
||||
info.dma_address = cl_data->sensor_dma_addr[i];
|
||||
mp2->mp2_ops->start(mp2, info);
|
||||
status = amd_sfh_wait_for_response
|
||||
(mp2, cl_data->sensor_idx[i], SENSOR_ENABLED);
|
||||
if (status == SENSOR_ENABLED)
|
||||
cl_data->sensor_sts[i] = SENSOR_ENABLED;
|
||||
dev_dbg(dev, "resume sid 0x%x status 0x%x\n",
|
||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
|
||||
struct amdtp_cl_data *cl_data = mp2->cl_data;
|
||||
int i, status;
|
||||
|
||||
for (i = 0; i < cl_data->num_hid_devices; i++) {
|
||||
if (cl_data->sensor_idx[i] != HPD_IDX &&
|
||||
cl_data->sensor_sts[i] == SENSOR_ENABLED) {
|
||||
mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
|
||||
status = amd_sfh_wait_for_response
|
||||
(mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
|
||||
if (status != SENSOR_ENABLED)
|
||||
cl_data->sensor_sts[i] = SENSOR_DISABLED;
|
||||
dev_dbg(dev, "suspend sid 0x%x status 0x%x\n",
|
||||
cl_data->sensor_idx[i], cl_data->sensor_sts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend,
|
||||
amd_mp2_pci_resume);
|
||||
|
||||
static const struct pci_device_id amd_mp2_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) },
|
||||
{ }
|
||||
@ -258,6 +326,7 @@ static struct pci_driver amd_mp2_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = amd_mp2_pci_tbl,
|
||||
.probe = amd_mp2_pci_probe,
|
||||
.driver.pm = &amd_mp2_pm_ops,
|
||||
};
|
||||
module_pci_driver(amd_mp2_pci_driver);
|
||||
|
||||
|
@ -24,14 +24,20 @@
|
||||
#define AMD_C2P_MSG2 0x10508
|
||||
|
||||
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
|
||||
#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4))
|
||||
|
||||
/* MP2 P2C Message Registers */
|
||||
#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */
|
||||
|
||||
#define V2_STATUS 0x2
|
||||
|
||||
#define SENSOR_ENABLED 4
|
||||
#define SENSOR_DISABLED 5
|
||||
|
||||
#define HPD_IDX 16
|
||||
|
||||
#define AMD_SFH_IDLE_LOOP 200
|
||||
|
||||
/* SFH Command register */
|
||||
union sfh_cmd_base {
|
||||
u32 ul;
|
||||
@ -51,6 +57,19 @@ union sfh_cmd_base {
|
||||
} cmd_v2;
|
||||
};
|
||||
|
||||
union cmd_response {
|
||||
u32 resp;
|
||||
struct {
|
||||
u32 status : 2;
|
||||
u32 out_in_c2p : 1;
|
||||
u32 rsvd1 : 1;
|
||||
u32 response : 4;
|
||||
u32 sub_cmd : 8;
|
||||
u32 sensor_id : 6;
|
||||
u32 rsvd2 : 10;
|
||||
} response_v2;
|
||||
};
|
||||
|
||||
union sfh_cmd_param {
|
||||
u32 ul;
|
||||
struct {
|
||||
@ -112,10 +131,14 @@ void amd_stop_all_sensors(struct amd_mp2_dev *privdata);
|
||||
int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id);
|
||||
int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata);
|
||||
int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata);
|
||||
u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
||||
void amd_mp2_suspend(struct amd_mp2_dev *mp2);
|
||||
void amd_mp2_resume(struct amd_mp2_dev *mp2);
|
||||
|
||||
struct amd_mp2_ops {
|
||||
void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info);
|
||||
void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx);
|
||||
void (*stop_all)(struct amd_mp2_dev *privdata);
|
||||
int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts);
|
||||
};
|
||||
#endif
|
||||
|
@ -187,6 +187,15 @@ static const struct apple_key_translation *apple_find_translation(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void input_event_with_scancode(struct input_dev *input,
|
||||
__u8 type, __u16 code, unsigned int hid, __s32 value)
|
||||
{
|
||||
if (type == EV_KEY &&
|
||||
(!test_bit(code, input->key)) == value)
|
||||
input_event(input, EV_MSC, MSC_SCAN, hid);
|
||||
input_event(input, type, code, value);
|
||||
}
|
||||
|
||||
static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
@ -199,7 +208,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
|
||||
if (usage->code == fn_keycode) {
|
||||
asc->fn_on = !!value;
|
||||
input_event(input, usage->type, KEY_FN, value);
|
||||
input_event_with_scancode(input, usage->type, KEY_FN,
|
||||
usage->hid, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -240,7 +250,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
code = do_translate ? trans->to : trans->from;
|
||||
}
|
||||
|
||||
input_event(input, usage->type, code, value);
|
||||
input_event_with_scancode(input, usage->type, code,
|
||||
usage->hid, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -258,8 +269,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
clear_bit(usage->code,
|
||||
asc->pressed_numlock);
|
||||
|
||||
input_event(input, usage->type, trans->to,
|
||||
value);
|
||||
input_event_with_scancode(input, usage->type,
|
||||
trans->to, usage->hid, value);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -270,7 +281,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
if (hid->country == HID_COUNTRY_INTERNATIONAL_ISO) {
|
||||
trans = apple_find_translation(apple_iso_keyboard, usage->code);
|
||||
if (trans) {
|
||||
input_event(input, usage->type, trans->to, value);
|
||||
input_event_with_scancode(input, usage->type,
|
||||
trans->to, usage->hid, value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -279,7 +291,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
if (swap_opt_cmd) {
|
||||
trans = apple_find_translation(swapped_option_cmd_keys, usage->code);
|
||||
if (trans) {
|
||||
input_event(input, usage->type, trans->to, value);
|
||||
input_event_with_scancode(input, usage->type,
|
||||
trans->to, usage->hid, value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -287,7 +300,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
|
||||
if (swap_fn_leftctrl) {
|
||||
trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
|
||||
if (trans) {
|
||||
input_event(input, usage->type, trans->to, value);
|
||||
input_event_with_scancode(input, usage->type,
|
||||
trans->to, usage->hid, value);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -306,8 +320,8 @@ static int apple_event(struct hid_device *hdev, struct hid_field *field,
|
||||
|
||||
if ((asc->quirks & APPLE_INVERT_HWHEEL) &&
|
||||
usage->code == REL_HWHEEL) {
|
||||
input_event(field->hidinput->input, usage->type, usage->code,
|
||||
-value);
|
||||
input_event_with_scancode(field->hidinput->input, usage->type,
|
||||
usage->code, usage->hid, -value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
||||
#define QUIRK_T90CHI BIT(9)
|
||||
#define QUIRK_MEDION_E1239T BIT(10)
|
||||
#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
|
||||
#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
|
||||
|
||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
||||
QUIRK_NO_INIT_REPORTS | \
|
||||
@ -366,6 +367,17 @@ static int asus_raw_event(struct hid_device *hdev,
|
||||
|
||||
}
|
||||
|
||||
if (drvdata->quirks & QUIRK_ROG_CLAYMORE_II_KEYBOARD) {
|
||||
/*
|
||||
* CLAYMORE II keyboard sends this packet when it goes to sleep
|
||||
* this causes the whole system to go into suspend.
|
||||
*/
|
||||
|
||||
if(size == 2 && data[0] == 0x02 && data[1] == 0x00) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1225,6 +1237,9 @@ static const struct hid_device_id asus_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2),
|
||||
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
|
||||
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
||||
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
|
||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
||||
|
@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* HID driver for CMedia CM6533 audio jack controls
|
||||
* and HS100B mute buttons
|
||||
*
|
||||
* Copyright (C) 2015 Ben Chen <ben_chen@bizlinktech.com>
|
||||
* Copyright (C) 2021 Thomas Weißschuh <linux@weissschuh.net>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
@ -11,13 +13,53 @@
|
||||
#include "hid-ids.h"
|
||||
|
||||
MODULE_AUTHOR("Ben Chen");
|
||||
MODULE_DESCRIPTION("CM6533 HID jack controls");
|
||||
MODULE_AUTHOR("Thomas Weißschuh");
|
||||
MODULE_DESCRIPTION("CM6533 HID jack controls and HS100B mute button");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define CM6533_JD_TYPE_COUNT 1
|
||||
#define CM6533_JD_RAWEV_LEN 16
|
||||
#define CM6533_JD_SFX_OFFSET 8
|
||||
|
||||
#define HS100B_RDESC_ORIG_SIZE 60
|
||||
|
||||
/* Fixed report descriptor of HS-100B audio chip
|
||||
* Bit 4 is an abolute Microphone mute usage instead of being unassigned.
|
||||
*/
|
||||
static __u8 hs100b_rdesc_fixed[] = {
|
||||
0x05, 0x0C, /* Usage Page (Consumer), */
|
||||
0x09, 0x01, /* Usage (Consumer Control), */
|
||||
0xA1, 0x01, /* Collection (Application), */
|
||||
0x15, 0x00, /* Logical Minimum (0), */
|
||||
0x25, 0x01, /* Logical Maximum (1), */
|
||||
0x09, 0xE9, /* Usage (Volume Inc), */
|
||||
0x09, 0xEA, /* Usage (Volume Dec), */
|
||||
0x75, 0x01, /* Report Size (1), */
|
||||
0x95, 0x02, /* Report Count (2), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0xE2, /* Usage (Mute), */
|
||||
0x95, 0x01, /* Report Count (1), */
|
||||
0x81, 0x06, /* Input (Variable, Relative), */
|
||||
0x05, 0x0B, /* Usage Page (Telephony), */
|
||||
0x09, 0x2F, /* Usage (2Fh), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x20, /* Usage (20h), */
|
||||
0x81, 0x06, /* Input (Variable, Relative), */
|
||||
0x05, 0x0C, /* Usage Page (Consumer), */
|
||||
0x09, 0x00, /* Usage (00h), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
|
||||
0x09, 0x00, /* Usage (00h), */
|
||||
0x75, 0x08, /* Report Size (8), */
|
||||
0x95, 0x03, /* Report Count (3), */
|
||||
0x81, 0x02, /* Input (Variable), */
|
||||
0x09, 0x00, /* Usage (00h), */
|
||||
0x95, 0x04, /* Report Count (4), */
|
||||
0x91, 0x02, /* Output (Variable), */
|
||||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
*CM6533 audio jack HID raw events:
|
||||
@ -156,5 +198,49 @@ static struct hid_driver cmhid_driver = {
|
||||
.remove = cmhid_remove,
|
||||
.input_mapping = cmhid_input_mapping,
|
||||
};
|
||||
module_hid_driver(cmhid_driver);
|
||||
|
||||
static __u8 *cmhid_hs100b_report_fixup(struct hid_device *hid, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize == HS100B_RDESC_ORIG_SIZE) {
|
||||
hid_info(hid, "Fixing CMedia HS-100B report descriptor\n");
|
||||
rdesc = hs100b_rdesc_fixed;
|
||||
*rsize = sizeof(hs100b_rdesc_fixed);
|
||||
}
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id cmhid_hs100b_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_HS100B) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, cmhid_hs100b_devices);
|
||||
|
||||
static struct hid_driver cmhid_hs100b_driver = {
|
||||
.name = "cmedia_hs100b",
|
||||
.id_table = cmhid_hs100b_devices,
|
||||
.report_fixup = cmhid_hs100b_report_fixup,
|
||||
};
|
||||
|
||||
static int cmedia_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hid_register_driver(&cmhid_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hid_register_driver(&cmhid_hs100b_driver);
|
||||
if (ret)
|
||||
hid_unregister_driver(&cmhid_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(cmedia_init);
|
||||
|
||||
static void cmedia_exit(void)
|
||||
{
|
||||
hid_unregister_driver(&cmhid_driver);
|
||||
hid_unregister_driver(&cmhid_hs100b_driver);
|
||||
}
|
||||
module_exit(cmedia_exit);
|
||||
|
@ -228,13 +228,15 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
struct elo_priv *priv;
|
||||
int ret;
|
||||
struct usb_device *udev;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_DELAYED_WORK(&priv->work, elo_work);
|
||||
priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
|
||||
udev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
|
||||
priv->usbdev = usb_get_dev(udev);
|
||||
|
||||
hid_set_drvdata(hdev, priv);
|
||||
|
||||
@ -265,6 +267,8 @@ static void elo_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct elo_priv *priv = hid_get_drvdata(hdev);
|
||||
|
||||
usb_put_dev(priv->usbdev);
|
||||
|
||||
hid_hw_stop(hdev);
|
||||
cancel_delayed_work_sync(&priv->work);
|
||||
kfree(priv);
|
||||
|
@ -41,9 +41,6 @@
|
||||
#define USB_VENDOR_ID_ACTIONSTAR 0x2101
|
||||
#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011
|
||||
|
||||
#define USB_VENDOR_ID_ACTIVISION 0x1430
|
||||
#define USB_DEVICE_ID_ACTIVISION_GUITAR_DONGLE 0x474c
|
||||
|
||||
#define USB_VENDOR_ID_ADS_TECH 0x06e1
|
||||
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
|
||||
|
||||
@ -197,6 +194,7 @@
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6
|
||||
#define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b
|
||||
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
|
||||
|
||||
#define USB_VENDOR_ID_ATEN 0x0557
|
||||
@ -292,6 +290,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_CMEDIA 0x0d8c
|
||||
#define USB_DEVICE_ID_CM109 0x000e
|
||||
#define USB_DEVICE_ID_CMEDIA_HS100B 0x0014
|
||||
#define USB_DEVICE_ID_CM6533 0x0022
|
||||
|
||||
#define USB_VENDOR_ID_CODEMERCS 0x07c0
|
||||
@ -1018,6 +1017,10 @@
|
||||
#define USB_VENDOR_ID_REALTEK 0x0bda
|
||||
#define USB_DEVICE_ID_REALTEK_READER 0x0152
|
||||
|
||||
#define USB_VENDOR_ID_REDOCTANE 0x1430
|
||||
#define USB_DEVICE_ID_REDOCTANE_GUITAR_DONGLE 0x474c
|
||||
#define USB_DEVICE_ID_REDOCTANE_PS4_GHLIVE_DONGLE 0x07bb
|
||||
|
||||
#define USB_VENDOR_ID_RETROUSB 0xf000
|
||||
#define USB_DEVICE_ID_RETROUSB_SNES_RETROPAD 0x0003
|
||||
#define USB_DEVICE_ID_RETROUSB_SNES_RETROPORT 0x00f1
|
||||
|
@ -419,8 +419,6 @@ static int hidinput_get_battery_property(struct power_supply *psy,
|
||||
|
||||
if (dev->battery_status == HID_BATTERY_UNKNOWN)
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
else if (dev->battery_capacity == 100)
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
break;
|
||||
|
@ -1331,6 +1331,43 @@ static int hidpp20_battery_get_battery_voltage(struct hidpp_device *hidpp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hidpp20_map_battery_capacity(struct hid_device *hid_dev, int voltage)
|
||||
{
|
||||
/* NB: This voltage curve doesn't necessarily map perfectly to all
|
||||
* devices that implement the BATTERY_VOLTAGE feature. This is because
|
||||
* there are a few devices that use different battery technology.
|
||||
*/
|
||||
|
||||
static const int voltages[] = {
|
||||
4186, 4156, 4143, 4133, 4122, 4113, 4103, 4094, 4086, 4075,
|
||||
4067, 4059, 4051, 4043, 4035, 4027, 4019, 4011, 4003, 3997,
|
||||
3989, 3983, 3976, 3969, 3961, 3955, 3949, 3942, 3935, 3929,
|
||||
3922, 3916, 3909, 3902, 3896, 3890, 3883, 3877, 3870, 3865,
|
||||
3859, 3853, 3848, 3842, 3837, 3833, 3828, 3824, 3819, 3815,
|
||||
3811, 3808, 3804, 3800, 3797, 3793, 3790, 3787, 3784, 3781,
|
||||
3778, 3775, 3772, 3770, 3767, 3764, 3762, 3759, 3757, 3754,
|
||||
3751, 3748, 3744, 3741, 3737, 3734, 3730, 3726, 3724, 3720,
|
||||
3717, 3714, 3710, 3706, 3702, 3697, 3693, 3688, 3683, 3677,
|
||||
3671, 3666, 3662, 3658, 3654, 3646, 3633, 3612, 3579, 3537
|
||||
};
|
||||
|
||||
int i;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(voltages) != 100);
|
||||
|
||||
if (unlikely(voltage < 3500 || voltage >= 5000))
|
||||
hid_warn_once(hid_dev,
|
||||
"%s: possibly using the wrong voltage curve\n",
|
||||
__func__);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(voltages); i++) {
|
||||
if (voltage >= voltages[i])
|
||||
return ARRAY_SIZE(voltages) - i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp)
|
||||
{
|
||||
u8 feature_type;
|
||||
@ -1354,6 +1391,8 @@ static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp)
|
||||
|
||||
hidpp->battery.status = status;
|
||||
hidpp->battery.voltage = voltage;
|
||||
hidpp->battery.capacity = hidpp20_map_battery_capacity(hidpp->hid_dev,
|
||||
voltage);
|
||||
hidpp->battery.level = level;
|
||||
hidpp->battery.charge_type = charge_type;
|
||||
hidpp->battery.online = status != POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
@ -1378,6 +1417,8 @@ static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp,
|
||||
|
||||
if (voltage != hidpp->battery.voltage || status != hidpp->battery.status) {
|
||||
hidpp->battery.voltage = voltage;
|
||||
hidpp->battery.capacity = hidpp20_map_battery_capacity(hidpp->hid_dev,
|
||||
voltage);
|
||||
hidpp->battery.status = status;
|
||||
hidpp->battery.level = level;
|
||||
hidpp->battery.charge_type = charge_type;
|
||||
@ -2240,11 +2281,10 @@ static int hidpp_ff_queue_work(struct hidpp_ff_private_data *data, int effect_id
|
||||
wd->size = size;
|
||||
memcpy(wd->params, params, size);
|
||||
|
||||
atomic_inc(&data->workqueue_size);
|
||||
s = atomic_inc_return(&data->workqueue_size);
|
||||
queue_work(data->wq, &wd->work);
|
||||
|
||||
/* warn about excessive queue size */
|
||||
s = atomic_read(&data->workqueue_size);
|
||||
if (s >= 20 && s % 20 == 0)
|
||||
hid_warn(data->hidpp->hid_dev, "Force feedback command queue contains %d commands, causing substantial delays!", s);
|
||||
|
||||
@ -3717,7 +3757,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
||||
num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3;
|
||||
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
|
||||
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE)
|
||||
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ||
|
||||
hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
|
||||
battery_props[num_battery_props++] =
|
||||
POWER_SUPPLY_PROP_CAPACITY;
|
||||
|
||||
|
@ -68,6 +68,10 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
|
||||
#define TOUCH_STATE_START 0x30
|
||||
#define TOUCH_STATE_DRAG 0x40
|
||||
|
||||
/* Number of high-resolution events for each low-resolution detent. */
|
||||
#define SCROLL_HR_STEPS 10
|
||||
#define SCROLL_HR_MULT (120 / SCROLL_HR_STEPS)
|
||||
#define SCROLL_HR_THRESHOLD 90 /* units */
|
||||
#define SCROLL_ACCEL_DEFAULT 7
|
||||
|
||||
/* Touch surface information. Dimension is in hundredths of a mm, min and max
|
||||
@ -126,7 +130,11 @@ struct magicmouse_sc {
|
||||
short y;
|
||||
short scroll_x;
|
||||
short scroll_y;
|
||||
short scroll_x_hr;
|
||||
short scroll_y_hr;
|
||||
u8 size;
|
||||
bool scroll_x_active;
|
||||
bool scroll_y_active;
|
||||
} touches[16];
|
||||
int tracking_ids[16];
|
||||
|
||||
@ -248,12 +256,20 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
unsigned long now = jiffies;
|
||||
int step_x = msc->touches[id].scroll_x - x;
|
||||
int step_y = msc->touches[id].scroll_y - y;
|
||||
int step_hr = ((64 - (int)scroll_speed) * msc->scroll_accel) /
|
||||
SCROLL_HR_STEPS;
|
||||
int step_x_hr = msc->touches[id].scroll_x_hr - x;
|
||||
int step_y_hr = msc->touches[id].scroll_y_hr - y;
|
||||
|
||||
/* Calculate and apply the scroll motion. */
|
||||
switch (state) {
|
||||
case TOUCH_STATE_START:
|
||||
msc->touches[id].scroll_x = x;
|
||||
msc->touches[id].scroll_y = y;
|
||||
msc->touches[id].scroll_x_hr = x;
|
||||
msc->touches[id].scroll_y_hr = y;
|
||||
msc->touches[id].scroll_x_active = false;
|
||||
msc->touches[id].scroll_y_active = false;
|
||||
|
||||
/* Reset acceleration after half a second. */
|
||||
if (scroll_acceleration && time_before(now,
|
||||
@ -280,6 +296,40 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
msc->scroll_jiffies = now;
|
||||
input_report_rel(input, REL_WHEEL, step_y);
|
||||
}
|
||||
|
||||
if (!msc->touches[id].scroll_x_active &&
|
||||
abs(step_x_hr) > SCROLL_HR_THRESHOLD) {
|
||||
msc->touches[id].scroll_x_active = true;
|
||||
msc->touches[id].scroll_x_hr = x;
|
||||
step_x_hr = 0;
|
||||
}
|
||||
|
||||
step_x_hr /= step_hr;
|
||||
if (step_x_hr != 0 &&
|
||||
msc->touches[id].scroll_x_active) {
|
||||
msc->touches[id].scroll_x_hr -= step_x_hr *
|
||||
step_hr;
|
||||
input_report_rel(input,
|
||||
REL_HWHEEL_HI_RES,
|
||||
-step_x_hr * SCROLL_HR_MULT);
|
||||
}
|
||||
|
||||
if (!msc->touches[id].scroll_y_active &&
|
||||
abs(step_y_hr) > SCROLL_HR_THRESHOLD) {
|
||||
msc->touches[id].scroll_y_active = true;
|
||||
msc->touches[id].scroll_y_hr = y;
|
||||
step_y_hr = 0;
|
||||
}
|
||||
|
||||
step_y_hr /= step_hr;
|
||||
if (step_y_hr != 0 &&
|
||||
msc->touches[id].scroll_y_active) {
|
||||
msc->touches[id].scroll_y_hr -= step_y_hr *
|
||||
step_hr;
|
||||
input_report_rel(input,
|
||||
REL_WHEEL_HI_RES,
|
||||
step_y_hr * SCROLL_HR_MULT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -481,6 +531,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
if (emulate_scroll_wheel) {
|
||||
__set_bit(REL_WHEEL, input->relbit);
|
||||
__set_bit(REL_HWHEEL, input->relbit);
|
||||
__set_bit(REL_WHEEL_HI_RES, input->relbit);
|
||||
__set_bit(REL_HWHEEL_HI_RES, input->relbit);
|
||||
}
|
||||
} else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
/* setting the device name to ensure the same driver settings
|
||||
|
@ -662,8 +662,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_TMINIT)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65d) },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_HID_TIVO)
|
||||
|
@ -11,8 +11,9 @@
|
||||
* Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
|
||||
* Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com>
|
||||
* Copyright (c) 2018 Todd Kelner
|
||||
* Copyright (c) 2020 Pascal Giard <pascal.giard@etsmtl.ca>
|
||||
* Copyright (c) 2020-2021 Pascal Giard <pascal.giard@etsmtl.ca>
|
||||
* Copyright (c) 2020 Sanjay Govind <sanjay.govind9@gmail.com>
|
||||
* Copyright (c) 2021 Daniel Nguyen <daniel.nguyen.1@ens.etsmtl.ca>
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -62,6 +63,7 @@
|
||||
#define SHANWAN_GAMEPAD BIT(16)
|
||||
#define GH_GUITAR_CONTROLLER BIT(17)
|
||||
#define GHL_GUITAR_PS3WIIU BIT(18)
|
||||
#define GHL_GUITAR_PS4 BIT(19)
|
||||
|
||||
#define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)
|
||||
#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT)
|
||||
@ -85,18 +87,27 @@
|
||||
#define NSG_MRXU_MAX_X 1667
|
||||
#define NSG_MRXU_MAX_Y 1868
|
||||
|
||||
#define GHL_GUITAR_POKE_INTERVAL 10 /* In seconds */
|
||||
/* The PS3/Wii U dongles require a poke every 10 seconds, but the PS4
|
||||
* requires one every 8 seconds. Using 8 seconds for all for simplicity.
|
||||
*/
|
||||
#define GHL_GUITAR_POKE_INTERVAL 8 /* In seconds */
|
||||
#define GUITAR_TILT_USAGE 44
|
||||
|
||||
/* Magic value and data taken from GHLtarUtility:
|
||||
/* Magic data taken from GHLtarUtility:
|
||||
* https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs
|
||||
* Note: The Wii U and PS3 dongles happen to share the same!
|
||||
*/
|
||||
static const u16 ghl_ps3wiiu_magic_value = 0x201;
|
||||
static const char ghl_ps3wiiu_magic_data[] = {
|
||||
0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Magic data for the PS4 dongles sniffed with a USB protocol
|
||||
* analyzer.
|
||||
*/
|
||||
static const char ghl_ps4_magic_data[] = {
|
||||
0x30, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* PS/3 Motion controller */
|
||||
static u8 motion_rdesc[] = {
|
||||
0x05, 0x01, /* Usage Page (Desktop), */
|
||||
@ -642,14 +653,14 @@ static void ghl_magic_poke(struct timer_list *t)
|
||||
hid_err(sc->hdev, "usb_submit_urb failed: %d", ret);
|
||||
}
|
||||
|
||||
static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
|
||||
static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev,
|
||||
const char ghl_magic_data[], u16 poke_size)
|
||||
{
|
||||
struct usb_ctrlrequest *cr;
|
||||
u16 poke_size;
|
||||
u8 *databuf;
|
||||
unsigned int pipe;
|
||||
u16 ghl_magic_value = (((HID_OUTPUT_REPORT + 1) << 8) | ghl_magic_data[0]);
|
||||
|
||||
poke_size = ARRAY_SIZE(ghl_ps3wiiu_magic_data);
|
||||
pipe = usb_sndctrlpipe(usbdev, 0);
|
||||
|
||||
cr = devm_kzalloc(&sc->hdev->dev, sizeof(*cr), GFP_ATOMIC);
|
||||
@ -663,10 +674,10 @@ static int ghl_init_urb(struct sony_sc *sc, struct usb_device *usbdev)
|
||||
cr->bRequestType =
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT;
|
||||
cr->bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value);
|
||||
cr->wValue = cpu_to_le16(ghl_magic_value);
|
||||
cr->wIndex = 0;
|
||||
cr->wLength = cpu_to_le16(poke_size);
|
||||
memcpy(databuf, ghl_ps3wiiu_magic_data, poke_size);
|
||||
memcpy(databuf, ghl_magic_data, poke_size);
|
||||
usb_fill_control_urb(
|
||||
sc->ghl_urb, usbdev, pipe,
|
||||
(unsigned char *) cr, databuf, poke_size,
|
||||
@ -2974,7 +2985,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
if (!strcmp(hdev->name, "FutureMax Dance Mat"))
|
||||
quirks |= FUTUREMAX_DANCE_MAT;
|
||||
|
||||
if (!strcmp(hdev->name, "SHANWAN PS3 GamePad"))
|
||||
if (!strcmp(hdev->name, "SHANWAN PS3 GamePad") ||
|
||||
!strcmp(hdev->name, "ShanWan PS(R) Ga`epad"))
|
||||
quirks |= SHANWAN_GAMEPAD;
|
||||
|
||||
sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL);
|
||||
@ -3030,11 +3042,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
|
||||
if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
|
||||
sc->ghl_urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!sc->ghl_urb)
|
||||
return -ENOMEM;
|
||||
ret = ghl_init_urb(sc, usbdev);
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU)
|
||||
ret = ghl_init_urb(sc, usbdev, ghl_ps3wiiu_magic_data,
|
||||
ARRAY_SIZE(ghl_ps3wiiu_magic_data));
|
||||
else if (sc->quirks & GHL_GUITAR_PS4)
|
||||
ret = ghl_init_urb(sc, usbdev, ghl_ps4_magic_data,
|
||||
ARRAY_SIZE(ghl_ps4_magic_data));
|
||||
if (ret) {
|
||||
hid_err(hdev, "error preparing URB\n");
|
||||
return ret;
|
||||
@ -3052,7 +3070,7 @@ static void sony_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct sony_sc *sc = hid_get_drvdata(hdev);
|
||||
|
||||
if (sc->quirks & GHL_GUITAR_PS3WIIU) {
|
||||
if (sc->quirks & (GHL_GUITAR_PS3WIIU | GHL_GUITAR_PS4)) {
|
||||
del_timer_sync(&sc->ghl_poke_timer);
|
||||
usb_free_urb(sc->ghl_urb);
|
||||
}
|
||||
@ -3172,11 +3190,14 @@ static const struct hid_device_id sony_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE),
|
||||
.driver_data = GHL_GUITAR_PS3WIIU | GH_GUITAR_CONTROLLER },
|
||||
/* Guitar Hero PC Guitar Dongle */
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ACTIVISION, USB_DEVICE_ID_ACTIVISION_GUITAR_DONGLE),
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_GUITAR_DONGLE),
|
||||
.driver_data = GH_GUITAR_CONTROLLER },
|
||||
/* Guitar Hero PS3 World Tour Guitar Dongle */
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY_RHYTHM, USB_DEVICE_ID_SONY_PS3_GUITAR_DONGLE),
|
||||
.driver_data = GH_GUITAR_CONTROLLER },
|
||||
/* Guitar Hero Live PS4 guitar dongles */
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_REDOCTANE, USB_DEVICE_ID_REDOCTANE_PS4_GHLIVE_DONGLE),
|
||||
.driver_data = GHL_GUITAR_PS4 | GH_GUITAR_CONTROLLER },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, sony_devices);
|
||||
|
@ -173,6 +173,7 @@ static void thrustmaster_interrupts(struct hid_device *hdev)
|
||||
|
||||
if (ret) {
|
||||
hid_err(hdev, "setup data couldn't be sent\n");
|
||||
kfree(send_buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -253,6 +254,7 @@ static void thrustmaster_remove(struct hid_device *hdev)
|
||||
|
||||
usb_kill_urb(tm_wheel->urb);
|
||||
|
||||
kfree(tm_wheel->change_request);
|
||||
kfree(tm_wheel->response);
|
||||
kfree(tm_wheel->model_request);
|
||||
usb_free_urb(tm_wheel->urb);
|
||||
@ -336,11 +338,14 @@ static int thrustmaster_probe(struct hid_device *hdev, const struct hid_device_i
|
||||
);
|
||||
|
||||
ret = usb_submit_urb(tm_wheel->urb, GFP_ATOMIC);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
hid_err(hdev, "Error %d while submitting the URB. I am unable to initialize this wheel...\n", ret);
|
||||
goto error6;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error6: kfree(tm_wheel->change_request);
|
||||
error5: kfree(tm_wheel->response);
|
||||
error4: kfree(tm_wheel->model_request);
|
||||
error3: usb_free_urb(tm_wheel->urb);
|
||||
|
@ -171,8 +171,6 @@ static const struct i2c_hid_quirks {
|
||||
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
|
||||
{ I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118,
|
||||
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
|
||||
{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
|
||||
I2C_HID_QUIRK_BOGUS_IRQ },
|
||||
{ USB_VENDOR_ID_ALPS_JP, HID_ANY_ID,
|
||||
I2C_HID_QUIRK_RESET_ON_RESUME },
|
||||
{ I2C_VENDOR_ID_SYNAPTICS, I2C_PRODUCT_ID_SYNAPTICS_SYNA2393,
|
||||
@ -183,7 +181,8 @@ static const struct i2c_hid_quirks {
|
||||
* Sending the wakeup after reset actually break ELAN touchscreen controller
|
||||
*/
|
||||
{ USB_VENDOR_ID_ELAN, HID_ANY_ID,
|
||||
I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET },
|
||||
I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET |
|
||||
I2C_HID_QUIRK_BOGUS_IRQ },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -26,28 +26,29 @@ struct i2c_hid_of_goodix {
|
||||
struct i2chid_ops ops;
|
||||
|
||||
struct regulator *vdd;
|
||||
struct notifier_block nb;
|
||||
struct mutex regulator_mutex;
|
||||
struct gpio_desc *reset_gpio;
|
||||
const struct goodix_i2c_hid_timing_data *timings;
|
||||
};
|
||||
|
||||
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
|
||||
static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix,
|
||||
bool regulator_just_turned_on)
|
||||
{
|
||||
struct i2c_hid_of_goodix *ihid_goodix =
|
||||
container_of(ops, struct i2c_hid_of_goodix, ops);
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(ihid_goodix->vdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ihid_goodix->timings->post_power_delay_ms)
|
||||
if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms)
|
||||
msleep(ihid_goodix->timings->post_power_delay_ms);
|
||||
|
||||
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
|
||||
if (ihid_goodix->timings->post_gpio_reset_delay_ms)
|
||||
msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
|
||||
{
|
||||
struct i2c_hid_of_goodix *ihid_goodix =
|
||||
container_of(ops, struct i2c_hid_of_goodix, ops);
|
||||
|
||||
return regulator_enable(ihid_goodix->vdd);
|
||||
}
|
||||
|
||||
static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
|
||||
@ -55,20 +56,54 @@ static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
|
||||
struct i2c_hid_of_goodix *ihid_goodix =
|
||||
container_of(ops, struct i2c_hid_of_goodix, ops);
|
||||
|
||||
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
|
||||
regulator_disable(ihid_goodix->vdd);
|
||||
}
|
||||
|
||||
static int ihid_goodix_vdd_notify(struct notifier_block *nb,
|
||||
unsigned long event,
|
||||
void *ignored)
|
||||
{
|
||||
struct i2c_hid_of_goodix *ihid_goodix =
|
||||
container_of(nb, struct i2c_hid_of_goodix, nb);
|
||||
int ret = NOTIFY_OK;
|
||||
|
||||
mutex_lock(&ihid_goodix->regulator_mutex);
|
||||
|
||||
switch (event) {
|
||||
case REGULATOR_EVENT_PRE_DISABLE:
|
||||
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
|
||||
break;
|
||||
|
||||
case REGULATOR_EVENT_ENABLE:
|
||||
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
|
||||
break;
|
||||
|
||||
case REGULATOR_EVENT_ABORT_DISABLE:
|
||||
goodix_i2c_hid_deassert_reset(ihid_goodix, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = NOTIFY_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ihid_goodix->regulator_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_hid_of_goodix_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_hid_of_goodix *ihid_goodix;
|
||||
|
||||
int ret;
|
||||
ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
|
||||
GFP_KERNEL);
|
||||
if (!ihid_goodix)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ihid_goodix->regulator_mutex);
|
||||
|
||||
ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
|
||||
ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
|
||||
|
||||
@ -84,6 +119,37 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
|
||||
|
||||
ihid_goodix->timings = device_get_match_data(&client->dev);
|
||||
|
||||
/*
|
||||
* We need to control the "reset" line in lockstep with the regulator
|
||||
* actually turning on an off instead of just when we make the request.
|
||||
* This matters if the regulator is shared with another consumer.
|
||||
* - If the regulator is off then we must assert reset. The reset
|
||||
* line is active low and on some boards it could cause a current
|
||||
* leak if left high.
|
||||
* - If the regulator is on then we don't want reset asserted for very
|
||||
* long. Holding the controller in reset apparently draws extra
|
||||
* power.
|
||||
*/
|
||||
mutex_lock(&ihid_goodix->regulator_mutex);
|
||||
ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
|
||||
ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
|
||||
if (ret) {
|
||||
mutex_unlock(&ihid_goodix->regulator_mutex);
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"regulator notifier request failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* If someone else is holding the regulator on (or the regulator is
|
||||
* an always-on one) we might never be told to deassert reset. Do it
|
||||
* now. Here we'll assume that someone else might have _just
|
||||
* barely_ turned the regulator on so we'll do the full
|
||||
* "post_power_delay" just in case.
|
||||
*/
|
||||
if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd))
|
||||
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
|
||||
mutex_unlock(&ihid_goodix->regulator_mutex);
|
||||
|
||||
return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001);
|
||||
}
|
||||
|
||||
|
@ -377,27 +377,23 @@ static int hid_submit_ctrl(struct hid_device *hid)
|
||||
len = hid_report_len(report);
|
||||
if (dir == USB_DIR_OUT) {
|
||||
usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
|
||||
usbhid->urbctrl->transfer_buffer_length = len;
|
||||
if (raw_report) {
|
||||
memcpy(usbhid->ctrlbuf, raw_report, len);
|
||||
kfree(raw_report);
|
||||
usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
|
||||
}
|
||||
} else {
|
||||
int maxpacket, padlen;
|
||||
int maxpacket;
|
||||
|
||||
usbhid->urbctrl->pipe = usb_rcvctrlpipe(hid_to_usb_dev(hid), 0);
|
||||
maxpacket = usb_maxpacket(hid_to_usb_dev(hid),
|
||||
usbhid->urbctrl->pipe, 0);
|
||||
if (maxpacket > 0) {
|
||||
padlen = DIV_ROUND_UP(len, maxpacket);
|
||||
padlen *= maxpacket;
|
||||
if (padlen > usbhid->bufsize)
|
||||
padlen = usbhid->bufsize;
|
||||
} else
|
||||
padlen = 0;
|
||||
usbhid->urbctrl->transfer_buffer_length = padlen;
|
||||
len += (len == 0); /* Don't allow 0-length reports */
|
||||
len = round_up(len, maxpacket);
|
||||
if (len > usbhid->bufsize)
|
||||
len = usbhid->bufsize;
|
||||
}
|
||||
usbhid->urbctrl->transfer_buffer_length = len;
|
||||
usbhid->urbctrl->dev = hid_to_usb_dev(hid);
|
||||
|
||||
usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir;
|
||||
@ -505,7 +501,7 @@ static void hid_ctrl(struct urb *urb)
|
||||
|
||||
if (unplug) {
|
||||
usbhid->ctrltail = usbhid->ctrlhead;
|
||||
} else {
|
||||
} else if (usbhid->ctrlhead != usbhid->ctrltail) {
|
||||
usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
|
||||
|
||||
if (usbhid->ctrlhead != usbhid->ctrltail &&
|
||||
@ -1223,9 +1219,20 @@ static void usbhid_stop(struct hid_device *hid)
|
||||
mutex_lock(&usbhid->mutex);
|
||||
|
||||
clear_bit(HID_STARTED, &usbhid->iofl);
|
||||
|
||||
spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */
|
||||
set_bit(HID_DISCONNECTED, &usbhid->iofl);
|
||||
while (usbhid->ctrltail != usbhid->ctrlhead) {
|
||||
if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_OUT) {
|
||||
kfree(usbhid->ctrl[usbhid->ctrltail].raw_report);
|
||||
usbhid->ctrl[usbhid->ctrltail].raw_report = NULL;
|
||||
}
|
||||
|
||||
usbhid->ctrltail = (usbhid->ctrltail + 1) &
|
||||
(HID_CONTROL_FIFO_SIZE - 1);
|
||||
}
|
||||
spin_unlock_irq(&usbhid->lock);
|
||||
|
||||
usb_kill_urb(usbhid->urbin);
|
||||
usb_kill_urb(usbhid->urbout);
|
||||
usb_kill_urb(usbhid->urbctrl);
|
||||
|
@ -2287,7 +2287,13 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
|
||||
|
||||
if (wacom_wac->has_mute_touch_switch) {
|
||||
wacom_wac->shared->has_mute_touch_switch = true;
|
||||
wacom_wac->shared->is_touch_on = true;
|
||||
/* Hardware touch switch may be off. Wait until
|
||||
* we know the switch state to decide is_touch_on.
|
||||
* Softkey state should be initialized to "on" to
|
||||
* match historic default.
|
||||
*/
|
||||
if (wacom_wac->is_soft_touch_switch)
|
||||
wacom_wac->shared->is_touch_on = true;
|
||||
}
|
||||
|
||||
if (wacom_wac->shared->has_mute_touch_switch &&
|
||||
@ -2791,6 +2797,7 @@ static int wacom_probe(struct hid_device *hdev,
|
||||
error);
|
||||
}
|
||||
|
||||
wacom_wac->probe_complete = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -824,6 +824,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool touch_is_muted(struct wacom_wac *wacom_wac)
|
||||
{
|
||||
return wacom_wac->probe_complete &&
|
||||
wacom_wac->shared->has_mute_touch_switch &&
|
||||
!wacom_wac->shared->is_touch_on;
|
||||
}
|
||||
|
||||
static inline bool report_touch_events(struct wacom_wac *wacom)
|
||||
{
|
||||
return (touch_arbitration ? !wacom->shared->stylus_in_proximity : 1);
|
||||
@ -1525,11 +1532,8 @@ 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 (touch_is_muted(wacom) && !wacom->shared->touch_down)
|
||||
return 0;
|
||||
|
||||
if (wacom->features.type == WACOM_27QHDT) {
|
||||
current_num_contacts = data[63];
|
||||
@ -1987,14 +1991,17 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
|
||||
features->numbered_buttons++;
|
||||
features->device_type |= WACOM_DEVICETYPE_PAD;
|
||||
break;
|
||||
case WACOM_HID_WD_TOUCHONOFF:
|
||||
case WACOM_HID_WD_MUTE_DEVICE:
|
||||
/* softkey touch switch */
|
||||
wacom_wac->is_soft_touch_switch = true;
|
||||
fallthrough;
|
||||
case WACOM_HID_WD_TOUCHONOFF:
|
||||
/*
|
||||
* This usage, which is used to mute touch events, comes
|
||||
* from the pad packet, but is reported on the touch
|
||||
* These two usages, which are used to mute touch events, come
|
||||
* from the pad packet, but are reported on the touch
|
||||
* interface. Because the touch interface may not have
|
||||
* been created yet, we cannot call wacom_map_usage(). In
|
||||
* order to process this usage when we receive it, we set
|
||||
* order to process the usages when we receive them, we set
|
||||
* the usage type and code directly.
|
||||
*/
|
||||
wacom_wac->has_mute_touch_switch = true;
|
||||
@ -2533,8 +2540,7 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
||||
bool prox = hid_data->tipswitch &&
|
||||
report_touch_events(wacom_wac);
|
||||
|
||||
if (wacom_wac->shared->has_mute_touch_switch &&
|
||||
!wacom_wac->shared->is_touch_on) {
|
||||
if (touch_is_muted(wacom_wac)) {
|
||||
if (!wacom_wac->shared->touch_down)
|
||||
return;
|
||||
prox = false;
|
||||
@ -2548,8 +2554,17 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
|
||||
int slot;
|
||||
|
||||
slot = input_mt_get_slot_by_key(input, hid_data->id);
|
||||
if (slot < 0)
|
||||
if (slot < 0) {
|
||||
return;
|
||||
} else {
|
||||
struct input_mt_slot *ps = &input->mt->slots[slot];
|
||||
int mt_id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
|
||||
|
||||
if (!prox && mt_id < 0) {
|
||||
// No data to send for this slot; short-circuit
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
input_mt_slot(input, slot);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, prox);
|
||||
@ -2581,6 +2596,9 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
|
||||
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
||||
struct wacom_features *features = &wacom->wacom_wac.features;
|
||||
|
||||
if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down)
|
||||
return;
|
||||
|
||||
if (wacom_wac->is_invalid_bt_frame)
|
||||
return;
|
||||
|
||||
@ -2630,6 +2648,9 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
|
||||
struct hid_data* hid_data = &wacom_wac->hid_data;
|
||||
int i;
|
||||
|
||||
if (touch_is_muted(wacom_wac) && !wacom_wac->shared->touch_down)
|
||||
return;
|
||||
|
||||
wacom_wac->is_invalid_bt_frame = false;
|
||||
|
||||
for (i = 0; i < report->maxfield; i++) {
|
||||
@ -2681,6 +2702,10 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||
struct input_dev *input = wacom_wac->touch_input;
|
||||
unsigned touch_max = wacom_wac->features.touch_max;
|
||||
|
||||
/* if there was nothing to process, don't send an empty sync */
|
||||
if (wacom_wac->hid_data.num_expected == 0)
|
||||
return;
|
||||
|
||||
/* If more packets of data are expected, give us a chance to
|
||||
* process them rather than immediately syncing a partial
|
||||
* update.
|
||||
@ -3835,6 +3860,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_SW);
|
||||
__set_bit(SW_MUTE_DEVICE, input_dev->swbit);
|
||||
wacom_wac->has_mute_touch_switch = true;
|
||||
wacom_wac->is_soft_touch_switch = true;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
|
@ -337,6 +337,7 @@ struct wacom_wac {
|
||||
int tool[2];
|
||||
int id[2];
|
||||
__u64 serial[2];
|
||||
bool probe_complete;
|
||||
bool reporting_data;
|
||||
struct wacom_features features;
|
||||
struct wacom_shared *shared;
|
||||
@ -352,6 +353,7 @@ struct wacom_wac {
|
||||
int mode_value;
|
||||
struct hid_data hid_data;
|
||||
bool has_mute_touch_switch;
|
||||
bool is_soft_touch_switch;
|
||||
bool has_mode_change;
|
||||
bool is_direct_mode;
|
||||
bool is_invalid_bt_frame;
|
||||
|
Loading…
Reference in New Issue
Block a user