forked from Minki/linux
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
This commit is contained in:
commit
988b7fb0bf
@ -147,6 +147,16 @@ config HID_BELKIN
|
||||
---help---
|
||||
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
|
||||
tristate "Cherry Cymotion keyboard" if EXPERT
|
||||
depends on HID
|
||||
@ -389,7 +399,7 @@ config HID_LOGITECH_HIDPP
|
||||
Say Y if you want support for Logitech devices relying on the HID++
|
||||
specification. Such devices are the various Logitech Touchpads (T650,
|
||||
T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar
|
||||
Keayboard).
|
||||
Keyboard).
|
||||
|
||||
config LOGITECH_FF
|
||||
bool "Logitech force feedback support"
|
||||
|
@ -2,10 +2,7 @@
|
||||
# Makefile for the HID driver
|
||||
#
|
||||
hid-y := hid-core.o hid-input.o
|
||||
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
hid-objs += hid-debug.o
|
||||
endif
|
||||
hid-$(CONFIG_DEBUG_FS) += hid-debug.o
|
||||
|
||||
obj-$(CONFIG_HID) += hid.o
|
||||
obj-$(CONFIG_UHID) += uhid.o
|
||||
@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o
|
||||
hid-$(CONFIG_HIDRAW) += hidraw.o
|
||||
|
||||
hid-logitech-y := hid-lg.o
|
||||
ifdef CONFIG_LOGITECH_FF
|
||||
hid-logitech-y += hid-lgff.o
|
||||
endif
|
||||
ifdef CONFIG_LOGIRUMBLEPAD2_FF
|
||||
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-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o
|
||||
hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o
|
||||
hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o
|
||||
hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o
|
||||
|
||||
hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
hid-wiimote-y += hid-wiimote-debug.o
|
||||
endif
|
||||
hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
|
||||
|
||||
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
|
||||
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
|
||||
@ -39,6 +26,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
|
||||
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
|
||||
obj-$(CONFIG_HID_AUREAL) += hid-aureal.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_CHICONY) += hid-chicony.o
|
||||
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
|
||||
@ -76,24 +64,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o
|
||||
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
|
||||
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
|
||||
hid-picolcd-y += hid-picolcd_core.o
|
||||
ifdef CONFIG_HID_PICOLCD_FB
|
||||
hid-picolcd-y += hid-picolcd_fb.o
|
||||
endif
|
||||
ifdef CONFIG_HID_PICOLCD_BACKLIGHT
|
||||
hid-picolcd-y += hid-picolcd_backlight.o
|
||||
endif
|
||||
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
|
||||
hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o
|
||||
hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o
|
||||
hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o
|
||||
hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o
|
||||
hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o
|
||||
hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
|
||||
|
||||
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
|
||||
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
|
||||
|
160
drivers/hid/hid-betopff.c
Normal file
160
drivers/hid/hid-betopff.c
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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)
|
||||
static void hid_scan_collection(struct hid_parser *parser, unsigned type)
|
||||
{
|
||||
struct hid_device *hid = parser->device;
|
||||
int i;
|
||||
|
||||
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
|
||||
type == HID_COLLECTION_PHYSICAL)
|
||||
hid->group = HID_GROUP_SENSOR_HUB;
|
||||
|
||||
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_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)
|
||||
@ -792,11 +802,14 @@ static int hid_scan_report(struct hid_device *hid)
|
||||
hid->group = HID_GROUP_WACOM;
|
||||
break;
|
||||
case USB_VENDOR_ID_SYNAPTICS:
|
||||
if ((hid->group == HID_GROUP_GENERIC) &&
|
||||
(hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE))
|
||||
/* hid-rmi should only bind to the mouse interface of
|
||||
* composite USB devices */
|
||||
hid->group = HID_GROUP_RMI;
|
||||
if (hid->group == HID_GROUP_GENERIC)
|
||||
if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
|
||||
&& (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
|
||||
/*
|
||||
* hid-rmi should take care of them,
|
||||
* not hid-generic
|
||||
*/
|
||||
hid->group = HID_GROUP_RMI;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -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_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
|
||||
{ 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_2) },
|
||||
{ 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[] = {
|
||||
{ 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_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_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
|
||||
{ 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[] = {
|
||||
{ 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_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)
|
||||
static int mousevsc_connect_to_vsp(struct hv_device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
int t;
|
||||
unsigned long t;
|
||||
struct mousevsc_dev *input_dev = hv_get_drvdata(device);
|
||||
struct mousevsc_prt_msg *request;
|
||||
struct mousevsc_prt_msg *response;
|
||||
|
@ -189,6 +189,11 @@
|
||||
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
|
||||
#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_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
|
||||
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
|
||||
@ -655,6 +660,7 @@
|
||||
#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_3 0x07dc
|
||||
#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd
|
||||
|
||||
#define USB_VENDOR_ID_MOJO 0x8282
|
||||
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
|
||||
@ -769,6 +775,9 @@
|
||||
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
|
||||
#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_DEVICE_ID_REALTEK_READER 0x0152
|
||||
|
||||
|
@ -306,10 +306,13 @@ static enum power_supply_property hidinput_battery_props[] = {
|
||||
|
||||
static const struct hid_device_id hid_battery_quirks[] = {
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
|
||||
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
|
||||
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
|
||||
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
|
||||
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
|
||||
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
|
||||
@ -1104,6 +1107,23 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
|
||||
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 */
|
||||
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
|
||||
input_event(input, EV_MSC, MSC_SCAN, usage->hid);
|
||||
|
@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd {
|
||||
|
||||
struct lenovo_drvdata_cptkbd {
|
||||
bool fn_lock;
|
||||
int sensitivity;
|
||||
};
|
||||
|
||||
#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,
|
||||
case 0x00fa: /* Fn-Esc: Fn-lock toggle */
|
||||
map_key_clear(KEY_FN_ESC);
|
||||
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)
|
||||
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, 0x02, cptkbd_data->sensitivity);
|
||||
if (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,
|
||||
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 =
|
||||
__ATTR(fn_lock, S_IWUSR | S_IRUGO,
|
||||
attr_fn_lock_show_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[] = {
|
||||
&dev_attr_fn_lock_cptkbd.attr,
|
||||
&dev_attr_sensitivity_cptkbd.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -594,8 +665,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
|
||||
if (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->sensitivity = 0x05;
|
||||
lenovo_features_set_cptkbd(hdev);
|
||||
|
||||
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
|
||||
|
@ -49,10 +49,6 @@
|
||||
|
||||
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 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 {
|
||||
__u32 product_id;
|
||||
@ -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 */
|
||||
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 lg4ff_device_entry *entry;
|
||||
@ -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
|
||||
* 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 lg4ff_device_entry *entry;
|
||||
@ -472,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(range);
|
||||
|
||||
#ifdef CONFIG_LEDS_CLASS
|
||||
static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
|
||||
|
@ -89,6 +89,7 @@ struct hidpp_device {
|
||||
struct hid_device *hid_dev;
|
||||
struct mutex send_mutex;
|
||||
void *send_receive_buf;
|
||||
char *name; /* will never be NULL and should not be freed */
|
||||
wait_queue_head_t wait;
|
||||
bool answer_available;
|
||||
u8 protocol_major;
|
||||
@ -105,6 +106,7 @@ struct hidpp_device {
|
||||
};
|
||||
|
||||
|
||||
/* HID++ 1.0 error codes */
|
||||
#define HIDPP_ERROR 0x8f
|
||||
#define HIDPP_ERROR_SUCCESS 0x00
|
||||
#define HIDPP_ERROR_INVALID_SUBID 0x01
|
||||
@ -119,6 +121,8 @@ struct hidpp_device {
|
||||
#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
|
||||
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
|
||||
#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);
|
||||
|
||||
@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
|
||||
}
|
||||
|
||||
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];
|
||||
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;
|
||||
}
|
||||
|
||||
@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question,
|
||||
static inline bool hidpp_match_error(struct hidpp_report *question,
|
||||
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.params[0] == question->fap.funcindex_clientid);
|
||||
}
|
||||
@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
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 wtp_data *wd = hidpp->private_data;
|
||||
int ret;
|
||||
|
||||
if (!connected)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (!wd->x_size) {
|
||||
ret = wtp_get_config(hidpp);
|
||||
if (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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
* previoulsly sent command
|
||||
* previously sent command.
|
||||
*/
|
||||
if (unlikely(mutex_is_locked(&hidpp->send_mutex))) {
|
||||
/*
|
||||
@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
|
||||
return wtp_raw_event(hidpp->hid_dev, data, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
u8 *data, int size)
|
||||
{
|
||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||
int ret = 0;
|
||||
|
||||
/* Generic HID++ processing. */
|
||||
switch (data[0]) {
|
||||
case REPORT_ID_HIDPP_LONG:
|
||||
if (size != HIDPP_REPORT_LONG_LENGTH) {
|
||||
@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
size);
|
||||
return 1;
|
||||
}
|
||||
return hidpp_raw_hidpp_event(hidpp, data, size);
|
||||
ret = hidpp_raw_hidpp_event(hidpp, data, size);
|
||||
break;
|
||||
case REPORT_ID_HIDPP_SHORT:
|
||||
if (size != HIDPP_REPORT_SHORT_LENGTH) {
|
||||
hid_err(hdev, "received hid++ report of bad size (%d)",
|
||||
size);
|
||||
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)
|
||||
return wtp_raw_event(hdev, data, size);
|
||||
|
||||
@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev)
|
||||
static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
|
||||
{
|
||||
struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev);
|
||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||
|
||||
if (!input_dev)
|
||||
return NULL;
|
||||
@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
|
||||
input_dev->open = hidpp_input_open;
|
||||
input_dev->close = hidpp_input_close;
|
||||
|
||||
input_dev->name = hdev->name;
|
||||
input_dev->name = hidpp->name;
|
||||
input_dev->phys = hdev->phys;
|
||||
input_dev->uniq = hdev->uniq;
|
||||
input_dev->id.bustype = hdev->bus;
|
||||
@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
struct input_dev *input;
|
||||
char *name, *devm_name;
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
|
||||
wtp_connect(hdev, connected);
|
||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
|
||||
ret = wtp_connect(hdev, connected);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connected || hidpp->delayed_input)
|
||||
return;
|
||||
@ -1117,22 +1139,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
hid_info(hdev, "HID++ %u.%u device connected.\n",
|
||||
hidpp->protocol_major, hidpp->protocol_minor);
|
||||
|
||||
if (!hidpp->name || hidpp->name == hdev->name) {
|
||||
name = hidpp_get_device_name(hidpp);
|
||||
if (!name) {
|
||||
hid_err(hdev,
|
||||
"unable to retrieve the name of the device");
|
||||
return;
|
||||
}
|
||||
|
||||
devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", 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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (devm_name)
|
||||
input->name = devm_name;
|
||||
kfree(name);
|
||||
}
|
||||
|
||||
hidpp_populate_input(hidpp, input, false);
|
||||
|
||||
ret = input_register_device(input);
|
||||
@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return -ENOMEM;
|
||||
|
||||
hidpp->hid_dev = hdev;
|
||||
hidpp->name = hdev->name;
|
||||
hid_set_drvdata(hdev, hidpp);
|
||||
|
||||
hidpp->quirks = id->driver_data;
|
||||
|
@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = {
|
||||
.driver_data = MS_DUPLICATE_USAGES },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
|
||||
.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),
|
||||
.driver_data = MS_PRESENTER },
|
||||
|
@ -33,6 +33,10 @@
|
||||
#define RMI_READ_DATA_PENDING BIT(1)
|
||||
#define RMI_STARTED BIT(2)
|
||||
|
||||
/* device flags */
|
||||
#define RMI_DEVICE BIT(0)
|
||||
#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1)
|
||||
|
||||
enum rmi_mode_type {
|
||||
RMI_MODE_OFF = 0,
|
||||
RMI_MODE_ATTN_REPORTS = 1,
|
||||
@ -118,6 +122,8 @@ struct rmi_data {
|
||||
|
||||
struct work_struct reset_work;
|
||||
struct hid_device *hdev;
|
||||
|
||||
unsigned long device_flags;
|
||||
};
|
||||
|
||||
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
|
||||
@ -452,9 +458,32 @@ static int rmi_raw_event(struct hid_device *hdev,
|
||||
return rmi_read_data_event(hdev, data, size);
|
||||
case RMI_ATTN_REPORT_ID:
|
||||
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);
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -856,6 +885,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
if (!(data->device_flags & RMI_DEVICE))
|
||||
return;
|
||||
|
||||
/* Allow incoming hid reports */
|
||||
hid_device_io_start(hdev);
|
||||
|
||||
@ -914,8 +946,38 @@ static int rmi_input_mapping(struct hid_device *hdev,
|
||||
struct hid_input *hi, struct hid_field *field,
|
||||
struct hid_usage *usage, unsigned long **bit, int *max)
|
||||
{
|
||||
/* we want to make HID ignore the advertised HID collection */
|
||||
return -1;
|
||||
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 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)
|
||||
@ -925,6 +987,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
size_t alloc_size;
|
||||
struct hid_report *input_report;
|
||||
struct hid_report *output_report;
|
||||
struct hid_report *feature_report;
|
||||
|
||||
data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
@ -943,27 +1006,37 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
input_report = hdev->report_enum[HID_INPUT_REPORT]
|
||||
.report_id_hash[RMI_ATTN_REPORT_ID];
|
||||
if (!input_report) {
|
||||
hid_err(hdev, "device does not have expected input report\n");
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
if (id->driver_data)
|
||||
data->device_flags = id->driver_data;
|
||||
|
||||
/*
|
||||
* Check for the RMI specific report ids. If they are misisng
|
||||
* 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 */;
|
||||
|
||||
output_report = hdev->report_enum[HID_OUTPUT_REPORT]
|
||||
.report_id_hash[RMI_WRITE_REPORT_ID];
|
||||
if (!output_report) {
|
||||
hid_err(hdev, "device does not have expected output report\n");
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
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;
|
||||
}
|
||||
|
||||
data->output_report_size = (output_report->size >> 3)
|
||||
+ 1 /* report id */;
|
||||
data->input_report_size = hid_report_len(input_report);
|
||||
|
||||
if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT,
|
||||
RMI_WRITE_REPORT_ID, &output_report)) {
|
||||
hid_dbg(hdev,
|
||||
"device does not have rmi write output report\n");
|
||||
goto start;
|
||||
}
|
||||
|
||||
data->output_report_size = hid_report_len(output_report);
|
||||
|
||||
data->device_flags |= RMI_DEVICE;
|
||||
alloc_size = data->output_report_size + data->input_report_size;
|
||||
|
||||
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)
|
||||
|
||||
mutex_init(&data->page_mutex);
|
||||
|
||||
start:
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
if (ret) {
|
||||
hid_err(hdev, "hw start failed\n");
|
||||
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
|
||||
* 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)
|
||||
}
|
||||
|
||||
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) },
|
||||
{ }
|
||||
};
|
||||
@ -1017,6 +1094,7 @@ static struct hid_driver rmi_driver = {
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_probe,
|
||||
.remove = rmi_remove,
|
||||
.event = rmi_event,
|
||||
.raw_event = rmi_raw_event,
|
||||
.input_mapping = rmi_input_mapping,
|
||||
.input_configured = rmi_input_configured,
|
||||
|
@ -2,17 +2,9 @@
|
||||
# Makefile for the USB input drivers
|
||||
#
|
||||
|
||||
# Multipart objects.
|
||||
usbhid-y := hid-core.o hid-quirks.o
|
||||
|
||||
# Optional parts of multipart objects.
|
||||
|
||||
ifeq ($(CONFIG_USB_HIDDEV),y)
|
||||
usbhid-y += hiddev.o
|
||||
endif
|
||||
ifeq ($(CONFIG_HID_PID),y)
|
||||
usbhid-y += hid-pidff.o
|
||||
endif
|
||||
usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o
|
||||
usbhid-$(CONFIG_HID_PID) += hid-pidff.o
|
||||
|
||||
obj-$(CONFIG_USB_HID) += usbhid.o
|
||||
obj-$(CONFIG_USB_KBD) += usbkbd.o
|
||||
|
@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid)
|
||||
|
||||
pidff->hid = hid;
|
||||
|
||||
hid_device_io_start(hid);
|
||||
|
||||
pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
|
||||
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
|
||||
|
||||
@ -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_device_io_stop(hid);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
hid_device_io_stop(hid);
|
||||
|
||||
kfree(pidff);
|
||||
return error;
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ static const struct hid_blacklist {
|
||||
{ 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_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_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 },
|
||||
|
@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
|
||||
{
|
||||
struct wacom *wacom = hid_get_drvdata(hdev);
|
||||
struct wacom_features *features = &wacom->wacom_wac.features;
|
||||
bool finger = (field->logical == HID_DG_FINGER) ||
|
||||
(field->physical == HID_DG_FINGER);
|
||||
bool pen = (field->logical == HID_DG_STYLUS) ||
|
||||
(field->physical == HID_DG_STYLUS);
|
||||
bool finger = WACOM_FINGER_FIELD(field);
|
||||
bool pen = WACOM_PEN_FIELD(field);
|
||||
|
||||
/*
|
||||
* Requiring Stylus Usage will ignore boot mouse
|
||||
@ -405,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
|
||||
else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
|
||||
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) {
|
||||
if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
|
||||
return wacom_set_device_mode(hdev, 2, 2, 2);
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "wacom_wac.h"
|
||||
#include "wacom.h"
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
/* resolution for penabled devices */
|
||||
#define WACOM_PL_RES 20
|
||||
@ -444,9 +443,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
|
||||
/* Enter report */
|
||||
if ((data[1] & 0xfc) == 0xc0) {
|
||||
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = true;
|
||||
|
||||
/* serial number of the tool */
|
||||
wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
|
||||
(data[4] << 20) + (data[5] << 12) +
|
||||
@ -535,24 +531,46 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* don't report events for invalid data
|
||||
*/
|
||||
/* older I4 styli don't work with new Cintiqs */
|
||||
if (!((wacom->id[idx] >> 20) & 0x01) &&
|
||||
(features->type == WACOM_21UX2))
|
||||
if ((!((wacom->id[idx] >> 20) & 0x01) &&
|
||||
(features->type == WACOM_21UX2)) ||
|
||||
/* Only large Intuos support Lense Cursor */
|
||||
(wacom->tool[idx] == BTN_TOOL_LENS &&
|
||||
(features->type == INTUOS3 ||
|
||||
features->type == INTUOS3S ||
|
||||
features->type == INTUOS4 ||
|
||||
features->type == INTUOS4S ||
|
||||
features->type == INTUOS5 ||
|
||||
features->type == INTUOS5S ||
|
||||
features->type == INTUOSPM ||
|
||||
features->type == INTUOSPS)) ||
|
||||
/* Cintiq doesn't send data when RDY bit isn't set */
|
||||
(features->type == CINTIQ && !(data[1] & 0x40)))
|
||||
return 1;
|
||||
|
||||
/* Range Report */
|
||||
if ((data[1] & 0xfe) == 0x20) {
|
||||
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = true;
|
||||
|
||||
/* in Range while exiting */
|
||||
if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
|
||||
input_report_key(input, BTN_TOUCH, 0);
|
||||
input_report_abs(input, ABS_PRESSURE, 0);
|
||||
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
|
||||
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = true;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Exit report */
|
||||
if ((data[1] & 0xfe) == 0x80) {
|
||||
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
|
||||
wacom->shared->stylus_in_proximity = false;
|
||||
wacom->reporting_data = false;
|
||||
|
||||
/* don't report exit if we don't know the ID */
|
||||
if (!wacom->id[idx])
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Reset all states otherwise we lose the initial states
|
||||
@ -586,6 +604,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
|
||||
wacom->id[idx] = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* don't report other events if we don't know the ID */
|
||||
if (!wacom->id[idx])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -633,6 +656,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
data[0] != WACOM_REPORT_INTUOSREAD &&
|
||||
data[0] != WACOM_REPORT_INTUOSWRITE &&
|
||||
data[0] != WACOM_REPORT_INTUOSPAD &&
|
||||
data[0] != WACOM_REPORT_CINTIQ &&
|
||||
data[0] != WACOM_REPORT_CINTIQPAD &&
|
||||
data[0] != WACOM_REPORT_INTUOS5PAD) {
|
||||
dev_dbg(input->dev.parent,
|
||||
"%s: received unknown report #%d\n", __func__, data[0]);
|
||||
@ -644,7 +669,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
idx = data[1] & 0x01;
|
||||
|
||||
/* pad packets. Works as a second tool and is always in prox */
|
||||
if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
|
||||
if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
|
||||
data[0] == WACOM_REPORT_CINTIQPAD) {
|
||||
input = wacom->pad_input;
|
||||
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
|
||||
input_report_key(input, BTN_0, (data[2] & 0x01));
|
||||
@ -744,6 +770,14 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
} else {
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
}
|
||||
} else if (features->type == WACOM_27QHD) {
|
||||
input_report_key(input, KEY_PROG1, data[2] & 0x01);
|
||||
input_report_key(input, KEY_PROG2, data[2] & 0x02);
|
||||
input_report_key(input, KEY_PROG3, data[2] & 0x04);
|
||||
|
||||
input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
|
||||
input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
|
||||
input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
|
||||
} else if (features->type == CINTIQ_HYBRID) {
|
||||
/*
|
||||
* Do not send hardware buttons under Android. They
|
||||
@ -760,6 +794,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */
|
||||
input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */
|
||||
input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */
|
||||
|
||||
if (data[4] | (data[3] & 0x01)) {
|
||||
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
|
||||
} else {
|
||||
input_report_abs(input, ABS_MISC, 0);
|
||||
}
|
||||
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
|
||||
int i;
|
||||
|
||||
@ -843,28 +883,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
if (result)
|
||||
return result - 1;
|
||||
|
||||
/* don't proceed if we don't know the ID */
|
||||
if (!wacom->id[idx])
|
||||
return 0;
|
||||
|
||||
/* Only large Intuos support Lense Cursor */
|
||||
if (wacom->tool[idx] == BTN_TOOL_LENS &&
|
||||
(features->type == INTUOS3 ||
|
||||
features->type == INTUOS3S ||
|
||||
features->type == INTUOS4 ||
|
||||
features->type == INTUOS4S ||
|
||||
features->type == INTUOS5 ||
|
||||
features->type == INTUOS5S ||
|
||||
features->type == INTUOSPM ||
|
||||
features->type == INTUOSPS)) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cintiq doesn't send data when RDY bit isn't set */
|
||||
if (features->type == CINTIQ && !(data[1] & 0x40))
|
||||
return 0;
|
||||
|
||||
if (features->type >= INTUOS3S) {
|
||||
input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
|
||||
input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
|
||||
@ -951,6 +969,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
||||
input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
|
||||
input_report_key(input, wacom->tool[idx], 1);
|
||||
input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
|
||||
wacom->reporting_data = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1019,8 +1038,20 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
||||
struct input_dev *input = wacom->input;
|
||||
unsigned char *data = wacom->data;
|
||||
int i;
|
||||
int current_num_contacts = data[61];
|
||||
int current_num_contacts = 0;
|
||||
int contacts_to_send = 0;
|
||||
int num_contacts_left = 4; /* maximum contacts per packet */
|
||||
int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
|
||||
int y_offset = 2;
|
||||
|
||||
if (wacom->features.type == WACOM_27QHDT) {
|
||||
current_num_contacts = data[63];
|
||||
num_contacts_left = 10;
|
||||
byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
|
||||
y_offset = 0;
|
||||
} else {
|
||||
current_num_contacts = data[61];
|
||||
}
|
||||
|
||||
/*
|
||||
* First packet resets the counter since only the first
|
||||
@ -1029,12 +1060,11 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
||||
if (current_num_contacts)
|
||||
wacom->num_contacts_left = current_num_contacts;
|
||||
|
||||
/* There are at most 4 contacts per packet */
|
||||
contacts_to_send = min(4, wacom->num_contacts_left);
|
||||
contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
|
||||
|
||||
for (i = 0; i < contacts_to_send; i++) {
|
||||
int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
|
||||
bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
|
||||
int offset = (byte_per_packet * i) + 1;
|
||||
bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
|
||||
int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
|
||||
|
||||
if (slot < 0)
|
||||
@ -1044,18 +1074,23 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
||||
|
||||
if (touch) {
|
||||
int t_x = get_unaligned_le16(&data[offset + 2]);
|
||||
int c_x = get_unaligned_le16(&data[offset + 4]);
|
||||
int t_y = get_unaligned_le16(&data[offset + 6]);
|
||||
int c_y = get_unaligned_le16(&data[offset + 8]);
|
||||
int w = get_unaligned_le16(&data[offset + 10]);
|
||||
int h = get_unaligned_le16(&data[offset + 12]);
|
||||
int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]);
|
||||
|
||||
input_report_abs(input, ABS_MT_POSITION_X, t_x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, t_y);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
|
||||
input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y));
|
||||
input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
|
||||
input_report_abs(input, ABS_MT_ORIENTATION, w > h);
|
||||
|
||||
if (wacom->features.type != WACOM_27QHDT) {
|
||||
int c_x = get_unaligned_le16(&data[offset + 4]);
|
||||
int c_y = get_unaligned_le16(&data[offset + 8]);
|
||||
int w = get_unaligned_le16(&data[offset + 10]);
|
||||
int h = get_unaligned_le16(&data[offset + 12]);
|
||||
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
|
||||
input_report_abs(input, ABS_MT_WIDTH_MAJOR,
|
||||
min(w, h) + int_dist(t_x, t_y, c_x, c_y));
|
||||
input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
|
||||
input_report_abs(input, ABS_MT_ORIENTATION, w > h);
|
||||
}
|
||||
}
|
||||
}
|
||||
input_mt_report_pointer_emulation(input, true);
|
||||
@ -1064,6 +1099,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
|
||||
if (wacom->num_contacts_left <= 0)
|
||||
wacom->num_contacts_left = 0;
|
||||
|
||||
wacom->shared->touch_down = (wacom->num_contacts_left > 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1092,7 +1128,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
|
||||
|
||||
for (i = 0; i < contacts_to_send; i++) {
|
||||
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
|
||||
bool touch = data[offset] & 0x1;
|
||||
bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
|
||||
int id = get_unaligned_le16(&data[offset + 1]);
|
||||
int slot = input_mt_get_slot_by_key(input, id);
|
||||
|
||||
@ -1114,6 +1150,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
|
||||
if (wacom->num_contacts_left < 0)
|
||||
wacom->num_contacts_left = 0;
|
||||
|
||||
wacom->shared->touch_down = (wacom->num_contacts_left > 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1514,13 +1551,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
|
||||
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev);
|
||||
}
|
||||
|
||||
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
|
||||
((f)->physical == HID_DG_STYLUS) || \
|
||||
((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))
|
||||
|
||||
void wacom_wac_usage_mapping(struct hid_device *hdev,
|
||||
struct hid_field *field, struct hid_usage *usage)
|
||||
{
|
||||
@ -1891,6 +1921,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
case WACOM_21UX2:
|
||||
case WACOM_22HD:
|
||||
case WACOM_24HD:
|
||||
case WACOM_27QHD:
|
||||
case DTK:
|
||||
case CINTIQ_HYBRID:
|
||||
sync = wacom_intuos_irq(wacom_wac);
|
||||
@ -1901,6 +1932,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
|
||||
break;
|
||||
|
||||
case WACOM_24HDT:
|
||||
case WACOM_27QHDT:
|
||||
sync = wacom_24hdt_irq(wacom_wac);
|
||||
break;
|
||||
|
||||
@ -2086,8 +2118,14 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
wacom_abs_set_axis(input_dev, wacom_wac);
|
||||
|
||||
switch (features->type) {
|
||||
case GRAPHIRE_BT:
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
|
||||
case WACOM_MO:
|
||||
case WACOM_G4:
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||
features->distance_max,
|
||||
0, 0);
|
||||
/* fall through */
|
||||
|
||||
case GRAPHIRE:
|
||||
@ -2106,52 +2144,15 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
break;
|
||||
|
||||
case GRAPHIRE_BT:
|
||||
__clear_bit(ABS_MISC, input_dev->absbit);
|
||||
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
|
||||
features->distance_max,
|
||||
0, 0);
|
||||
|
||||
input_set_capability(input_dev, EV_REL, REL_WHEEL);
|
||||
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||
__set_bit(BTN_MIDDLE, input_dev->keybit);
|
||||
|
||||
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS, input_dev->keybit);
|
||||
__set_bit(BTN_STYLUS2, input_dev->keybit);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
break;
|
||||
|
||||
case WACOM_27QHD:
|
||||
case WACOM_24HD:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
|
||||
/* fall through */
|
||||
|
||||
case DTK:
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
|
||||
wacom_setup_cintiq(wacom_wac);
|
||||
break;
|
||||
|
||||
case WACOM_22HD:
|
||||
case WACOM_21UX2:
|
||||
case WACOM_BEE:
|
||||
case CINTIQ:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
|
||||
wacom_setup_cintiq(wacom_wac);
|
||||
break;
|
||||
|
||||
case WACOM_13HD:
|
||||
case CINTIQ_HYBRID:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
@ -2161,6 +2162,10 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
case INTUOS3:
|
||||
case INTUOS3L:
|
||||
case INTUOS3S:
|
||||
case INTUOS4:
|
||||
case INTUOS4WL:
|
||||
case INTUOS4L:
|
||||
case INTUOS4S:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
/* fall through */
|
||||
@ -2199,17 +2204,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
}
|
||||
break;
|
||||
|
||||
case INTUOS4:
|
||||
case INTUOS4WL:
|
||||
case INTUOS4L:
|
||||
case INTUOS4S:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
wacom_setup_intuos(wacom_wac);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
break;
|
||||
|
||||
case WACOM_24HDT:
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
|
||||
@ -2219,6 +2213,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case WACOM_27QHDT:
|
||||
case MTSCREEN:
|
||||
case MTTPC:
|
||||
case MTTPC_B:
|
||||
@ -2305,14 +2300,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
|
||||
0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case CINTIQ_HYBRID:
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 287);
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
|
||||
wacom_setup_cintiq(wacom_wac);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2374,6 +2361,19 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
|
||||
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
|
||||
break;
|
||||
|
||||
case WACOM_27QHD:
|
||||
__set_bit(KEY_PROG1, input_dev->keybit);
|
||||
__set_bit(KEY_PROG2, input_dev->keybit);
|
||||
__set_bit(KEY_PROG3, input_dev->keybit);
|
||||
input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
|
||||
input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Y, 1024);
|
||||
input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0);
|
||||
input_abs_set_res(input_dev, ABS_Z, 1024);
|
||||
__set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
|
||||
break;
|
||||
|
||||
case DTK:
|
||||
for (i = 0; i < 6; i++)
|
||||
__set_bit(BTN_0 + i, input_dev->keybit);
|
||||
@ -2724,6 +2724,18 @@ static const struct wacom_features wacom_features_0xF6 =
|
||||
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
|
||||
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
|
||||
static const struct wacom_features wacom_features_0x32A =
|
||||
{ "Wacom Cintiq 27QHD", 119740, 67520, 2047,
|
||||
63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
static const struct wacom_features wacom_features_0x32B =
|
||||
{ "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
|
||||
WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
|
||||
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C };
|
||||
static const struct wacom_features wacom_features_0x32C =
|
||||
{ "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT,
|
||||
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 };
|
||||
static const struct wacom_features wacom_features_0x3F =
|
||||
{ "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
|
||||
CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
|
||||
@ -3090,6 +3102,9 @@ const struct hid_device_id wacom_ids[] = {
|
||||
{ USB_DEVICE_WACOM(0x315) },
|
||||
{ USB_DEVICE_WACOM(0x317) },
|
||||
{ USB_DEVICE_WACOM(0x323) },
|
||||
{ USB_DEVICE_WACOM(0x32A) },
|
||||
{ USB_DEVICE_WACOM(0x32B) },
|
||||
{ USB_DEVICE_WACOM(0x32C) },
|
||||
{ USB_DEVICE_WACOM(0x32F) },
|
||||
{ USB_DEVICE_WACOM(0x4001) },
|
||||
{ USB_DEVICE_WACOM(0x4004) },
|
||||
|
@ -10,9 +10,10 @@
|
||||
#define WACOM_WAC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
/* maximum packet length for USB devices */
|
||||
#define WACOM_PKGLEN_MAX 68
|
||||
#define WACOM_PKGLEN_MAX 192
|
||||
|
||||
#define WACOM_NAME_MAX 64
|
||||
|
||||
@ -36,6 +37,7 @@
|
||||
/* wacom data size per MT contact */
|
||||
#define WACOM_BYTES_PER_MT_PACKET 11
|
||||
#define WACOM_BYTES_PER_24HDT_PACKET 14
|
||||
#define WACOM_BYTES_PER_QHDTHID_PACKET 6
|
||||
|
||||
/* device IDs */
|
||||
#define STYLUS_DEVICE_ID 0x02
|
||||
@ -57,6 +59,8 @@
|
||||
#define WACOM_REPORT_TPCMT 13
|
||||
#define WACOM_REPORT_TPCMT2 3
|
||||
#define WACOM_REPORT_TPCHID 15
|
||||
#define WACOM_REPORT_CINTIQ 16
|
||||
#define WACOM_REPORT_CINTIQPAD 17
|
||||
#define WACOM_REPORT_TPCST 16
|
||||
#define WACOM_REPORT_DTUS 17
|
||||
#define WACOM_REPORT_TPC1FGE 18
|
||||
@ -71,6 +75,14 @@
|
||||
#define WACOM_QUIRK_MONITOR 0x0008
|
||||
#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 {
|
||||
PENPARTNER = 0,
|
||||
GRAPHIRE,
|
||||
@ -100,6 +112,7 @@ enum {
|
||||
WACOM_22HD,
|
||||
DTK,
|
||||
WACOM_24HD,
|
||||
WACOM_27QHD,
|
||||
CINTIQ_HYBRID,
|
||||
CINTIQ,
|
||||
WACOM_BEE,
|
||||
@ -108,6 +121,7 @@ enum {
|
||||
WIRELESS,
|
||||
BAMBOO_PT,
|
||||
WACOM_24HDT,
|
||||
WACOM_27QHDT,
|
||||
TABLETPC, /* add new TPC below */
|
||||
TABLETPCE,
|
||||
TABLETPC2FG,
|
||||
@ -180,6 +194,7 @@ struct wacom_wac {
|
||||
int tool[2];
|
||||
int id[2];
|
||||
__u32 serial[2];
|
||||
bool reporting_data;
|
||||
struct wacom_features features;
|
||||
struct wacom_shared *shared;
|
||||
struct input_dev *input;
|
||||
|
@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
|
||||
#define HID_GLOBAL_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_global global;
|
||||
|
@ -166,6 +166,7 @@ struct input_keymap_entry {
|
||||
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
|
||||
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
|
||||
#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_CNT (INPUT_PROP_MAX + 1)
|
||||
|
Loading…
Reference in New Issue
Block a user