Commit 988b7fb0 authored by Jiri Kosina's avatar Jiri Kosina

Merge branches 'for-3.19/upstream-fixes', 'for-3.20/apple', 'for-3.20/betop',...

Merge branches 'for-3.19/upstream-fixes', 'for-3.20/apple', 'for-3.20/betop', 'for-3.20/lenovo', 'for-3.20/logitech', 'for-3.20/rmi', 'for-3.20/upstream' and 'for-3.20/wacom' into for-linus
...@@ -147,6 +147,16 @@ config HID_BELKIN ...@@ -147,6 +147,16 @@ config HID_BELKIN
---help--- ---help---
Support for Belkin Flip KVM and Wireless keyboard. Support for Belkin Flip KVM and Wireless keyboard.
config HID_BETOP_FF
tristate "Betop Production Inc. force feedback support"
depends on USB_HID
select INPUT_FF_MEMLESS
---help---
Say Y here if you want to enable force feedback support for devices by
BETOP Production Ltd.
Currently the following devices are known to be supported:
- BETOP 2185 PC & BFM MODE
config HID_CHERRY config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT tristate "Cherry Cymotion keyboard" if EXPERT
depends on HID depends on HID
...@@ -389,7 +399,7 @@ config HID_LOGITECH_HIDPP ...@@ -389,7 +399,7 @@ config HID_LOGITECH_HIDPP
Say Y if you want support for Logitech devices relying on the HID++ Say Y if you want support for Logitech devices relying on the HID++
specification. Such devices are the various Logitech Touchpads (T650, specification. Such devices are the various Logitech Touchpads (T650,
T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar
Keayboard). Keyboard).
config LOGITECH_FF config LOGITECH_FF
bool "Logitech force feedback support" bool "Logitech force feedback support"
......
...@@ -2,10 +2,7 @@ ...@@ -2,10 +2,7 @@
# Makefile for the HID driver # Makefile for the HID driver
# #
hid-y := hid-core.o hid-input.o hid-y := hid-core.o hid-input.o
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
ifdef CONFIG_DEBUG_FS
hid-objs += hid-debug.o
endif
obj-$(CONFIG_HID) += hid.o obj-$(CONFIG_HID) += hid.o
obj-$(CONFIG_UHID) += uhid.o obj-$(CONFIG_UHID) += uhid.o
...@@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o ...@@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o
hid-$(CONFIG_HIDRAW) += hidraw.o hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-y := hid-lg.o hid-logitech-y := hid-lg.o
ifdef CONFIG_LOGITECH_FF hid-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o
hid-logitech-y += hid-lgff.o hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o
endif hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o
ifdef CONFIG_LOGIRUMBLEPAD2_FF hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o
hid-logitech-y += hid-lg2ff.o
endif
ifdef CONFIG_LOGIG940_FF
hid-logitech-y += hid-lg3ff.o
endif
ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o
endif
hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
ifdef CONFIG_DEBUG_FS hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
hid-wiimote-y += hid-wiimote-debug.o
endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o
...@@ -39,6 +26,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o ...@@ -39,6 +26,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
...@@ -76,24 +64,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o ...@@ -76,24 +64,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
hid-picolcd-y += hid-picolcd_core.o hid-picolcd-y += hid-picolcd_core.o
ifdef CONFIG_HID_PICOLCD_FB hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o
hid-picolcd-y += hid-picolcd_fb.o hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o
endif hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o
ifdef CONFIG_HID_PICOLCD_BACKLIGHT hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o
hid-picolcd-y += hid-picolcd_backlight.o hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o
endif hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
ifdef CONFIG_HID_PICOLCD_LCD
hid-picolcd-y += hid-picolcd_lcd.o
endif
ifdef CONFIG_HID_PICOLCD_LEDS
hid-picolcd-y += hid-picolcd_leds.o
endif
ifdef CONFIG_HID_PICOLCD_CIR
hid-picolcd-y += hid-picolcd_cir.o
endif
ifdef CONFIG_DEBUG_FS
hid-picolcd-y += hid-picolcd_debugfs.o
endif
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
......
/*
* Force feedback support for Betop based devices
*
* The devices are distributed under various names and the same USB device ID
* can be used in both adapters and actual game controllers.
*
* 0x11c2:0x2208 "BTP2185 BFM mode Joystick"
* - tested with BTP2185 BFM Mode.
*
* 0x11C0:0x5506 "BTP2185 PC mode Joystick"
* - tested with BTP2185 PC Mode.
*
* 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad"
* - tested with BTP2185 PC Mode with another version.
*
* 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick"
* - tested with BTP2171s.
* Copyright (c) 2014 Huang Bo <huangbobupt@163.com>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/hid.h>
#include "hid-ids.h"
struct betopff_device {
struct hid_report *report;
};
static int hid_betopff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct betopff_device *betopff = data;
__u16 left, right;
left = effect->u.rumble.strong_magnitude;
right = effect->u.rumble.weak_magnitude;
betopff->report->field[2]->value[0] = left / 256;
betopff->report->field[3]->value[0] = right / 256;
hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
return 0;
}
static int betopff_init(struct hid_device *hid)
{
struct betopff_device *betopff;
struct hid_report *report;
struct hid_input *hidinput =
list_first_entry(&hid->inputs, struct hid_input, list);
struct list_head *report_list =
&hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
int field_count = 0;
int error;
int i, j;
if (list_empty(report_list)) {
hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report = list_first_entry(report_list, struct hid_report, list);
/*
* Actually there are 4 fields for 4 Bytes as below:
* -----------------------------------------
* Byte0 Byte1 Byte2 Byte3
* 0x00 0x00 left_motor right_motor
* -----------------------------------------
* Do init them with default value.
*/
for (i = 0; i < report->maxfield; i++) {
for (j = 0; j < report->field[i]->report_count; j++) {
report->field[i]->value[j] = 0x00;
field_count++;
}
}
if (field_count < 4) {
hid_err(hid, "not enough fields in the report: %d\n",
field_count);
return -ENODEV;
}
betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
if (!betopff)
return -ENOMEM;
set_bit(FF_RUMBLE, dev->ffbit);
error = input_ff_create_memless(dev, betopff, hid_betopff_play);
if (error) {
kfree(betopff);
return error;
}
betopff->report = report;
hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force feedback for betop devices by huangbo <huangbobupt@163.com>\n");
return 0;
}
static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
if (id->driver_data)
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err;
}
betopff_init(hdev);
return 0;
err:
return ret;
}
static const struct hid_device_id betop_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
{ }
};
MODULE_DEVICE_TABLE(hid, betop_devices);
static struct hid_driver betop_driver = {
.name = "betop",
.id_table = betop_devices,
.probe = betop_probe,
};
module_hid_driver(betop_driver);
MODULE_LICENSE("GPL");
...@@ -698,15 +698,25 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) ...@@ -698,15 +698,25 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
static void hid_scan_collection(struct hid_parser *parser, unsigned type) static void hid_scan_collection(struct hid_parser *parser, unsigned type)
{ {
struct hid_device *hid = parser->device; struct hid_device *hid = parser->device;
int i;
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL) type == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB; hid->group = HID_GROUP_SENSOR_HUB;
if (hid->vendor == USB_VENDOR_ID_MICROSOFT && if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) &&
hid->group == HID_GROUP_MULTITOUCH) hid->group == HID_GROUP_MULTITOUCH)
hid->group = HID_GROUP_GENERIC; hid->group = HID_GROUP_GENERIC;
if ((parser->global.usage_page << 16) == HID_UP_GENDESK)
for (i = 0; i < parser->local.usage_index; i++)
if (parser->local.usage[i] == HID_GD_POINTER)
parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER;
if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR)
parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC;
} }
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
...@@ -792,10 +802,13 @@ static int hid_scan_report(struct hid_device *hid) ...@@ -792,10 +802,13 @@ static int hid_scan_report(struct hid_device *hid)
hid->group = HID_GROUP_WACOM; hid->group = HID_GROUP_WACOM;
break; break;
case USB_VENDOR_ID_SYNAPTICS: case USB_VENDOR_ID_SYNAPTICS:
if ((hid->group == HID_GROUP_GENERIC) && if (hid->group == HID_GROUP_GENERIC)
(hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
/* hid-rmi should only bind to the mouse interface of && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
* composite USB devices */ /*
* hid-rmi should take care of them,
* not hid-generic
*/
hid->group = HID_GROUP_RMI; hid->group = HID_GROUP_RMI;
break; break;
} }
...@@ -1757,6 +1770,10 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1757,6 +1770,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
...@@ -1861,6 +1878,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1861,6 +1878,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
...@@ -1971,6 +1989,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1971,6 +1989,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
{ } { }
}; };
......
...@@ -381,7 +381,7 @@ static void mousevsc_on_channel_callback(void *context) ...@@ -381,7 +381,7 @@ static void mousevsc_on_channel_callback(void *context)
static int mousevsc_connect_to_vsp(struct hv_device *device) static int mousevsc_connect_to_vsp(struct hv_device *device)
{ {
int ret = 0; int ret = 0;
int t; unsigned long t;
struct mousevsc_dev *input_dev = hv_get_drvdata(device); struct mousevsc_dev *input_dev = hv_get_drvdata(device);
struct mousevsc_prt_msg *request; struct mousevsc_prt_msg *request;
struct mousevsc_prt_msg *response; struct mousevsc_prt_msg *response;
......
...@@ -189,6 +189,11 @@ ...@@ -189,6 +189,11 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2
#define USB_VENDOR_ID_BETOP_2185PC 0x11c0
#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
#define USB_VENDOR_ID_BTC 0x046e #define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
...@@ -655,6 +660,7 @@ ...@@ -655,6 +660,7 @@
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc
#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd
#define USB_VENDOR_ID_MOJO 0x8282 #define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
...@@ -769,6 +775,9 @@ ...@@ -769,6 +775,9 @@
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
#define USB_VENDOR_ID_RAZER 0x1532
#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D
#define USB_VENDOR_ID_REALTEK 0x0bda #define USB_VENDOR_ID_REALTEK 0x0bda
#define USB_DEVICE_ID_REALTEK_READER 0x0152 #define USB_DEVICE_ID_REALTEK_READER 0x0152
......
...@@ -308,6 +308,9 @@ static const struct hid_device_id hid_battery_quirks[] = { ...@@ -308,6 +308,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
...@@ -1104,6 +1107,23 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct ...@@ -1104,6 +1107,23 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return; return;
} }
/*
* Ignore reports for absolute data if the data didn't change. This is
* not only an optimization but also fixes 'dead' key reports. Some
* RollOver implementations for localized keys (like BACKSLASH/PIPE; HID
* 0x31 and 0x32) report multiple keys, even though a localized keyboard
* can only have one of them physically available. The 'dead' keys
* report constant 0. As all map to the same keycode, they'd confuse
* the input layer. If we filter the 'dead' keys on the HID level, we
* skip the keycode translation and only forward real events.
*/
if (!(field->flags & (HID_MAIN_ITEM_RELATIVE |
HID_MAIN_ITEM_BUFFERED_BYTE)) &&
(field->flags & HID_MAIN_ITEM_VARIABLE) &&
usage->usage_index < field->maxusage &&
value == field->value[usage->usage_index])
return;
/* report the usage code as scancode if the key status has changed */ /* report the usage code as scancode if the key status has changed */
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, EV_MSC, MSC_SCAN, usage->hid);
......
...@@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd { ...@@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd {
struct lenovo_drvdata_cptkbd { struct lenovo_drvdata_cptkbd {
bool fn_lock; bool fn_lock;
int sensitivity;
}; };
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
...@@ -91,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, ...@@ -91,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
case 0x00fa: /* Fn-Esc: Fn-lock toggle */ case 0x00fa: /* Fn-Esc: Fn-lock toggle */
map_key_clear(KEY_FN_ESC); map_key_clear(KEY_FN_ESC);
return 1; return 1;
case 0x00fb: /* Middle mouse button (in native mode) */
map_key_clear(BTN_MIDDLE);
return 1;
}
}
/* Compatibility middle/wheel mappings should be ignored */
if (usage->hid == HID_GD_WHEEL)
return -1;
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON &&
(usage->hid & HID_USAGE) == 0x003)
return -1;
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER &&
(usage->hid & HID_USAGE) == 0x238)
return -1;
/* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */
if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 ||
(usage->hid & HID_USAGE_PAGE) == 0xffa10000) {
field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE;
field->logical_minimum = -127;
field->logical_maximum = 127;
switch (usage->hid & HID_USAGE) {
case 0x0000:
hid_map_usage(hi, usage, bit, max, EV_REL, 0x06);
return 1;
case 0x0001:
hid_map_usage(hi, usage, bit, max, EV_REL, 0x08);
return 1;
default:
return -1;
} }
} }
...@@ -145,6 +178,7 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) ...@@ -145,6 +178,7 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
if (ret) if (ret)
hid_err(hdev, "Fn-lock setting failed: %d\n", ret); hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
} }
...@@ -179,13 +213,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, ...@@ -179,13 +213,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
return count; return count;
} }
static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
cptkbd_data->sensitivity);
}
static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
int value;
if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
return -EINVAL;
cptkbd_data->sensitivity = value;
lenovo_features_set_cptkbd(hdev);
return count;
}
static struct device_attribute dev_attr_fn_lock_cptkbd = static struct device_attribute dev_attr_fn_lock_cptkbd =
__ATTR(fn_lock, S_IWUSR | S_IRUGO, __ATTR(fn_lock, S_IWUSR | S_IRUGO,
attr_fn_lock_show_cptkbd, attr_fn_lock_show_cptkbd,
attr_fn_lock_store_cptkbd); attr_fn_lock_store_cptkbd);
static struct device_attribute dev_attr_sensitivity_cptkbd =
__ATTR(sensitivity, S_IWUSR | S_IRUGO,
attr_sensitivity_show_cptkbd,
attr_sensitivity_store_cptkbd);
static struct attribute *lenovo_attributes_cptkbd[] = { static struct attribute *lenovo_attributes_cptkbd[] = {
&dev_attr_fn_lock_cptkbd.attr, &dev_attr_fn_lock_cptkbd.attr,
&dev_attr_sensitivity_cptkbd.attr,
NULL NULL
}; };
...@@ -594,8 +665,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) ...@@ -594,8 +665,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
if (ret) if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
/* Turn Fn-Lock on by default */ /* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
if (ret)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
/* Set keyboard settings to known state */
cptkbd_data->fn_lock = true; cptkbd_data->fn_lock = true;
cptkbd_data->sensitivity = 0x05;
lenovo_features_set_cptkbd(hdev); lenovo_features_set_cptkbd(hdev);
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
......
...@@ -49,10 +49,6 @@ ...@@ -49,10 +49,6 @@
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IROTH, lg4ff_range_show, lg4ff_range_store);
struct lg4ff_device_entry { struct lg4ff_device_entry {
__u32 product_id; __u32 product_id;
...@@ -416,7 +412,8 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n ...@@ -416,7 +412,8 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
} }
/* Read current range and display it in terminal */ /* Read current range and display it in terminal */
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t range_show(struct device *dev, struct device_attribute *attr,
char *buf)
{ {
struct hid_device *hid = to_hid_device(dev); struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry; struct lg4ff_device_entry *entry;
...@@ -441,7 +438,8 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att ...@@ -441,7 +438,8 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
/* Set range to user specified value, call appropriate function /* Set range to user specified value, call appropriate function
* according to the type of the wheel */ * according to the type of the wheel */
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) static ssize_t range_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct hid_device *hid = to_hid_device(dev); struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry; struct lg4ff_device_entry *entry;
...@@ -472,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at ...@@ -472,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
return count; return count;
} }
static DEVICE_ATTR_RW(range);
#ifdef CONFIG_LEDS_CLASS #ifdef CONFIG_LEDS_CLASS
static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
......
...@@ -89,6 +89,7 @@ struct hidpp_device { ...@@ -89,6 +89,7 @@ struct hidpp_device {
struct hid_device *hid_dev; struct hid_device *hid_dev;
struct mutex send_mutex; struct mutex send_mutex;
void *send_receive_buf; void *send_receive_buf;
char *name; /* will never be NULL and should not be freed */
wait_queue_head_t wait; wait_queue_head_t wait;
bool answer_available; bool answer_available;
u8 protocol_major; u8 protocol_major;
...@@ -105,6 +106,7 @@ struct hidpp_device { ...@@ -105,6 +106,7 @@ struct hidpp_device {
}; };
/* HID++ 1.0 error codes */
#define HIDPP_ERROR 0x8f #define HIDPP_ERROR 0x8f
#define HIDPP_ERROR_SUCCESS 0x00 #define HIDPP_ERROR_SUCCESS 0x00
#define HIDPP_ERROR_INVALID_SUBID 0x01 #define HIDPP_ERROR_INVALID_SUBID 0x01
...@@ -119,6 +121,8 @@ struct hidpp_device { ...@@ -119,6 +121,8 @@ struct hidpp_device {
#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
/* HID++ 2.0 error codes */
#define HIDPP20_ERROR 0xff
static void hidpp_connect_event(struct hidpp_device *hidpp_dev); static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
...@@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, ...@@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
} }
if (response->report_id == REPORT_ID_HIDPP_SHORT && if (response->report_id == REPORT_ID_HIDPP_SHORT &&
response->fap.feature_index == HIDPP_ERROR) { response->rap.sub_id == HIDPP_ERROR) {
ret = response->rap.params[1];
dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
goto exit;
}
if (response->report_id == REPORT_ID_HIDPP_LONG &&
response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1]; ret = response->fap.params[1];
dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit; goto exit;
} }
...@@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question, ...@@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question,
static inline bool hidpp_match_error(struct hidpp_report *question, static inline bool hidpp_match_error(struct hidpp_report *question,
struct hidpp_report *answer) struct hidpp_report *answer)
{ {
return (answer->fap.feature_index == HIDPP_ERROR) && return ((answer->rap.sub_id == HIDPP_ERROR) ||
(answer->fap.feature_index == HIDPP20_ERROR)) &&
(answer->fap.funcindex_clientid == question->fap.feature_index) && (answer->fap.funcindex_clientid == question->fap.feature_index) &&
(answer->fap.params[0] == question->fap.funcindex_clientid); (answer->fap.params[0] == question->fap.funcindex_clientid);
} }
...@@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
return 0; return 0;
}; };
static void wtp_connect(struct hid_device *hdev, bool connected) static int wtp_connect(struct hid_device *hdev, bool connected)
{ {
struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct hidpp_device *hidpp = hid_get_drvdata(hdev);
struct wtp_data *wd = hidpp->private_data; struct wtp_data *wd = hidpp->private_data;
int ret; int ret;
if (!connected) if (!connected)
return; return 0;
if (!wd->x_size) { if (!wd->x_size) {
ret = wtp_get_config(hidpp); ret = wtp_get_config(hidpp);
if (ret) { if (ret) {
hid_err(hdev, "Can not get wtp config: %d\n", ret); hid_err(hdev, "Can not get wtp config: %d\n", ret);
return; return ret;
} }
} }
hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index,
true, true); true, true);
} }
...@@ -965,7 +977,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, ...@@ -965,7 +977,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
/* /*
* If the mutex is locked then we have a pending answer from a * If the mutex is locked then we have a pending answer from a
* previoulsly sent command * previously sent command.
*/ */
if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { if (unlikely(mutex_is_locked(&hidpp->send_mutex))) {
/* /*
...@@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, ...@@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
return 1; return 1;
} }
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
return wtp_raw_event(hidpp->hid_dev, data, size);
return 0; return 0;
} }
...@@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size) u8 *data, int size)
{ {
struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct hidpp_device *hidpp = hid_get_drvdata(hdev);
int ret = 0;
/* Generic HID++ processing. */
switch (data[0]) { switch (data[0]) {
case REPORT_ID_HIDPP_LONG: case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) { if (size != HIDPP_REPORT_LONG_LENGTH) {
...@@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, ...@@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
size); size);
return 1; return 1;
} }
return hidpp_raw_hidpp_event(hidpp, data, size); ret = hidpp_raw_hidpp_event(hidpp, data, size);
break;
case REPORT_ID_HIDPP_SHORT: case REPORT_ID_HIDPP_SHORT:
if (size != HIDPP_REPORT_SHORT_LENGTH) { if (size != HIDPP_REPORT_SHORT_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)", hid_err(hdev, "received hid++ report of bad size (%d)",
size); size);
return 1; return 1;
} }
return hidpp_raw_hidpp_event(hidpp, data, size); ret = hidpp_raw_hidpp_event(hidpp, data, size);
break;
} }
/* If no report is available for further processing, skip calling
* raw_event of subclasses. */
if (ret != 0)
return ret;
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
return wtp_raw_event(hdev, data, size); return wtp_raw_event(hdev, data, size);
...@@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev) ...@@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev)
static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
{ {
struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev);
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
if (!input_dev) if (!input_dev)
return NULL; return NULL;
...@@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) ...@@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
input_dev->open = hidpp_input_open; input_dev->open = hidpp_input_open;
input_dev->close = hidpp_input_close; input_dev->close = hidpp_input_close;
input_dev->name = hdev->name; input_dev->name = hidpp->name;
input_dev->phys = hdev->phys; input_dev->phys = hdev->phys;
input_dev->uniq = hdev->uniq; input_dev->uniq = hdev->uniq;
input_dev->id.bustype = hdev->bus; input_dev->id.bustype = hdev->bus;
...@@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) ...@@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
struct input_dev *input; struct input_dev *input;
char *name, *devm_name; char *name, *devm_name;
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
wtp_connect(hdev, connected); ret = wtp_connect(hdev, connected);
if (ret)
return;
}
if (!connected || hidpp->delayed_input) if (!connected || hidpp->delayed_input)
return; return;
...@@ -1117,20 +1139,26 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) ...@@ -1117,20 +1139,26 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
hid_info(hdev, "HID++ %u.%u device connected.\n", hid_info(hdev, "HID++ %u.%u device connected.\n",
hidpp->protocol_major, hidpp->protocol_minor); hidpp->protocol_major, hidpp->protocol_minor);
input = hidpp_allocate_input(hdev); if (!hidpp->name || hidpp->name == hdev->name) {
if (!input) { name = hidpp_get_device_name(hidpp);
hid_err(hdev, "cannot allocate new input device: %d\n", ret); if (!name) {
hid_err(hdev,
"unable to retrieve the name of the device");
return; return;
} }
name = hidpp_get_device_name(hidpp);
if (!name) {
hid_err(hdev, "unable to retrieve the name of the device");
} else {
devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name);
if (devm_name)
input->name = devm_name;
kfree(name); kfree(name);
if (!devm_name)
return;
hidpp->name = devm_name;
}
input = hidpp_allocate_input(hdev);
if (!input) {
hid_err(hdev, "cannot allocate new input device: %d\n", ret);
return;
} }
hidpp_populate_input(hidpp, input, false); hidpp_populate_input(hidpp, input, false);
...@@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return -ENOMEM; return -ENOMEM;
hidpp->hid_dev = hdev; hidpp->hid_dev = hdev;
hidpp->name = hdev->name;
hid_set_drvdata(hdev, hidpp); hid_set_drvdata(hdev, hidpp);
hidpp->quirks = id->driver_data; hidpp->quirks = id->driver_data;
......
...@@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = { ...@@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_DUPLICATE_USAGES }, .driver_data = MS_DUPLICATE_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP),
.driver_data = MS_HIDINPUT },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER }, .driver_data = MS_PRESENTER },
......
...@@ -33,6 +33,10 @@ ...@@ -33,6 +33,10 @@
#define RMI_READ_DATA_PENDING BIT(1) #define RMI_READ_DATA_PENDING BIT(1)
#define RMI_STARTED BIT(2) #define RMI_STARTED BIT(2)
/* device flags */
#define RMI_DEVICE BIT(0)
#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1)
enum rmi_mode_type { enum rmi_mode_type {
RMI_MODE_OFF = 0, RMI_MODE_OFF = 0,
RMI_MODE_ATTN_REPORTS = 1, RMI_MODE_ATTN_REPORTS = 1,
...@@ -118,6 +122,8 @@ struct rmi_data { ...@@ -118,6 +122,8 @@ struct rmi_data {
struct work_struct reset_work; struct work_struct reset_work;
struct hid_device *hdev; struct hid_device *hdev;
unsigned long device_flags;
}; };
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff) #define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
...@@ -452,9 +458,32 @@ static int rmi_raw_event(struct hid_device *hdev, ...@@ -452,9 +458,32 @@ static int rmi_raw_event(struct hid_device *hdev,
return rmi_read_data_event(hdev, data, size); return rmi_read_data_event(hdev, data, size);
case RMI_ATTN_REPORT_ID: case RMI_ATTN_REPORT_ID:
return rmi_input_event(hdev, data, size); return rmi_input_event(hdev, data, size);
case RMI_MOUSE_REPORT_ID: default:
return 1;
}
return 0;
}
static int rmi_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct rmi_data *data = hid_get_drvdata(hdev);
if ((data->device_flags & RMI_DEVICE) &&
(field->application == HID_GD_POINTER ||
field->application == HID_GD_MOUSE)) {
if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) {
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
return 0;
if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y)
&& !value)
return 1;
}
rmi_schedule_reset(hdev); rmi_schedule_reset(hdev);
break; return 1;
} }
return 0; return 0;
...@@ -856,6 +885,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) ...@@ -856,6 +885,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret) if (ret)
return; return;
if (!(data->device_flags & RMI_DEVICE))
return;
/* Allow incoming hid reports */ /* Allow incoming hid reports */
hid_device_io_start(hdev); hid_device_io_start(hdev);
...@@ -914,8 +946,38 @@ static int rmi_input_mapping(struct hid_device *hdev, ...@@ -914,8 +946,38 @@ static int rmi_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max) struct hid_usage *usage, unsigned long **bit, int *max)
{ {
/* we want to make HID ignore the advertised HID collection */ struct rmi_data *data = hid_get_drvdata(hdev);
/*
* we want to make HID ignore the advertised HID collection
* for RMI deivces
*/
if (data->device_flags & RMI_DEVICE) {
if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) &&
((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON))
return 0;
return -1; return -1;
}
return 0;
}
static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type,
unsigned id, struct hid_report **report)
{
int i;
*report = hdev->report_enum[type].report_id_hash[id];
if (*report) {
for (i = 0; i < (*report)->maxfield; i++) {
unsigned app = (*report)->field[i]->application;
if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR)
return 1;
}
}
return 0;
} }
static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
...@@ -925,6 +987,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -925,6 +987,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
size_t alloc_size; size_t alloc_size;
struct hid_report *input_report; struct hid_report *input_report;
struct hid_report *output_report; struct hid_report *output_report;
struct hid_report *feature_report;
data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
if (!data) if (!data)
...@@ -943,27 +1006,37 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -943,27 +1006,37 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret; return ret;
} }
input_report = hdev->report_enum[HID_INPUT_REPORT] if (id->driver_data)
.report_id_hash[RMI_ATTN_REPORT_ID]; data->device_flags = id->driver_data;
if (!input_report) {
hid_err(hdev, "device does not have expected input report\n"); /*
ret = -ENODEV; * Check for the RMI specific report ids. If they are misisng
return ret; * simply return and let the events be processed by hid-input
*/
if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT,
RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) {
hid_dbg(hdev, "device does not have set mode feature report\n");
goto start;
} }
data->input_report_size = (input_report->size >> 3) + 1 /* report id */; if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT,
RMI_ATTN_REPORT_ID, &input_report)) {
hid_dbg(hdev, "device does not have attention input report\n");
goto start;
}
output_report = hdev->report_enum[HID_OUTPUT_REPORT] data->input_report_size = hid_report_len(input_report);
.report_id_hash[RMI_WRITE_REPORT_ID];
if (!output_report) { if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT,
hid_err(hdev, "device does not have expected output report\n"); RMI_WRITE_REPORT_ID, &output_report)) {
ret = -ENODEV; hid_dbg(hdev,
return ret; "device does not have rmi write output report\n");
goto start;
} }
data->output_report_size = (output_report->size >> 3) data->output_report_size = hid_report_len(output_report);
+ 1 /* report id */;
data->device_flags |= RMI_DEVICE;
alloc_size = data->output_report_size + data->input_report_size; alloc_size = data->output_report_size + data->input_report_size;
data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
...@@ -978,13 +1051,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -978,13 +1051,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
mutex_init(&data->page_mutex); mutex_init(&data->page_mutex);
start:
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) { if (ret) {
hid_err(hdev, "hw start failed\n"); hid_err(hdev, "hw start failed\n");
return ret; return ret;
} }
if (!test_bit(RMI_STARTED, &data->flags)) if ((data->device_flags & RMI_DEVICE) &&
!test_bit(RMI_STARTED, &data->flags))
/* /*
* The device maybe in the bootloader if rmi_input_configured * The device maybe in the bootloader if rmi_input_configured
* failed to find F11 in the PDT. Print an error, but don't * failed to find F11 in the PDT. Print an error, but don't
...@@ -1007,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev) ...@@ -1007,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev)
} }
static const struct hid_device_id rmi_id[] = { static const struct hid_device_id rmi_id[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14),
.driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
{ } { }
}; };
...@@ -1017,6 +1094,7 @@ static struct hid_driver rmi_driver = { ...@@ -1017,6 +1094,7 @@ static struct hid_driver rmi_driver = {
.id_table = rmi_id, .id_table = rmi_id,
.probe = rmi_probe, .probe = rmi_probe,
.remove = rmi_remove, .remove = rmi_remove,
.event = rmi_event,
.raw_event = rmi_raw_event, .raw_event = rmi_raw_event,
.input_mapping = rmi_input_mapping, .input_mapping = rmi_input_mapping,
.input_configured = rmi_input_configured, .input_configured = rmi_input_configured,
......
...@@ -2,17 +2,9 @@ ...@@ -2,17 +2,9 @@
# Makefile for the USB input drivers # Makefile for the USB input drivers
# #
# Multipart objects.
usbhid-y := hid-core.o hid-quirks.o usbhid-y := hid-core.o hid-quirks.o
usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o
# Optional parts of multipart objects. usbhid-$(CONFIG_HID_PID) += hid-pidff.o
ifeq ($(CONFIG_USB_HIDDEV),y)
usbhid-y += hiddev.o
endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-y += hid-pidff.o
endif
obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBD) += usbkbd.o
......
...@@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid) ...@@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid)
pidff->hid = hid; pidff->hid = hid;
hid_device_io_start(hid);
pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff); pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
...@@ -1315,9 +1317,13 @@ int hid_pidff_init(struct hid_device *hid) ...@@ -1315,9 +1317,13 @@ int hid_pidff_init(struct hid_device *hid)
hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n"); hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
hid_device_io_stop(hid);
return 0; return 0;
fail: fail:
hid_device_io_stop(hid);
kfree(pidff); kfree(pidff);
return error; return error;
} }
...@@ -80,6 +80,7 @@ static const struct hid_blacklist { ...@@ -80,6 +80,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
......
...@@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev, ...@@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
{ {
struct wacom *wacom = hid_get_drvdata(hdev); struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features; struct wacom_features *features = &wacom->wacom_wac.features;
bool finger = (field->logical == HID_DG_FINGER) || bool finger = WACOM_FINGER_FIELD(field);
(field->physical == HID_DG_FINGER); bool pen = WACOM_PEN_FIELD(field);
bool pen = (field->logical == HID_DG_STYLUS) ||
(field->physical == HID_DG_STYLUS);
/* /*
* Requiring Stylus Usage will ignore boot mouse * Requiring Stylus Usage will ignore boot mouse
...@@ -405,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev, ...@@ -405,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) { else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
return wacom_set_device_mode(hdev, 18, 3, 2); return wacom_set_device_mode(hdev, 18, 3, 2);
} }
else if (features->type == WACOM_27QHDT) {
return wacom_set_device_mode(hdev, 131, 3, 2);
}
} else if (features->device_type == BTN_TOOL_PEN) { } else if (features->device_type == BTN_TOOL_PEN) {
if (features->type <= BAMBOO_PT && features->type != WIRELESS) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
return wacom_set_device_mode(hdev, 2, 2, 2); return wacom_set_device_mode(hdev, 2, 2, 2);
......
This diff is collapsed.
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
#define WACOM_WAC_H #define WACOM_WAC_H
#include <linux/types.h> #include <linux/types.h>
#include <linux/hid.h>
/* maximum packet length for USB devices */ /* maximum packet length for USB devices */
#define WACOM_PKGLEN_MAX 68 #define WACOM_PKGLEN_MAX 192
#define WACOM_NAME_MAX 64 #define WACOM_NAME_MAX 64
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
/* wacom data size per MT contact */ /* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11 #define WACOM_BYTES_PER_MT_PACKET 11
#define WACOM_BYTES_PER_24HDT_PACKET 14 #define WACOM_BYTES_PER_24HDT_PACKET 14
#define WACOM_BYTES_PER_QHDTHID_PACKET 6
/* device IDs */ /* device IDs */
#define STYLUS_DEVICE_ID 0x02 #define STYLUS_DEVICE_ID 0x02
...@@ -57,6 +59,8 @@ ...@@ -57,6 +59,8 @@
#define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCMT2 3 #define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15 #define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_CINTIQ 16
#define WACOM_REPORT_CINTIQPAD 17
#define WACOM_REPORT_TPCST 16 #define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17 #define WACOM_REPORT_DTUS 17
#define WACOM_REPORT_TPC1FGE 18 #define WACOM_REPORT_TPC1FGE 18
...@@ -71,6 +75,14 @@ ...@@ -71,6 +75,14 @@
#define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_MONITOR 0x0008
#define WACOM_QUIRK_BATTERY 0x0010 #define WACOM_QUIRK_BATTERY 0x0010
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
((f)->physical == HID_DG_STYLUS) || \
((f)->physical == HID_DG_PEN) || \
((f)->application == HID_DG_PEN))
#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
((f)->physical == HID_DG_FINGER) || \
((f)->application == HID_DG_TOUCHSCREEN))
enum { enum {
PENPARTNER = 0, PENPARTNER = 0,
GRAPHIRE, GRAPHIRE,
...@@ -100,6 +112,7 @@ enum { ...@@ -100,6 +112,7 @@ enum {
WACOM_22HD, WACOM_22HD,
DTK, DTK,
WACOM_24HD, WACOM_24HD,
WACOM_27QHD,
CINTIQ_HYBRID, CINTIQ_HYBRID,
CINTIQ, CINTIQ,
WACOM_BEE, WACOM_BEE,
...@@ -108,6 +121,7 @@ enum { ...@@ -108,6 +121,7 @@ enum {
WIRELESS, WIRELESS,
BAMBOO_PT, BAMBOO_PT,
WACOM_24HDT, WACOM_24HDT,
WACOM_27QHDT,
TABLETPC, /* add new TPC below */ TABLETPC, /* add new TPC below */
TABLETPCE, TABLETPCE,
TABLETPC2FG, TABLETPC2FG,
...@@ -180,6 +194,7 @@ struct wacom_wac { ...@@ -180,6 +194,7 @@ struct wacom_wac {
int tool[2]; int tool[2];
int id[2]; int id[2];
__u32 serial[2]; __u32 serial[2];
bool reporting_data;
struct wacom_features features; struct wacom_features features;
struct wacom_shared *shared; struct wacom_shared *shared;
struct input_dev *input; struct input_dev *input;
......
...@@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data) ...@@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
#define HID_GLOBAL_STACK_SIZE 4 #define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4 #define HID_COLLECTION_STACK_SIZE 4
#define HID_SCAN_FLAG_MT_WIN_8 0x00000001 #define HID_SCAN_FLAG_MT_WIN_8 BIT(0)
#define HID_SCAN_FLAG_VENDOR_SPECIFIC BIT(1)
#define HID_SCAN_FLAG_GD_POINTER BIT(2)
struct hid_parser { struct hid_parser {
struct hid_global global; struct hid_global global;
......
...@@ -166,6 +166,7 @@ struct input_keymap_entry { ...@@ -166,6 +166,7 @@ struct input_keymap_entry {
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ #define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ #define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ #define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */
#define INPUT_PROP_MAX 0x1f #define INPUT_PROP_MAX 0x1f
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment