mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - Surface Aggregator Module support from Maximilian Luz - Apple Magic Mouse 2 support from John Chen - Support for newer Quad/BT 2.0 Logitech receivers in HID proxy mode from Hans de Goede - Thinkpad X1 Tablet keyboard support from Hans de Goede - Support for FTDI FT260 I2C host adapter from Michael Zaidman - other various small device-specific quirks, fixes and cleanups * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (46 commits) HID: wacom: Setup pen input capabilities to the targeted tools HID: hid-sensor-hub: Move 'hsdev' description to correct struct definition HID: hid-sensor-hub: Remove unused struct member 'quirks' HID: wacom_sys: Demote kernel-doc abuse HID: hid-sensor-custom: Remove unused variable 'ret' HID: hid-uclogic-params: Ensure function names are present and correct in kernel-doc headers HID: hid-uclogic-rdesc: Kernel-doc is for functions and structs HID: hid-logitech-hidpp: Fix conformant kernel-doc header and demote abuses HID: hid-picolcd_core: Remove unused variable 'ret' HID: hid-kye: Fix incorrect function name for kye_tablet_enable() HID: hid-core: Fix incorrect function name in header HID: hid-alps: Correct struct misnaming HID: usbhid: hid-pidff: Demote a couple kernel-doc abuses HID: usbhid: Repair a formatting issue in a struct description HID: hid-thrustmaster: Demote a bunch of kernel-doc abuses HID: input: map battery capacity (00850065) HID: magicmouse: fix reconnection of Magic Mouse 2 HID: magicmouse: fix 3 button emulation of Mouse 2 HID: magicmouse: add Apple Magic Mouse 2 support HID: lenovo: Add support for Thinkpad X1 Tablet Thin keyboard ...
This commit is contained in:
commit
efd8929b9e
38 files changed
+2955
-229
No files matched your search
+14
@@ -7432,6 +7432,13 @@ F: fs/verity/
|
||||
F: include/linux/fsverity.h
|
||||
F: include/uapi/linux/fsverity.h
|
||||
|
||||
FT260 FTDI USB-HID TO I2C BRIDGE DRIVER
|
||||
M: Michael Zaidman <michael.zaidman@gmail.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-ft260.c
|
||||
|
||||
FUJITSU LAPTOP EXTRAS
|
||||
M: Jonathan Woithe <jwoithe@just42.net>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
@@ -12079,6 +12086,13 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
|
||||
F: drivers/platform/surface/
|
||||
|
||||
MICROSOFT SURFACE HID TRANSPORT DRIVER
|
||||
M: Maximilian Luz <luzmaximilian@gmail.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/surface-hid/
|
||||
|
||||
MICROSOFT SURFACE HOT-PLUG DRIVER
|
||||
M: Maximilian Luz <luzmaximilian@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
||||
+17
-3
@@ -351,6 +351,17 @@ config HID_EZKEY
|
||||
help
|
||||
Support for Ezkey BTC 8193 keyboard.
|
||||
|
||||
config HID_FT260
|
||||
tristate "FTDI FT260 USB HID to I2C host support"
|
||||
depends on USB_HID && HIDRAW && I2C
|
||||
help
|
||||
Provides I2C host adapter functionality over USB-HID through FT260
|
||||
device. The customizable USB descriptor fields are exposed as sysfs
|
||||
attributes.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hid-ft260.
|
||||
|
||||
config HID_GEMBIRD
|
||||
tristate "Gembird Joypad"
|
||||
depends on HID
|
||||
@@ -1042,10 +1053,11 @@ config HID_THINGM
|
||||
|
||||
config HID_THRUSTMASTER
|
||||
tristate "ThrustMaster devices support"
|
||||
depends on HID
|
||||
depends on USB_HID
|
||||
help
|
||||
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
|
||||
a THRUSTMASTER Ferrari GT Rumble Wheel.
|
||||
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
|
||||
a THRUSTMASTER Ferrari GT Rumble Wheel or Thrustmaster FFB
|
||||
Wheel (T150RS, T300RS, T300 Ferrari Alcantara Edition, T500RS).
|
||||
|
||||
config THRUSTMASTER_FF
|
||||
bool "ThrustMaster devices force feedback support"
|
||||
@@ -1206,4 +1218,6 @@ source "drivers/hid/intel-ish-hid/Kconfig"
|
||||
|
||||
source "drivers/hid/amd-sfh-hid/Kconfig"
|
||||
|
||||
source "drivers/hid/surface-hid/Kconfig"
|
||||
|
||||
endmenu
|
||||
@@ -46,6 +46,7 @@ obj-$(CONFIG_HID_ELAN) += hid-elan.o
|
||||
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
|
||||
obj-$(CONFIG_HID_ELO) += hid-elo.o
|
||||
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
|
||||
obj-$(CONFIG_HID_FT260) += hid-ft260.o
|
||||
obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o
|
||||
obj-$(CONFIG_HID_GFRM) += hid-gfrm.o
|
||||
obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o
|
||||
@@ -112,7 +113,8 @@ obj-$(CONFIG_HID_STEAM) += hid-steam.o
|
||||
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
|
||||
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
|
||||
@@ -145,3 +147,5 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
|
||||
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
|
||||
|
||||
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
|
||||
|
||||
obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/
|
||||
@@ -74,7 +74,7 @@ enum dev_num {
|
||||
UNKNOWN,
|
||||
};
|
||||
/**
|
||||
* struct u1_data
|
||||
* struct alps_dev
|
||||
*
|
||||
* @input: pointer to the kernel input device
|
||||
* @input2: pointer to the kernel input2 device
|
||||
|
||||
@@ -2129,7 +2129,7 @@ struct hid_dynid {
|
||||
};
|
||||
|
||||
/**
|
||||
* store_new_id - add a new HID device ID to this driver and re-probe devices
|
||||
* new_id_store - add a new HID device ID to this driver and re-probe devices
|
||||
* @drv: target device driver
|
||||
* @buf: buffer for scanning device ID data
|
||||
* @count: input size
|
||||
|
||||
@@ -417,6 +417,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
|
||||
{ 0x85, 0x44, "Charging" },
|
||||
{ 0x85, 0x45, "Discharging" },
|
||||
{ 0x85, 0x4b, "NeedReplacement" },
|
||||
{ 0x85, 0x65, "AbsoluteStateOfCharge" },
|
||||
{ 0x85, 0x66, "RemainingCapacity" },
|
||||
{ 0x85, 0x68, "RunTimeToEmpty" },
|
||||
{ 0x85, 0x6a, "AverageTimeToFull" },
|
||||
|
||||
+5
-12
@@ -410,15 +410,6 @@ static int elan_start_multitouch(struct hid_device *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct device *dev = led_cdev->dev->parent;
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||
|
||||
return drvdata->mute_led_state;
|
||||
}
|
||||
|
||||
static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
@@ -445,8 +436,9 @@ static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev,
|
||||
kfree(dmabuf);
|
||||
|
||||
if (ret != ELAN_LED_REPORT_SIZE) {
|
||||
hid_err(hdev, "Failed to set mute led brightness: %d\n", ret);
|
||||
return ret;
|
||||
if (ret != -ENODEV)
|
||||
hid_err(hdev, "Failed to set mute led brightness: %d\n", ret);
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
drvdata->mute_led_state = led_state;
|
||||
@@ -459,9 +451,10 @@ static int elan_init_mute_led(struct hid_device *hdev)
|
||||
struct led_classdev *mute_led = &drvdata->mute_led;
|
||||
|
||||
mute_led->name = "elan:red:mute";
|
||||
mute_led->brightness_get = elan_mute_led_get_brigtness;
|
||||
mute_led->default_trigger = "audio-mute";
|
||||
mute_led->brightness_set_blocking = elan_mute_led_set_brigtness;
|
||||
mute_led->max_brightness = LED_ON;
|
||||
mute_led->flags = LED_HW_PLUGGABLE;
|
||||
mute_led->dev = &hdev->dev;
|
||||
|
||||
return devm_led_classdev_register(&hdev->dev, mute_led);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+12
-2
@@ -93,6 +93,7 @@
|
||||
#define BT_VENDOR_ID_APPLE 0x004c
|
||||
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
|
||||
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
|
||||
#define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269
|
||||
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e
|
||||
#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265
|
||||
#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
|
||||
@@ -431,6 +432,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_FUTURE_TECHNOLOGY 0x0403
|
||||
#define USB_DEVICE_ID_RETRODE2 0x97c1
|
||||
#define USB_DEVICE_ID_FT260 0x6030
|
||||
|
||||
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
|
||||
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
|
||||
@@ -808,6 +810,7 @@
|
||||
#define USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER 0xc51b
|
||||
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b
|
||||
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
|
||||
#define USB_DEVICE_ID_LOGITECH_G700_RECEIVER 0xc531
|
||||
#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_1 0xc539
|
||||
@@ -816,8 +819,14 @@
|
||||
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
|
||||
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
|
||||
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
|
||||
#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
|
||||
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
|
||||
#define USB_DEVICE_ID_MX5000_RECEIVER_MOUSE_DEV 0xc70a
|
||||
#define USB_DEVICE_ID_MX5000_RECEIVER_KBD_DEV 0xc70e
|
||||
#define USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_KBD_DEV 0xc713
|
||||
#define USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_MOUSE_DEV 0xc714
|
||||
#define USB_DEVICE_ID_MX5500_RECEIVER_KBD_DEV 0xc71b
|
||||
#define USB_DEVICE_ID_MX5500_RECEIVER_MOUSE_DEV 0xc71c
|
||||
#define USB_DEVICE_ID_DINOVO_MINI_RECEIVER_KBD_DEV 0xc71e
|
||||
#define USB_DEVICE_ID_DINOVO_MINI_RECEIVER_MOUSE_DEV 0xc71f
|
||||
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
|
||||
#define USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL 0xca04
|
||||
|
||||
@@ -946,6 +955,7 @@
|
||||
#define USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S 0x8003
|
||||
|
||||
#define USB_VENDOR_ID_PLANTRONICS 0x047f
|
||||
#define USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES 0xc056
|
||||
|
||||
#define USB_VENDOR_ID_PANASONIC 0x04da
|
||||
#define USB_DEVICE_ID_PANABOARD_UBT780 0x1044
|
||||
|
||||
+16
-6
@@ -435,7 +435,8 @@ static int hidinput_get_battery_property(struct power_supply *psy,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
|
||||
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
||||
struct hid_field *field, bool is_percentage)
|
||||
{
|
||||
struct power_supply_desc *psy_desc;
|
||||
struct power_supply_config psy_cfg = { .drv_data = dev, };
|
||||
@@ -475,7 +476,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
||||
min = field->logical_minimum;
|
||||
max = field->logical_maximum;
|
||||
|
||||
if (quirks & HID_BATTERY_QUIRK_PERCENT) {
|
||||
if (is_percentage || (quirks & HID_BATTERY_QUIRK_PERCENT)) {
|
||||
min = 0;
|
||||
max = 100;
|
||||
}
|
||||
@@ -552,7 +553,7 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
|
||||
}
|
||||
#else /* !CONFIG_HID_BATTERY_STRENGTH */
|
||||
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
|
||||
struct hid_field *field)
|
||||
struct hid_field *field, bool is_percentage)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -806,7 +807,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
break;
|
||||
|
||||
case 0x3b: /* Battery Strength */
|
||||
hidinput_setup_battery(device, HID_INPUT_REPORT, field);
|
||||
hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
|
||||
usage->type = EV_PWR;
|
||||
return;
|
||||
|
||||
@@ -1068,7 +1069,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case HID_UP_GENDEVCTRLS:
|
||||
switch (usage->hid) {
|
||||
case HID_DC_BATTERYSTRENGTH:
|
||||
hidinput_setup_battery(device, HID_INPUT_REPORT, field);
|
||||
hidinput_setup_battery(device, HID_INPUT_REPORT, field, false);
|
||||
usage->type = EV_PWR;
|
||||
return;
|
||||
}
|
||||
goto unknown;
|
||||
|
||||
case HID_UP_BATTERY:
|
||||
switch (usage->hid) {
|
||||
case HID_BAT_ABSOLUTESTATEOFCHARGE:
|
||||
hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);
|
||||
usage->type = EV_PWR;
|
||||
return;
|
||||
}
|
||||
@@ -1672,7 +1682,7 @@ static void report_features(struct hid_device *hid)
|
||||
/* Verify if Battery Strength feature is available */
|
||||
if (usage->hid == HID_DC_BATTERYSTRENGTH)
|
||||
hidinput_setup_battery(hid, HID_FEATURE_REPORT,
|
||||
rep->field[i]);
|
||||
rep->field[i], false);
|
||||
|
||||
if (drv->feature_mapping)
|
||||
drv->feature_mapping(hid, rep->field[i], usage);
|
||||
|
||||
@@ -655,7 +655,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable fully-functional tablet mode by setting a special feature report.
|
||||
* kye_tablet_enable() - Enable fully-functional tablet mode by setting a special feature report.
|
||||
*
|
||||
* @hdev: HID device
|
||||
*
|
||||
|
||||
+114
-33
@@ -33,6 +33,9 @@
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
/* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
|
||||
#define LENOVO_KEY_MICMUTE KEY_F20
|
||||
|
||||
struct lenovo_drvdata {
|
||||
u8 led_report[3]; /* Must be first for proper alignment */
|
||||
int led_state;
|
||||
@@ -62,8 +65,8 @@ struct lenovo_drvdata {
|
||||
#define TP10UBKBD_LED_OFF 1
|
||||
#define TP10UBKBD_LED_ON 2
|
||||
|
||||
static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
|
||||
enum led_brightness value)
|
||||
static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
int ret;
|
||||
@@ -75,10 +78,18 @@ static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
|
||||
data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF;
|
||||
ret = hid_hw_raw_request(hdev, data->led_report[0], data->led_report, 3,
|
||||
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret)
|
||||
hid_err(hdev, "Set LED output report error: %d\n", ret);
|
||||
if (ret != 3) {
|
||||
if (ret != -ENODEV)
|
||||
hid_err(hdev, "Set LED output report error: %d\n", ret);
|
||||
|
||||
ret = ret < 0 ? ret : -EIO;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->led_report_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lenovo_tp10ubkbd_sync_fn_lock(struct work_struct *work)
|
||||
@@ -126,7 +137,7 @@ static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
|
||||
if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
|
||||
/* This sub-device contains trackpoint, mark it */
|
||||
hid_set_drvdata(hdev, (void *)1);
|
||||
map_key_clear(KEY_MICMUTE);
|
||||
map_key_clear(LENOVO_KEY_MICMUTE);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -141,7 +152,7 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_LNVENDOR) {
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0x00f1: /* Fn-F4: Mic mute */
|
||||
map_key_clear(KEY_MICMUTE);
|
||||
map_key_clear(LENOVO_KEY_MICMUTE);
|
||||
return 1;
|
||||
case 0x00f2: /* Fn-F5: Brightness down */
|
||||
map_key_clear(KEY_BRIGHTNESSDOWN);
|
||||
@@ -231,7 +242,7 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
|
||||
map_key_clear(KEY_FN_ESC);
|
||||
return 1;
|
||||
case 9: /* Fn-F4: Mic mute */
|
||||
map_key_clear(KEY_MICMUTE);
|
||||
map_key_clear(LENOVO_KEY_MICMUTE);
|
||||
return 1;
|
||||
case 10: /* Fn-F7: Control panel */
|
||||
map_key_clear(KEY_CONFIG);
|
||||
@@ -255,6 +266,54 @@ static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_input_mapping_x1_tab_kbd(struct hid_device *hdev,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
{
|
||||
/*
|
||||
* The ThinkPad X1 Tablet Thin Keyboard uses 0x000c0001 usage for
|
||||
* a bunch of keys which have no standard consumer page code.
|
||||
*/
|
||||
if (usage->hid == 0x000c0001) {
|
||||
switch (usage->usage_index) {
|
||||
case 0: /* Fn-F10: Enable/disable bluetooth */
|
||||
map_key_clear(KEY_BLUETOOTH);
|
||||
return 1;
|
||||
case 1: /* Fn-F11: Keyboard settings */
|
||||
map_key_clear(KEY_KEYBOARD);
|
||||
return 1;
|
||||
case 2: /* Fn-F12: User function / Cortana */
|
||||
map_key_clear(KEY_MACRO1);
|
||||
return 1;
|
||||
case 3: /* Fn-PrtSc: Snipping tool */
|
||||
map_key_clear(KEY_SELECTIVE_SCREENSHOT);
|
||||
return 1;
|
||||
case 8: /* Fn-Esc: Fn-lock toggle */
|
||||
map_key_clear(KEY_FN_ESC);
|
||||
return 1;
|
||||
case 9: /* Fn-F4: Mute/unmute microphone */
|
||||
map_key_clear(KEY_MICMUTE);
|
||||
return 1;
|
||||
case 10: /* Fn-F9: Settings */
|
||||
map_key_clear(KEY_CONFIG);
|
||||
return 1;
|
||||
case 13: /* Fn-F7: Manage external displays */
|
||||
map_key_clear(KEY_SWITCHVIDEOMODE);
|
||||
return 1;
|
||||
case 14: /* Fn-F8: Enable/disable wifi */
|
||||
map_key_clear(KEY_WLAN);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (usage->hid == (HID_UP_KEYBOARD | 0x009a)) {
|
||||
map_key_clear(KEY_SYSRQ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
@@ -278,6 +337,8 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
|
||||
usage, bit, max);
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -349,7 +410,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
||||
{
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
|
||||
int value;
|
||||
int value, ret;
|
||||
|
||||
if (kstrtoint(buf, 10, &value))
|
||||
return -EINVAL;
|
||||
@@ -364,7 +425,10 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
||||
lenovo_features_set_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -498,11 +562,15 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
|
||||
static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
if (!hid_get_drvdata(hdev))
|
||||
return 0;
|
||||
|
||||
switch (hdev->product) {
|
||||
case USB_DEVICE_ID_LENOVO_CUSBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_CBTKBD:
|
||||
return lenovo_event_cptkbd(hdev, field, usage, value);
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
return lenovo_event_tp10ubkbd(hdev, field, usage, value);
|
||||
default:
|
||||
return 0;
|
||||
@@ -761,23 +829,7 @@ static void lenovo_led_set_tpkbd(struct hid_device *hdev)
|
||||
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
static enum led_brightness lenovo_led_brightness_get(
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
struct device *dev = led_cdev->dev->parent;
|
||||
struct hid_device *hdev = to_hid_device(dev);
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
int led_nr = 0;
|
||||
|
||||
if (led_cdev == &data_pointer->led_micmute)
|
||||
led_nr = 1;
|
||||
|
||||
return data_pointer->led_state & (1 << led_nr)
|
||||
? LED_FULL
|
||||
: LED_OFF;
|
||||
}
|
||||
|
||||
static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct device *dev = led_cdev->dev->parent;
|
||||
@@ -785,6 +837,7 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
|
||||
u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
|
||||
int led_nr = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (led_cdev == &data_pointer->led_micmute)
|
||||
led_nr = 1;
|
||||
@@ -799,9 +852,12 @@ static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
lenovo_led_set_tpkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lenovo_register_leds(struct hid_device *hdev)
|
||||
@@ -821,16 +877,20 @@ static int lenovo_register_leds(struct hid_device *hdev)
|
||||
snprintf(name_micm, name_sz, "%s:amber:micmute", dev_name(&hdev->dev));
|
||||
|
||||
data->led_mute.name = name_mute;
|
||||
data->led_mute.brightness_get = lenovo_led_brightness_get;
|
||||
data->led_mute.brightness_set = lenovo_led_brightness_set;
|
||||
data->led_mute.default_trigger = "audio-mute";
|
||||
data->led_mute.brightness_set_blocking = lenovo_led_brightness_set;
|
||||
data->led_mute.max_brightness = 1;
|
||||
data->led_mute.flags = LED_HW_PLUGGABLE;
|
||||
data->led_mute.dev = &hdev->dev;
|
||||
ret = led_classdev_register(&hdev->dev, &data->led_mute);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->led_micmute.name = name_micm;
|
||||
data->led_micmute.brightness_get = lenovo_led_brightness_get;
|
||||
data->led_micmute.brightness_set = lenovo_led_brightness_set;
|
||||
data->led_micmute.default_trigger = "audio-micmute";
|
||||
data->led_micmute.brightness_set_blocking = lenovo_led_brightness_set;
|
||||
data->led_micmute.max_brightness = 1;
|
||||
data->led_micmute.flags = LED_HW_PLUGGABLE;
|
||||
data->led_micmute.dev = &hdev->dev;
|
||||
ret = led_classdev_register(&hdev->dev, &data->led_micmute);
|
||||
if (ret < 0) {
|
||||
@@ -952,11 +1012,24 @@ static const struct attribute_group lenovo_attr_group_tp10ubkbd = {
|
||||
|
||||
static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
|
||||
{
|
||||
struct hid_report_enum *rep_enum;
|
||||
struct lenovo_drvdata *data;
|
||||
struct hid_report *rep;
|
||||
bool found;
|
||||
int ret;
|
||||
|
||||
/* All the custom action happens on the USBMOUSE device for USB */
|
||||
if (hdev->type != HID_TYPE_USBMOUSE)
|
||||
/*
|
||||
* The LEDs and the Fn-lock functionality use output report 9,
|
||||
* with an application of 0xffa0001, add the LEDs on the interface
|
||||
* with this output report.
|
||||
*/
|
||||
found = false;
|
||||
rep_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
|
||||
list_for_each_entry(rep, &rep_enum->report_list, list) {
|
||||
if (rep->application == 0xffa00001)
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
return 0;
|
||||
|
||||
data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
@@ -1018,6 +1091,7 @@ static int lenovo_probe(struct hid_device *hdev,
|
||||
ret = lenovo_probe_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
ret = lenovo_probe_tp10ubkbd(hdev);
|
||||
break;
|
||||
default:
|
||||
@@ -1083,6 +1157,7 @@ static void lenovo_remove(struct hid_device *hdev)
|
||||
lenovo_remove_cptkbd(hdev);
|
||||
break;
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
lenovo_remove_tp10ubkbd(hdev);
|
||||
break;
|
||||
}
|
||||
@@ -1122,6 +1197,12 @@ static const struct hid_device_id lenovo_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TP10UBKBD) },
|
||||
/*
|
||||
* Note bind to the HID_GROUP_GENERIC group, so that we only bind to the keyboard
|
||||
* part, while letting hid-multitouch.c handle the touchpad and trackpoint.
|
||||
*/
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -568,22 +568,6 @@ static int lg_ultrax_remote_mapping(struct hid_input *hi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
|
||||
return 0;
|
||||
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
|
||||
case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
@@ -668,10 +652,6 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
lg_ultrax_remote_mapping(hi, usage, bit, max))
|
||||
return 1;
|
||||
|
||||
if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
|
||||
lg_dinovo_mapping(hi, usage, bit, max))
|
||||
return 1;
|
||||
|
||||
if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
|
||||
return 1;
|
||||
|
||||
@@ -879,10 +859,6 @@ static const struct hid_device_id lg_devices[] = {
|
||||
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
|
||||
.driver_data = LG_DUPLICATE_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
|
||||
.driver_data = LG_DUPLICATE_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
|
||||
.driver_data = LG_DUPLICATE_USAGES },
|
||||
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
|
||||
.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
|
||||
|
||||
+114
-23
@@ -84,6 +84,7 @@
|
||||
#define STD_MOUSE BIT(2)
|
||||
#define MULTIMEDIA BIT(3)
|
||||
#define POWER_KEYS BIT(4)
|
||||
#define KBD_MOUSE BIT(5)
|
||||
#define MEDIA_CENTER BIT(8)
|
||||
#define KBD_LEDS BIT(14)
|
||||
/* Fake (bitnr > NUMBER_OF_HID_REPORTS) bit to track HID++ capability */
|
||||
@@ -117,6 +118,7 @@ enum recvr_type {
|
||||
recvr_type_mouse_only,
|
||||
recvr_type_27mhz,
|
||||
recvr_type_bluetooth,
|
||||
recvr_type_dinovo,
|
||||
};
|
||||
|
||||
struct dj_report {
|
||||
@@ -333,6 +335,47 @@ static const char mse_bluetooth_descriptor[] = {
|
||||
0xC0, /* END_COLLECTION */
|
||||
};
|
||||
|
||||
/* Mouse descriptor (5) for Bluetooth receiver, normal-res hwheel, 8 buttons */
|
||||
static const char mse5_bluetooth_descriptor[] = {
|
||||
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
|
||||
0x09, 0x02, /* Usage (Mouse) */
|
||||
0xa1, 0x01, /* Collection (Application) */
|
||||
0x85, 0x05, /* Report ID (5) */
|
||||
0x09, 0x01, /* Usage (Pointer) */
|
||||
0xa1, 0x00, /* Collection (Physical) */
|
||||
0x05, 0x09, /* Usage Page (Button) */
|
||||
0x19, 0x01, /* Usage Minimum (1) */
|
||||
0x29, 0x08, /* Usage Maximum (8) */
|
||||
0x15, 0x00, /* Logical Minimum (0) */
|
||||
0x25, 0x01, /* Logical Maximum (1) */
|
||||
0x95, 0x08, /* Report Count (8) */
|
||||
0x75, 0x01, /* Report Size (1) */
|
||||
0x81, 0x02, /* Input (Data,Var,Abs) */
|
||||
0x05, 0x01, /* Usage Page (Generic Desktop) */
|
||||
0x16, 0x01, 0xf8, /* Logical Minimum (-2047) */
|
||||
0x26, 0xff, 0x07, /* Logical Maximum (2047) */
|
||||
0x75, 0x0c, /* Report Size (12) */
|
||||
0x95, 0x02, /* Report Count (2) */
|
||||
0x09, 0x30, /* Usage (X) */
|
||||
0x09, 0x31, /* Usage (Y) */
|
||||
0x81, 0x06, /* Input (Data,Var,Rel) */
|
||||
0x15, 0x81, /* Logical Minimum (-127) */
|
||||
0x25, 0x7f, /* Logical Maximum (127) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x95, 0x01, /* Report Count (1) */
|
||||
0x09, 0x38, /* Usage (Wheel) */
|
||||
0x81, 0x06, /* Input (Data,Var,Rel) */
|
||||
0x05, 0x0c, /* Usage Page (Consumer Devices) */
|
||||
0x0a, 0x38, 0x02, /* Usage (AC Pan) */
|
||||
0x15, 0x81, /* Logical Minimum (-127) */
|
||||
0x25, 0x7f, /* Logical Maximum (127) */
|
||||
0x75, 0x08, /* Report Size (8) */
|
||||
0x95, 0x01, /* Report Count (1) */
|
||||
0x81, 0x06, /* Input (Data,Var,Rel) */
|
||||
0xc0, /* End Collection */
|
||||
0xc0, /* End Collection */
|
||||
};
|
||||
|
||||
/* Gaming Mouse descriptor (2) */
|
||||
static const char mse_high_res_descriptor[] = {
|
||||
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
|
||||
@@ -480,6 +523,7 @@ static const char hidpp_descriptor[] = {
|
||||
#define MAX_RDESC_SIZE \
|
||||
(sizeof(kbd_descriptor) + \
|
||||
sizeof(mse_bluetooth_descriptor) + \
|
||||
sizeof(mse5_bluetooth_descriptor) + \
|
||||
sizeof(consumer_descriptor) + \
|
||||
sizeof(syscontrol_descriptor) + \
|
||||
sizeof(media_descriptor) + \
|
||||
@@ -517,6 +561,11 @@ static void delayedwork_callback(struct work_struct *work);
|
||||
static LIST_HEAD(dj_hdev_list);
|
||||
static DEFINE_MUTEX(dj_hdev_list_lock);
|
||||
|
||||
static bool recvr_type_is_bluetooth(enum recvr_type type)
|
||||
{
|
||||
return type == recvr_type_bluetooth || type == recvr_type_dinovo;
|
||||
}
|
||||
|
||||
/*
|
||||
* dj/HID++ receivers are really a single logical entity, but for BIOS/Windows
|
||||
* compatibility they have multiple USB interfaces. On HID++ receivers we need
|
||||
@@ -534,7 +583,7 @@ static struct dj_receiver_dev *dj_find_receiver_dev(struct hid_device *hdev,
|
||||
* The bluetooth receiver contains a built-in hub and has separate
|
||||
* USB-devices for the keyboard and mouse interfaces.
|
||||
*/
|
||||
sep = (type == recvr_type_bluetooth) ? '.' : '/';
|
||||
sep = recvr_type_is_bluetooth(type) ? '.' : '/';
|
||||
|
||||
/* Try to find an already-probed interface from the same device */
|
||||
list_for_each_entry(djrcv_dev, &dj_hdev_list, list) {
|
||||
@@ -872,6 +921,14 @@ static void logi_dj_recv_queue_notification(struct dj_receiver_dev *djrcv_dev,
|
||||
* touchpad to work we must also forward mouse input reports to the dj_hiddev
|
||||
* created for the keyboard (instead of forwarding them to a second paired
|
||||
* device with a device_type of REPORT_TYPE_MOUSE as we normally would).
|
||||
*
|
||||
* On Dinovo receivers the keyboard's touchpad and an optional paired actual
|
||||
* mouse send separate input reports, INPUT(2) aka STD_MOUSE for the mouse
|
||||
* and INPUT(5) aka KBD_MOUSE for the keyboard's touchpad.
|
||||
*
|
||||
* On MX5x00 receivers (which can also be paired with a Dinovo keyboard)
|
||||
* INPUT(2) is used for both an optional paired actual mouse and for the
|
||||
* keyboard's touchpad.
|
||||
*/
|
||||
static const u16 kbd_builtin_touchpad_ids[] = {
|
||||
0xb309, /* Dinovo Edge */
|
||||
@@ -898,7 +955,10 @@ static void logi_hidpp_dev_conn_notif_equad(struct hid_device *hdev,
|
||||
id = (workitem->quad_id_msb << 8) | workitem->quad_id_lsb;
|
||||
for (i = 0; i < ARRAY_SIZE(kbd_builtin_touchpad_ids); i++) {
|
||||
if (id == kbd_builtin_touchpad_ids[i]) {
|
||||
workitem->reports_supported |= STD_MOUSE;
|
||||
if (djrcv_dev->type == recvr_type_dinovo)
|
||||
workitem->reports_supported |= KBD_MOUSE;
|
||||
else
|
||||
workitem->reports_supported |= STD_MOUSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1367,7 +1427,7 @@ static int logi_dj_ll_parse(struct hid_device *hid)
|
||||
else if (djdev->dj_receiver_dev->type == recvr_type_27mhz)
|
||||
rdcat(rdesc, &rsize, mse_27mhz_descriptor,
|
||||
sizeof(mse_27mhz_descriptor));
|
||||
else if (djdev->dj_receiver_dev->type == recvr_type_bluetooth)
|
||||
else if (recvr_type_is_bluetooth(djdev->dj_receiver_dev->type))
|
||||
rdcat(rdesc, &rsize, mse_bluetooth_descriptor,
|
||||
sizeof(mse_bluetooth_descriptor));
|
||||
else
|
||||
@@ -1375,6 +1435,13 @@ static int logi_dj_ll_parse(struct hid_device *hid)
|
||||
sizeof(mse_descriptor));
|
||||
}
|
||||
|
||||
if (djdev->reports_supported & KBD_MOUSE) {
|
||||
dbg_hid("%s: sending a kbd-mouse descriptor, reports_supported: %llx\n",
|
||||
__func__, djdev->reports_supported);
|
||||
rdcat(rdesc, &rsize, mse5_bluetooth_descriptor,
|
||||
sizeof(mse5_bluetooth_descriptor));
|
||||
}
|
||||
|
||||
if (djdev->reports_supported & MULTIMEDIA) {
|
||||
dbg_hid("%s: sending a multimedia report descriptor: %llx\n",
|
||||
__func__, djdev->reports_supported);
|
||||
@@ -1692,6 +1759,7 @@ static int logi_dj_probe(struct hid_device *hdev,
|
||||
case recvr_type_mouse_only: no_dj_interfaces = 2; break;
|
||||
case recvr_type_27mhz: no_dj_interfaces = 2; break;
|
||||
case recvr_type_bluetooth: no_dj_interfaces = 2; break;
|
||||
case recvr_type_dinovo: no_dj_interfaces = 2; break;
|
||||
}
|
||||
if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
|
||||
intf = to_usb_interface(hdev->dev.parent);
|
||||
@@ -1857,23 +1925,27 @@ static void logi_dj_remove(struct hid_device *hdev)
|
||||
}
|
||||
|
||||
static const struct hid_device_id logi_dj_receivers[] = {
|
||||
{HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
{ /* Logitech unifying receiver (0xc52b) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER),
|
||||
.driver_data = recvr_type_dj},
|
||||
{HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
{ /* Logitech unifying receiver (0xc532) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2),
|
||||
.driver_data = recvr_type_dj},
|
||||
{ /* Logitech Nano mouse only receiver */
|
||||
|
||||
{ /* Logitech Nano mouse only receiver (0xc52f) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER),
|
||||
.driver_data = recvr_type_mouse_only},
|
||||
{ /* Logitech Nano (non DJ) receiver */
|
||||
{ /* Logitech Nano (non DJ) receiver (0xc534) */
|
||||
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),
|
||||
USB_DEVICE_ID_LOGITECH_G700_RECEIVER),
|
||||
.driver_data = recvr_type_gaming_hidpp},
|
||||
{ /* Logitech G602 receiver (0xc537) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
@@ -1883,17 +1955,18 @@ static const struct hid_device_id logi_dj_receivers[] = {
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
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),
|
||||
.driver_data = recvr_type_27mhz},
|
||||
{ /* Logitech powerplay receiver (0xc53a) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY),
|
||||
.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),
|
||||
.driver_data = recvr_type_27mhz},
|
||||
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc517) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_S510_RECEIVER_2),
|
||||
@@ -1902,22 +1975,40 @@ static const struct hid_device_id logi_dj_receivers[] = {
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER),
|
||||
.driver_data = recvr_type_27mhz},
|
||||
{ /* Logitech MX5000 HID++ / bluetooth receiver keyboard intf. */
|
||||
|
||||
{ /* Logitech MX5000 HID++ / bluetooth receiver keyboard intf. (0xc70e) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
0xc70e),
|
||||
USB_DEVICE_ID_MX5000_RECEIVER_KBD_DEV),
|
||||
.driver_data = recvr_type_bluetooth},
|
||||
{ /* Logitech MX5000 HID++ / bluetooth receiver mouse intf. */
|
||||
{ /* Logitech MX5000 HID++ / bluetooth receiver mouse intf. (0xc70a) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
0xc70a),
|
||||
USB_DEVICE_ID_MX5000_RECEIVER_MOUSE_DEV),
|
||||
.driver_data = recvr_type_bluetooth},
|
||||
{ /* Logitech MX5500 HID++ / bluetooth receiver keyboard intf. */
|
||||
{ /* Logitech MX5500 HID++ / bluetooth receiver keyboard intf. (0xc71b) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
0xc71b),
|
||||
USB_DEVICE_ID_MX5500_RECEIVER_KBD_DEV),
|
||||
.driver_data = recvr_type_bluetooth},
|
||||
{ /* Logitech MX5500 HID++ / bluetooth receiver mouse intf. */
|
||||
{ /* Logitech MX5500 HID++ / bluetooth receiver mouse intf. (0xc71c) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
0xc71c),
|
||||
USB_DEVICE_ID_MX5500_RECEIVER_MOUSE_DEV),
|
||||
.driver_data = recvr_type_bluetooth},
|
||||
|
||||
{ /* Logitech Dinovo Edge HID++ / bluetooth receiver keyboard intf. (0xc713) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_KBD_DEV),
|
||||
.driver_data = recvr_type_dinovo},
|
||||
{ /* Logitech Dinovo Edge HID++ / bluetooth receiver mouse intf. (0xc714) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_DINOVO_EDGE_RECEIVER_MOUSE_DEV),
|
||||
.driver_data = recvr_type_dinovo},
|
||||
{ /* Logitech DiNovo Mini HID++ / bluetooth receiver mouse intf. (0xc71e) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_DINOVO_MINI_RECEIVER_KBD_DEV),
|
||||
.driver_data = recvr_type_dinovo},
|
||||
{ /* Logitech DiNovo Mini HID++ / bluetooth receiver keyboard intf. (0xc71f) */
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_DINOVO_MINI_RECEIVER_MOUSE_DEV),
|
||||
.driver_data = recvr_type_dinovo},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ static int __hidpp_send_report(struct hid_device *hdev,
|
||||
return ret == fields_count ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* hidpp_send_message_sync() returns 0 in case of success, and something else
|
||||
* in case of a failure.
|
||||
* - If ' something else' is positive, that means that an error has been raised
|
||||
@@ -423,7 +423,7 @@ static inline bool hidpp_report_is_connect_event(struct hidpp_device *hidpp,
|
||||
(report->rap.sub_id == 0x41));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* hidpp_prefix_name() prefixes the current given name with "Logitech ".
|
||||
*/
|
||||
static void hidpp_prefix_name(char **name, int name_length)
|
||||
@@ -454,6 +454,7 @@ static void hidpp_prefix_name(char **name, int name_length)
|
||||
* hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
|
||||
* events given a high-resolution wheel
|
||||
* movement.
|
||||
* @input_dev: Pointer to the input device
|
||||
* @counter: a hid_scroll_counter struct describing the wheel.
|
||||
* @hi_res_value: the movement of the wheel, in the mouse's high-resolution
|
||||
* units.
|
||||
@@ -1884,7 +1885,7 @@ struct hidpp_touchpad_fw_items {
|
||||
uint8_t persistent;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* send a set state command to the device by reading the current items->state
|
||||
* field. items is then filled with the current state.
|
||||
*/
|
||||
|
||||
+128
-34
@@ -16,6 +16,7 @@
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
@@ -54,6 +55,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
|
||||
#define TRACKPAD2_USB_REPORT_ID 0x02
|
||||
#define TRACKPAD2_BT_REPORT_ID 0x31
|
||||
#define MOUSE_REPORT_ID 0x29
|
||||
#define MOUSE2_REPORT_ID 0x12
|
||||
#define DOUBLE_REPORT_ID 0xf7
|
||||
/* These definitions are not precise, but they're close enough. (Bits
|
||||
* 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
|
||||
@@ -127,6 +129,9 @@ struct magicmouse_sc {
|
||||
u8 size;
|
||||
} touches[16];
|
||||
int tracking_ids[16];
|
||||
|
||||
struct hid_device *hdev;
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
static int magicmouse_firm_touch(struct magicmouse_sc *msc)
|
||||
@@ -195,7 +200,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
int id, x, y, size, orientation, touch_major, touch_minor, state, down;
|
||||
int pressure = 0;
|
||||
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
|
||||
x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
|
||||
y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
|
||||
@@ -296,7 +302,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
|
||||
input_report_abs(input, ABS_MT_PRESSURE, pressure);
|
||||
|
||||
if (report_undeciphered) {
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
|
||||
input_event(input, EV_MSC, MSC_RAW, tdata[7]);
|
||||
else if (input->id.product !=
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)
|
||||
@@ -380,6 +387,34 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
* ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
|
||||
*/
|
||||
break;
|
||||
case MOUSE2_REPORT_ID:
|
||||
/* Size is either 8 or (14 + 8 * N) */
|
||||
if (size != 8 && (size < 14 || (size - 14) % 8 != 0))
|
||||
return 0;
|
||||
npoints = (size - 14) / 8;
|
||||
if (npoints > 15) {
|
||||
hid_warn(hdev, "invalid size value (%d) for MOUSE2_REPORT_ID\n",
|
||||
size);
|
||||
return 0;
|
||||
}
|
||||
msc->ntouches = 0;
|
||||
for (ii = 0; ii < npoints; ii++)
|
||||
magicmouse_emit_touch(msc, ii, data + ii * 8 + 14);
|
||||
|
||||
/* When emulating three-button mode, it is important
|
||||
* to have the current touch information before
|
||||
* generating a click event.
|
||||
*/
|
||||
x = (int)((data[3] << 24) | (data[2] << 16)) >> 16;
|
||||
y = (int)((data[5] << 24) | (data[4] << 16)) >> 16;
|
||||
clicks = data[1];
|
||||
|
||||
/* The following bits provide a device specific timestamp. They
|
||||
* are unused here.
|
||||
*
|
||||
* ts = data[11] >> 6 | data[12] << 2 | data[13] << 10;
|
||||
*/
|
||||
break;
|
||||
case DOUBLE_REPORT_ID:
|
||||
/* Sometimes the trackpad sends two touch reports in one
|
||||
* packet.
|
||||
@@ -392,7 +427,8 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
magicmouse_emit_buttons(msc, clicks & 3);
|
||||
input_report_rel(input, REL_X, x);
|
||||
input_report_rel(input, REL_Y, y);
|
||||
@@ -408,6 +444,23 @@ static int magicmouse_raw_event(struct hid_device *hdev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int magicmouse_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
|
||||
if (msc->input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 &&
|
||||
field->report->id == MOUSE2_REPORT_ID) {
|
||||
/*
|
||||
* magic_mouse_raw_event has done all the work. Skip hidinput.
|
||||
*
|
||||
* Specifically, hidinput may modify BTN_LEFT and BTN_RIGHT,
|
||||
* breaking emulate_3button.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
|
||||
{
|
||||
int error;
|
||||
@@ -415,7 +468,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
__set_bit(BTN_LEFT, input->keybit);
|
||||
__set_bit(BTN_RIGHT, input->keybit);
|
||||
if (emulate_3button)
|
||||
@@ -480,7 +534,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd
|
||||
* the origin at the same position, and just uses the additive
|
||||
* inverse of the reported Y.
|
||||
*/
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
|
||||
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE ||
|
||||
input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
|
||||
@@ -580,19 +635,60 @@ static int magicmouse_input_configured(struct hid_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int magicmouse_enable_multitouch(struct hid_device *hdev)
|
||||
{
|
||||
const u8 *feature;
|
||||
const u8 feature_mt[] = { 0xD7, 0x01 };
|
||||
const u8 feature_mt_mouse2[] = { 0xF1, 0x02, 0x01 };
|
||||
const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
|
||||
const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
|
||||
u8 *buf;
|
||||
int ret;
|
||||
int feature_size;
|
||||
|
||||
if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
if (hdev->vendor == BT_VENDOR_ID_APPLE) {
|
||||
feature_size = sizeof(feature_mt_trackpad2_bt);
|
||||
feature = feature_mt_trackpad2_bt;
|
||||
} else { /* USB_VENDOR_ID_APPLE */
|
||||
feature_size = sizeof(feature_mt_trackpad2_usb);
|
||||
feature = feature_mt_trackpad2_usb;
|
||||
}
|
||||
} else if (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
feature_size = sizeof(feature_mt_mouse2);
|
||||
feature = feature_mt_mouse2;
|
||||
} else {
|
||||
feature_size = sizeof(feature_mt);
|
||||
feature = feature_mt;
|
||||
}
|
||||
|
||||
buf = kmemdup(feature, feature_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void magicmouse_enable_mt_work(struct work_struct *work)
|
||||
{
|
||||
struct magicmouse_sc *msc =
|
||||
container_of(work, struct magicmouse_sc, work.work);
|
||||
int ret;
|
||||
|
||||
ret = magicmouse_enable_multitouch(msc->hdev);
|
||||
if (ret < 0)
|
||||
hid_err(msc->hdev, "unable to request touch data (%d)\n", ret);
|
||||
}
|
||||
|
||||
static int magicmouse_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
const u8 *feature;
|
||||
const u8 feature_mt[] = { 0xD7, 0x01 };
|
||||
const u8 feature_mt_trackpad2_usb[] = { 0x02, 0x01 };
|
||||
const u8 feature_mt_trackpad2_bt[] = { 0xF1, 0x02, 0x01 };
|
||||
u8 *buf;
|
||||
struct magicmouse_sc *msc;
|
||||
struct hid_report *report;
|
||||
int ret;
|
||||
int feature_size;
|
||||
|
||||
if (id->vendor == USB_VENDOR_ID_APPLE &&
|
||||
id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 &&
|
||||
@@ -606,6 +702,8 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
}
|
||||
|
||||
msc->scroll_accel = SCROLL_ACCEL_DEFAULT;
|
||||
msc->hdev = hdev;
|
||||
INIT_DEFERRABLE_WORK(&msc->work, magicmouse_enable_mt_work);
|
||||
|
||||
msc->quirks = id->driver_data;
|
||||
hid_set_drvdata(hdev, msc);
|
||||
@@ -631,6 +729,9 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
MOUSE_REPORT_ID, 0);
|
||||
else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
MOUSE2_REPORT_ID, 0);
|
||||
else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
if (id->vendor == BT_VENDOR_ID_APPLE)
|
||||
report = hid_register_report(hdev, HID_INPUT_REPORT,
|
||||
@@ -652,25 +753,6 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
}
|
||||
report->size = 6;
|
||||
|
||||
if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) {
|
||||
if (id->vendor == BT_VENDOR_ID_APPLE) {
|
||||
feature_size = sizeof(feature_mt_trackpad2_bt);
|
||||
feature = feature_mt_trackpad2_bt;
|
||||
} else { /* USB_VENDOR_ID_APPLE */
|
||||
feature_size = sizeof(feature_mt_trackpad2_usb);
|
||||
feature = feature_mt_trackpad2_usb;
|
||||
}
|
||||
} else {
|
||||
feature_size = sizeof(feature_mt);
|
||||
feature = feature_mt;
|
||||
}
|
||||
|
||||
buf = kmemdup(feature, feature_size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some devices repond with 'invalid report id' when feature
|
||||
* report switching it into multitouch mode is sent to it.
|
||||
@@ -679,13 +761,14 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
* but there seems to be no other way of switching the mode.
|
||||
* Thus the super-ugly hacky success check below.
|
||||
*/
|
||||
ret = hid_hw_raw_request(hdev, buf[0], buf, feature_size,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
kfree(buf);
|
||||
if (ret != -EIO && ret != feature_size) {
|
||||
ret = magicmouse_enable_multitouch(hdev);
|
||||
if (ret != -EIO && ret < 0) {
|
||||
hid_err(hdev, "unable to request touch data (%d)\n", ret);
|
||||
goto err_stop_hw;
|
||||
}
|
||||
if (ret == -EIO && id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) {
|
||||
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_stop_hw:
|
||||
@@ -693,9 +776,18 @@ err_stop_hw:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void magicmouse_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct magicmouse_sc *msc = hid_get_drvdata(hdev);
|
||||
cancel_delayed_work_sync(&msc->work);
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
static const struct hid_device_id magic_mice[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
|
||||
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICMOUSE2), .driver_data = 0 },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
|
||||
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
|
||||
@@ -710,7 +802,9 @@ static struct hid_driver magicmouse_driver = {
|
||||
.name = "magicmouse",
|
||||
.id_table = magic_mice,
|
||||
.probe = magicmouse_probe,
|
||||
.remove = magicmouse_remove,
|
||||
.raw_event = magicmouse_raw_event,
|
||||
.event = magicmouse_event,
|
||||
.input_mapping = magicmouse_input_mapping,
|
||||
.input_configured = magicmouse_input_configured,
|
||||
};
|
||||
|
||||
@@ -329,7 +329,6 @@ static int picolcd_raw_event(struct hid_device *hdev,
|
||||
{
|
||||
struct picolcd_data *data = hid_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!data)
|
||||
return 1;
|
||||
@@ -342,9 +341,9 @@ static int picolcd_raw_event(struct hid_device *hdev,
|
||||
|
||||
if (report->id == REPORT_KEY_STATE) {
|
||||
if (data->input_keys)
|
||||
ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
|
||||
picolcd_raw_keypad(data, report, raw_data+1, size-1);
|
||||
} else if (report->id == REPORT_IR_DATA) {
|
||||
ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
|
||||
picolcd_raw_cir(data, report, raw_data+1, size-1);
|
||||
} else {
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
/*
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#define PLT_HID_1_0_PAGE 0xffa00000
|
||||
#define PLT_HID_2_0_PAGE 0xffa20000
|
||||
@@ -36,6 +37,16 @@
|
||||
#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
|
||||
|
||||
#define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0)
|
||||
|
||||
#define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */
|
||||
|
||||
struct plt_drv_data {
|
||||
unsigned long device_type;
|
||||
unsigned long last_volume_key_ts;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
static int plantronics_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi,
|
||||
struct hid_field *field,
|
||||
@@ -43,7 +54,8 @@ static int plantronics_input_mapping(struct hid_device *hdev,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
unsigned short mapped_key;
|
||||
unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev);
|
||||
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
|
||||
unsigned long plt_type = drv_data->device_type;
|
||||
|
||||
/* special case for PTT products */
|
||||
if (field->application == HID_GD_JOYSTICK)
|
||||
@@ -105,6 +117,30 @@ mapped:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int plantronics_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
struct plt_drv_data *drv_data = hid_get_drvdata(hdev);
|
||||
|
||||
if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) {
|
||||
unsigned long prev_ts, cur_ts;
|
||||
|
||||
/* Usages are filtered in plantronics_usages. */
|
||||
|
||||
if (!value) /* Handle key presses only. */
|
||||
return 0;
|
||||
|
||||
prev_ts = drv_data->last_volume_key_ts;
|
||||
cur_ts = jiffies;
|
||||
if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT)
|
||||
return 1; /* Ignore the repeated key. */
|
||||
|
||||
drv_data->last_volume_key_ts = cur_ts;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long plantronics_device_type(struct hid_device *hdev)
|
||||
{
|
||||
unsigned i, col_page;
|
||||
@@ -133,15 +169,24 @@ exit:
|
||||
static int plantronics_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
struct plt_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev));
|
||||
drv_data->device_type = plantronics_device_type(hdev);
|
||||
drv_data->quirks = id->driver_data;
|
||||
drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT);
|
||||
|
||||
hid_set_drvdata(hdev, drv_data);
|
||||
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
|
||||
HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE);
|
||||
@@ -153,15 +198,26 @@ err:
|
||||
}
|
||||
|
||||
static const struct hid_device_id plantronics_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS,
|
||||
USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES),
|
||||
.driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, plantronics_devices);
|
||||
|
||||
static const struct hid_usage_id plantronics_usages[] = {
|
||||
{ HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID },
|
||||
{ HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID },
|
||||
{ HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR }
|
||||
};
|
||||
|
||||
static struct hid_driver plantronics_driver = {
|
||||
.name = "plantronics",
|
||||
.id_table = plantronics_devices,
|
||||
.usage_table = plantronics_usages,
|
||||
.input_mapping = plantronics_input_mapping,
|
||||
.event = plantronics_event,
|
||||
.probe = plantronics_probe,
|
||||
};
|
||||
module_hid_driver(plantronics_driver);
|
||||
|
||||
@@ -445,8 +445,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
|
||||
@@ -661,6 +659,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ 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)
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
|
||||
|
||||
@@ -397,15 +397,14 @@ static ssize_t store_value(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
if (!strncmp(name, "value", strlen("value"))) {
|
||||
u32 report_id;
|
||||
int ret;
|
||||
|
||||
if (kstrtoint(buf, 0, &value) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
report_id = sensor_inst->fields[field_index].attribute.
|
||||
report_id;
|
||||
ret = sensor_hub_set_feature(sensor_inst->hsdev, report_id,
|
||||
index, sizeof(value), &value);
|
||||
sensor_hub_set_feature(sensor_inst->hsdev, report_id,
|
||||
index, sizeof(value), &value);
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
Loaded 20 of 38 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user