You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
Merge tag 'for-linus-2022100501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Benjamin Tissoires: - handle of all Logitech Bluetooth HID++ devices in the Logitech HID++ drivers (Bastien Nocera) - fix broken atomic checks in hid-multitouch by adding memory barriers (Andri Yngvason) - better handling of devices with AMD SFH1.1 (Basavaraj Natikar) - better support of Nintendo clone controllers (Icenowy Zheng and Johnothan King) - Support for various RC controllers (Marcus Folkesson) - Add UGEEv2 support in hid-uclogic (XP-PEN Deco Pro S and Parblo A610 PRO) (José Expósito) - some conversions to use dev_groups (Greg Kroah-Hartman) - HID-BPF preparatory patches, mostly to convert blank defines as enums (Benjamin Tissoires) * tag 'for-linus-2022100501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (38 commits) HID: wacom: add three styli to wacom_intuos_get_tool_type HID: amd_sfh: Handle condition of "no sensors" for SFH1.1 HID: amd_sfh: Change dev_err to dev_dbg for additional debug info HID: nintendo: check analog user calibration for plausibility HID: nintendo: deregister home LED when it fails HID: roccat: Fix use-after-free in roccat_read() hid: topre: Add driver fixing report descriptor HID: multitouch: Add memory barriers HID: convert defines of HID class requests into a proper enum HID: export hid_report_type to uapi HID: core: store the unique system identifier in hid_device HID: Add driver for PhoenixRC Flight Controller HID: Add driver for VRC-2 Car Controller HID: sony: Fix double word in comments hid: hid-logitech-hidpp: avoid unnecessary assignments in hidpp_connect_event HID: logitech-hidpp: Detect hi-res scrolling support HID: logitech-hidpp: Remove hard-coded "Sw. Id." for HID++ 2.0 commands HID: logitech-hidpp: Fix "Sw. Id." for HID++ 2.0 commands HID: logitech-hidpp: Remove special-casing of Bluetooth devices HID: logitech-hidpp: Enable HID++ for all the Logitech Bluetooth devices ...
This commit is contained in:
12
MAINTAINERS
12
MAINTAINERS
@@ -9082,6 +9082,12 @@ L: linux-input@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/hid/hid-playstation.c
|
||||
|
||||
HID PHOENIX RC FLIGHT CONTROLLER
|
||||
M: Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-pxrc.c
|
||||
|
||||
HID SENSOR HUB DRIVERS
|
||||
M: Jiri Kosina <jikos@kernel.org>
|
||||
M: Jonathan Cameron <jic23@kernel.org>
|
||||
@@ -9094,6 +9100,12 @@ F: drivers/hid/hid-sensor-*
|
||||
F: drivers/iio/*/hid-*
|
||||
F: include/linux/hid-sensor-*
|
||||
|
||||
HID VRC-2 CAR CONTROLLER DRIVER
|
||||
M: Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/hid/hid-vrc2.c
|
||||
|
||||
HID WACOM DRIVER
|
||||
M: Ping Cheng <ping.cheng@wacom.com>
|
||||
M: Jason Gerecke <jason.gerecke@wacom.com>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -101,6 +101,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
|
||||
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
|
||||
obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o
|
||||
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
|
||||
obj-$(CONFIG_HID_PXRC) += hid-pxrc.o
|
||||
obj-$(CONFIG_HID_RAZER) += hid-razer.o
|
||||
obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o
|
||||
obj-$(CONFIG_HID_RETRODE) += hid-retrode.o
|
||||
@@ -123,6 +124,7 @@ obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
|
||||
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o hid-thrustmaster.o
|
||||
obj-$(CONFIG_HID_TIVO) += hid-tivo.o
|
||||
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
|
||||
obj-$(CONFIG_HID_TOPRE) += hid-topre.o
|
||||
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
|
||||
obj-$(CONFIG_HID_U2FZERO) += hid-u2fzero.o
|
||||
hid-uclogic-objs := hid-uclogic-core.o \
|
||||
@@ -136,6 +138,7 @@ obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
|
||||
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
|
||||
obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
|
||||
obj-$(CONFIG_HID_VIEWSONIC) += hid-viewsonic.o
|
||||
obj-$(CONFIG_HID_VRC2) += hid-vrc2.o
|
||||
|
||||
wacom-objs := wacom_wac.o wacom_sys.o
|
||||
obj-$(CONFIG_HID_WACOM) += wacom.o
|
||||
@@ -144,8 +147,10 @@ obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
|
||||
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
|
||||
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
|
||||
|
||||
obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \
|
||||
hid-uclogic-test-objs := hid-uclogic-rdesc.o \
|
||||
hid-uclogic-params.o \
|
||||
hid-uclogic-rdesc-test.o
|
||||
obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-test.o
|
||||
|
||||
obj-$(CONFIG_USB_HID) += usbhid/
|
||||
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
||||
|
||||
@@ -110,6 +110,8 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
|
||||
amd_sfh1_1_set_desc_ops(mp2_ops);
|
||||
|
||||
cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]);
|
||||
if (cl_data->num_hid_devices == 0)
|
||||
return -ENODEV;
|
||||
|
||||
INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work);
|
||||
INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer);
|
||||
@@ -286,13 +288,13 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
|
||||
|
||||
phy_base <<= 21;
|
||||
if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) {
|
||||
dev_err(dev, "can't reserve mmio registers\n");
|
||||
dev_dbg(dev, "can't reserve mmio registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024);
|
||||
if (!mp2->vsbase) {
|
||||
dev_err(dev, "failed to remap vsbase\n");
|
||||
dev_dbg(dev, "failed to remap vsbase\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -301,7 +303,7 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
|
||||
|
||||
memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
|
||||
if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) {
|
||||
dev_err(dev, "failed to get sensors\n");
|
||||
dev_dbg(dev, "failed to get sensors\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver);
|
||||
|
||||
@@ -55,7 +55,7 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
|
||||
*/
|
||||
|
||||
struct hid_report *hid_register_report(struct hid_device *device,
|
||||
unsigned int type, unsigned int id,
|
||||
enum hid_report_type type, unsigned int id,
|
||||
unsigned int application)
|
||||
{
|
||||
struct hid_report_enum *report_enum = device->report_enum + type;
|
||||
@@ -967,7 +967,7 @@ static const char * const hid_report_names[] = {
|
||||
* parsing.
|
||||
*/
|
||||
struct hid_report *hid_validate_values(struct hid_device *hid,
|
||||
unsigned int type, unsigned int id,
|
||||
enum hid_report_type type, unsigned int id,
|
||||
unsigned int field_index,
|
||||
unsigned int report_counts)
|
||||
{
|
||||
@@ -1921,7 +1921,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
|
||||
* DO NOT USE in hid drivers directly, but through hid_hw_request instead.
|
||||
*/
|
||||
int __hid_request(struct hid_device *hid, struct hid_report *report,
|
||||
int reqtype)
|
||||
enum hid_class_request reqtype)
|
||||
{
|
||||
char *buf;
|
||||
int ret;
|
||||
@@ -1954,8 +1954,8 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hid_request);
|
||||
|
||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
||||
int interrupt)
|
||||
int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt)
|
||||
{
|
||||
struct hid_report_enum *report_enum = hid->report_enum + type;
|
||||
struct hid_report *report;
|
||||
@@ -2019,7 +2019,8 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);
|
||||
*
|
||||
* This is data entry for lower layers.
|
||||
*/
|
||||
int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
|
||||
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
|
||||
int interrupt)
|
||||
{
|
||||
struct hid_report_enum *report_enum;
|
||||
struct hid_driver *hdrv;
|
||||
@@ -2088,6 +2089,7 @@ const struct hid_device_id *hid_match_id(const struct hid_device *hdev,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_match_id);
|
||||
|
||||
static const struct hid_device_id hid_hiddev_list[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
|
||||
@@ -2352,7 +2354,7 @@ EXPORT_SYMBOL_GPL(hid_hw_close);
|
||||
* @reqtype: hid request type
|
||||
*/
|
||||
void hid_hw_request(struct hid_device *hdev,
|
||||
struct hid_report *report, int reqtype)
|
||||
struct hid_report *report, enum hid_class_request reqtype)
|
||||
{
|
||||
if (hdev->ll_driver->request)
|
||||
return hdev->ll_driver->request(hdev, report, reqtype);
|
||||
@@ -2377,7 +2379,7 @@ EXPORT_SYMBOL_GPL(hid_hw_request);
|
||||
*/
|
||||
int hid_hw_raw_request(struct hid_device *hdev,
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
size_t len, unsigned char rtype, int reqtype)
|
||||
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
|
||||
{
|
||||
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
|
||||
return -EINVAL;
|
||||
@@ -2739,10 +2741,12 @@ int hid_add_device(struct hid_device *hdev)
|
||||
hid_warn(hdev, "bad device descriptor (%d)\n", ret);
|
||||
}
|
||||
|
||||
hdev->id = atomic_inc_return(&id);
|
||||
|
||||
/* XXX hack, any other cleaner solution after the driver core
|
||||
* is converted to allow more than 20 bytes as the device name? */
|
||||
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
|
||||
hdev->vendor, hdev->product, atomic_inc_return(&id));
|
||||
hdev->vendor, hdev->product, hdev->id);
|
||||
|
||||
hid_debug_register(hdev, dev_name(&hdev->dev));
|
||||
ret = device_add(&hdev->dev);
|
||||
|
||||
@@ -608,9 +608,11 @@ static struct hid_driver hammer_driver = {
|
||||
.probe = hammer_probe,
|
||||
.remove = hammer_remove,
|
||||
.feature_mapping = vivaldi_feature_mapping,
|
||||
.input_configured = vivaldi_input_configured,
|
||||
.input_mapping = hammer_input_mapping,
|
||||
.event = hammer_event,
|
||||
.driver = {
|
||||
.dev_groups = vivaldi_attribute_groups,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init hammer_init(void)
|
||||
|
||||
@@ -1231,6 +1231,9 @@
|
||||
#define USB_DEVICE_ID_TIVO_SLIDE 0x1201
|
||||
#define USB_DEVICE_ID_TIVO_SLIDE_PRO 0x1203
|
||||
|
||||
#define USB_VENDOR_ID_TOPRE 0x0853
|
||||
#define USB_DEVICE_ID_TOPRE_REALFORCE_R2_108 0x0148
|
||||
|
||||
#define USB_VENDOR_ID_TOPSEED 0x0766
|
||||
#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
|
||||
|
||||
@@ -1279,10 +1282,12 @@
|
||||
#define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d
|
||||
|
||||
#define USB_VENDOR_ID_UGEE 0x28bd
|
||||
#define USB_DEVICE_ID_UGEE_PARBLO_A610_PRO 0x1903
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S 0x0909
|
||||
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
|
||||
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
|
||||
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
|
||||
@@ -1386,6 +1391,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_MULTIPLE_1781 0x1781
|
||||
#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a9d
|
||||
#define USB_DEVICE_ID_PHOENIXRC 0x0898
|
||||
|
||||
#define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b
|
||||
#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002
|
||||
|
||||
@@ -41,6 +41,9 @@ module_param(disable_tap_to_click, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_tap_to_click,
|
||||
"Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently).");
|
||||
|
||||
/* Define a non-zero software ID to identify our own requests */
|
||||
#define LINUX_KERNEL_SW_ID 0x01
|
||||
|
||||
#define REPORT_ID_HIDPP_SHORT 0x10
|
||||
#define REPORT_ID_HIDPP_LONG 0x11
|
||||
#define REPORT_ID_HIDPP_VERY_LONG 0x12
|
||||
@@ -71,21 +74,18 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
||||
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
||||
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
||||
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
||||
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
|
||||
#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
|
||||
#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
|
||||
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(29)
|
||||
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(30)
|
||||
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(31)
|
||||
#define HIDPP_QUIRK_HIDPP_WHEELS BIT(26)
|
||||
#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27)
|
||||
#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28)
|
||||
|
||||
/* These are just aliases for now */
|
||||
#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
|
||||
#define HIDPP_QUIRK_KBD_ZOOM_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
|
||||
|
||||
/* Convenience constant to check for any high-res support. */
|
||||
#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
|
||||
HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
|
||||
HIDPP_QUIRK_HI_RES_SCROLL_X2121)
|
||||
#define HIDPP_CAPABILITY_HI_RES_SCROLL (HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL | \
|
||||
HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL | \
|
||||
HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL)
|
||||
|
||||
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
||||
|
||||
@@ -96,6 +96,9 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
||||
#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
|
||||
#define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5)
|
||||
#define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6)
|
||||
#define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL BIT(7)
|
||||
#define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL BIT(8)
|
||||
#define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL BIT(9)
|
||||
|
||||
#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
|
||||
|
||||
@@ -343,7 +346,7 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
|
||||
else
|
||||
message->report_id = REPORT_ID_HIDPP_LONG;
|
||||
message->fap.feature_index = feat_index;
|
||||
message->fap.funcindex_clientid = funcindex_clientid;
|
||||
message->fap.funcindex_clientid = funcindex_clientid | LINUX_KERNEL_SW_ID;
|
||||
memcpy(&message->fap.params, params, param_count);
|
||||
|
||||
ret = hidpp_send_message_sync(hidpp, message, response);
|
||||
@@ -856,8 +859,8 @@ static int hidpp_unifying_init(struct hidpp_device *hidpp)
|
||||
#define HIDPP_PAGE_ROOT 0x0000
|
||||
#define HIDPP_PAGE_ROOT_IDX 0x00
|
||||
|
||||
#define CMD_ROOT_GET_FEATURE 0x01
|
||||
#define CMD_ROOT_GET_PROTOCOL_VERSION 0x11
|
||||
#define CMD_ROOT_GET_FEATURE 0x00
|
||||
#define CMD_ROOT_GET_PROTOCOL_VERSION 0x10
|
||||
|
||||
static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature,
|
||||
u8 *feature_index, u8 *feature_type)
|
||||
@@ -934,9 +937,9 @@ print_version:
|
||||
|
||||
#define HIDPP_PAGE_GET_DEVICE_NAME_TYPE 0x0005
|
||||
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x01
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x11
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x21
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x00
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x10
|
||||
#define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x20
|
||||
|
||||
static int hidpp_devicenametype_get_count(struct hidpp_device *hidpp,
|
||||
u8 feature_index, u8 *nameLength)
|
||||
@@ -1966,8 +1969,8 @@ static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp,
|
||||
|
||||
#define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100
|
||||
|
||||
#define CMD_TOUCHPAD_GET_RAW_INFO 0x01
|
||||
#define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x21
|
||||
#define CMD_TOUCHPAD_GET_RAW_INFO 0x00
|
||||
#define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x20
|
||||
|
||||
#define EVENT_TOUCHPAD_RAW_XY 0x00
|
||||
|
||||
@@ -3415,14 +3418,14 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
||||
int ret;
|
||||
u8 multiplier = 1;
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
|
||||
ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
|
||||
if (ret == 0)
|
||||
ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
|
||||
} else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
|
||||
} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) {
|
||||
ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
|
||||
&multiplier);
|
||||
} else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ {
|
||||
} else /* if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL) */ {
|
||||
ret = hidpp10_enable_scrolling_acceleration(hidpp);
|
||||
multiplier = 8;
|
||||
}
|
||||
@@ -3437,6 +3440,49 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp)
|
||||
{
|
||||
int ret;
|
||||
unsigned long capabilities;
|
||||
|
||||
capabilities = hidpp->capabilities;
|
||||
|
||||
if (hidpp->protocol_major >= 2) {
|
||||
u8 feature_index;
|
||||
u8 feature_type;
|
||||
|
||||
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
|
||||
&feature_index, &feature_type);
|
||||
if (!ret) {
|
||||
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL;
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scroll wheel\n");
|
||||
return 0;
|
||||
}
|
||||
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
|
||||
&feature_index, &feature_type);
|
||||
if (!ret) {
|
||||
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL;
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n");
|
||||
}
|
||||
} else {
|
||||
struct hidpp_report response;
|
||||
|
||||
ret = hidpp_send_rap_command_sync(hidpp,
|
||||
REPORT_ID_HIDPP_SHORT,
|
||||
HIDPP_GET_REGISTER,
|
||||
HIDPP_ENABLE_FAST_SCROLL,
|
||||
NULL, 0, &response);
|
||||
if (!ret) {
|
||||
hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL;
|
||||
hid_dbg(hidpp->hid_dev, "Detected HID++ 1.0 fast scroll\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (hidpp->capabilities == capabilities)
|
||||
hid_dbg(hidpp->hid_dev, "Did not detect HID++ hi-res scrolling hardware support\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Generic HID++ devices */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -3691,8 +3737,9 @@ static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
|
||||
* cases we must return early (falling back to default behaviour) to
|
||||
* avoid a crash in hidpp_scroll_counter_handle_scroll.
|
||||
*/
|
||||
if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
|
||||
|| hidpp->input == NULL || counter->wheel_multiplier == 0)
|
||||
if (!(hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL)
|
||||
|| value == 0 || hidpp->input == NULL
|
||||
|| counter->wheel_multiplier == 0)
|
||||
return 0;
|
||||
|
||||
hidpp_scroll_counter_handle_scroll(hidpp->input, counter, value);
|
||||
@@ -3924,6 +3971,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
}
|
||||
|
||||
hidpp_initialize_battery(hidpp);
|
||||
hidpp_initialize_hires_scroll(hidpp);
|
||||
|
||||
/* forward current battery state */
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
|
||||
@@ -3943,7 +3991,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
if (hidpp->battery.ps)
|
||||
power_supply_changed(hidpp->battery.ps);
|
||||
|
||||
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
|
||||
if (hidpp->capabilities & HIDPP_CAPABILITY_HI_RES_SCROLL)
|
||||
hi_res_scroll_enable(hidpp);
|
||||
|
||||
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
||||
@@ -3959,8 +4007,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||
hidpp_populate_input(hidpp, input);
|
||||
|
||||
ret = input_register_device(input);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
input_free_device(input);
|
||||
return;
|
||||
}
|
||||
|
||||
hidpp->delayed_input = input;
|
||||
}
|
||||
@@ -4219,6 +4269,21 @@ static void hidpp_remove(struct hid_device *hdev)
|
||||
mutex_destroy(&hidpp->send_mutex);
|
||||
}
|
||||
|
||||
static const struct hid_device_id unhandled_hidpp_devices[] = {
|
||||
/* Logitech Harmony Adapter for PS3, handled in hid-sony */
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
|
||||
/* Handled in hid-generic */
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD) },
|
||||
{}
|
||||
};
|
||||
|
||||
static bool hidpp_match(struct hid_device *hdev,
|
||||
bool ignore_special_driver)
|
||||
{
|
||||
/* Refuse to handle devices handled by other HID drivers */
|
||||
return !hid_match_id(hdev, unhandled_hidpp_devices);
|
||||
}
|
||||
|
||||
#define LDJ_DEVICE(product) \
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
|
||||
USB_VENDOR_ID_LOGITECH, (product))
|
||||
@@ -4239,42 +4304,9 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||
USB_DEVICE_ID_LOGITECH_T651),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
||||
{ /* Mouse Logitech Anywhere MX */
|
||||
LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
{ /* Mouse Logitech Cube */
|
||||
LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||
{ /* Mouse Logitech M335 */
|
||||
LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech M515 */
|
||||
LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||
{ /* Mouse logitech M560 */
|
||||
LDJ_DEVICE(0x402d),
|
||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
|
||||
| HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||
{ /* Mouse Logitech M705 (firmware RQM17) */
|
||||
LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
{ /* Mouse Logitech M705 (firmware RQM67) */
|
||||
LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech M720 */
|
||||
LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech MX Anywhere 2 */
|
||||
LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech MX Anywhere 2S */
|
||||
LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech MX Master */
|
||||
LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech MX Master 2S */
|
||||
LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech MX Master 3 */
|
||||
LDJ_DEVICE(0x4082), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* Mouse Logitech Performance MX */
|
||||
LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
||||
{ /* Keyboard logitech K400 */
|
||||
LDJ_DEVICE(0x4024),
|
||||
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
||||
@@ -4335,18 +4367,9 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||
{ /* MX5500 keyboard over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
|
||||
.driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
|
||||
{ /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
|
||||
{ /* MX Master mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012),
|
||||
.driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* MX Ergo trackball over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e),
|
||||
.driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
{ /* MX Master 3 mouse over Bluetooth */
|
||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023),
|
||||
.driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||
|
||||
{ /* And try to enable HID++ for all the Logitech Bluetooth devices */
|
||||
HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_ANY, USB_VENDOR_ID_LOGITECH, HID_ANY_ID) },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -4360,6 +4383,7 @@ static const struct hid_usage_id hidpp_usages[] = {
|
||||
static struct hid_driver hidpp_driver = {
|
||||
.name = "logitech-hidpp-device",
|
||||
.id_table = hidpp_devices,
|
||||
.match = hidpp_match,
|
||||
.report_fixup = hidpp_report_fixup,
|
||||
.probe = hidpp_probe,
|
||||
.remove = hidpp_remove,
|
||||
|
||||
@@ -1186,7 +1186,7 @@ static void mt_touch_report(struct hid_device *hid,
|
||||
int contact_count = -1;
|
||||
|
||||
/* sticky fingers release in progress, abort */
|
||||
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||
if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||
return;
|
||||
|
||||
scantime = *app->scantime;
|
||||
@@ -1267,7 +1267,7 @@ static void mt_touch_report(struct hid_device *hid,
|
||||
del_timer(&td->release_timer);
|
||||
}
|
||||
|
||||
clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
|
||||
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
|
||||
}
|
||||
|
||||
static int mt_touch_input_configured(struct hid_device *hdev,
|
||||
@@ -1699,11 +1699,11 @@ static void mt_expired_timeout(struct timer_list *t)
|
||||
* An input report came in just before we release the sticky fingers,
|
||||
* it will take care of the sticky fingers.
|
||||
*/
|
||||
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||
if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||
return;
|
||||
if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
|
||||
mt_release_contacts(hdev);
|
||||
clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
|
||||
clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
|
||||
}
|
||||
|
||||
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
@@ -760,12 +760,31 @@ static int joycon_read_stick_calibration(struct joycon_ctlr *ctlr, u16 cal_addr,
|
||||
cal_y->max = cal_y->center + y_max_above;
|
||||
cal_y->min = cal_y->center - y_min_below;
|
||||
|
||||
return 0;
|
||||
/* check if calibration values are plausible */
|
||||
if (cal_x->min >= cal_x->center || cal_x->center >= cal_x->max ||
|
||||
cal_y->min >= cal_y->center || cal_y->center >= cal_y->max)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const u16 DFLT_STICK_CAL_CEN = 2000;
|
||||
static const u16 DFLT_STICK_CAL_MAX = 3500;
|
||||
static const u16 DFLT_STICK_CAL_MIN = 500;
|
||||
static void joycon_use_default_calibration(struct hid_device *hdev,
|
||||
struct joycon_stick_cal *cal_x,
|
||||
struct joycon_stick_cal *cal_y,
|
||||
const char *stick, int ret)
|
||||
{
|
||||
hid_warn(hdev,
|
||||
"Failed to read %s stick cal, using defaults; e=%d\n",
|
||||
stick, ret);
|
||||
|
||||
cal_x->center = cal_y->center = DFLT_STICK_CAL_CEN;
|
||||
cal_x->max = cal_y->max = DFLT_STICK_CAL_MAX;
|
||||
cal_x->min = cal_y->min = DFLT_STICK_CAL_MIN;
|
||||
}
|
||||
|
||||
static int joycon_request_calibration(struct joycon_ctlr *ctlr)
|
||||
{
|
||||
u16 left_stick_addr = JC_CAL_FCT_DATA_LEFT_ADDR;
|
||||
@@ -793,38 +812,24 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr)
|
||||
&ctlr->left_stick_cal_x,
|
||||
&ctlr->left_stick_cal_y,
|
||||
true);
|
||||
if (ret) {
|
||||
hid_warn(ctlr->hdev,
|
||||
"Failed to read left stick cal, using dflts; e=%d\n",
|
||||
ret);
|
||||
|
||||
ctlr->left_stick_cal_x.center = DFLT_STICK_CAL_CEN;
|
||||
ctlr->left_stick_cal_x.max = DFLT_STICK_CAL_MAX;
|
||||
ctlr->left_stick_cal_x.min = DFLT_STICK_CAL_MIN;
|
||||
|
||||
ctlr->left_stick_cal_y.center = DFLT_STICK_CAL_CEN;
|
||||
ctlr->left_stick_cal_y.max = DFLT_STICK_CAL_MAX;
|
||||
ctlr->left_stick_cal_y.min = DFLT_STICK_CAL_MIN;
|
||||
}
|
||||
if (ret)
|
||||
joycon_use_default_calibration(ctlr->hdev,
|
||||
&ctlr->left_stick_cal_x,
|
||||
&ctlr->left_stick_cal_y,
|
||||
"left", ret);
|
||||
|
||||
/* read the right stick calibration data */
|
||||
ret = joycon_read_stick_calibration(ctlr, right_stick_addr,
|
||||
&ctlr->right_stick_cal_x,
|
||||
&ctlr->right_stick_cal_y,
|
||||
false);
|
||||
if (ret) {
|
||||
hid_warn(ctlr->hdev,
|
||||
"Failed to read right stick cal, using dflts; e=%d\n",
|
||||
ret);
|
||||
|
||||
ctlr->right_stick_cal_x.center = DFLT_STICK_CAL_CEN;
|
||||
ctlr->right_stick_cal_x.max = DFLT_STICK_CAL_MAX;
|
||||
ctlr->right_stick_cal_x.min = DFLT_STICK_CAL_MIN;
|
||||
|
||||
ctlr->right_stick_cal_y.center = DFLT_STICK_CAL_CEN;
|
||||
ctlr->right_stick_cal_y.max = DFLT_STICK_CAL_MAX;
|
||||
ctlr->right_stick_cal_y.min = DFLT_STICK_CAL_MIN;
|
||||
}
|
||||
if (ret)
|
||||
joycon_use_default_calibration(ctlr->hdev,
|
||||
&ctlr->right_stick_cal_x,
|
||||
&ctlr->right_stick_cal_y,
|
||||
"right", ret);
|
||||
|
||||
hid_dbg(ctlr->hdev, "calibration:\n"
|
||||
"l_x_c=%d l_x_max=%d l_x_min=%d\n"
|
||||
@@ -1904,9 +1909,8 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
|
||||
/* Set the home LED to 0 as default state */
|
||||
ret = joycon_home_led_brightness_set(led, 0);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to set home LED dflt; ret=%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
hid_warn(hdev, "Failed to set home LED default, unregistering home LED");
|
||||
devm_led_classdev_unregister(&hdev->dev, led);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -692,15 +692,12 @@ static ssize_t hardware_version_show(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR_RO(hardware_version);
|
||||
|
||||
static struct attribute *ps_device_attributes[] = {
|
||||
static struct attribute *ps_device_attrs[] = {
|
||||
&dev_attr_firmware_version.attr,
|
||||
&dev_attr_hardware_version.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ps_device_attribute_group = {
|
||||
.attrs = ps_device_attributes,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ps_device);
|
||||
|
||||
static int dualsense_get_calibration_data(struct dualsense *ds)
|
||||
{
|
||||
@@ -1448,12 +1445,6 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group);
|
||||
if (ret) {
|
||||
hid_err(hdev, "Failed to register sysfs nodes.\n");
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err_close:
|
||||
@@ -1487,6 +1478,9 @@ static struct hid_driver ps_driver = {
|
||||
.probe = ps_probe,
|
||||
.remove = ps_remove,
|
||||
.raw_event = ps_raw_event,
|
||||
.driver = {
|
||||
.dev_groups = ps_device_groups,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ps_init(void)
|
||||
|
||||
112
drivers/hid/hid-pxrc.c
Normal file
112
drivers/hid/hid-pxrc.c
Normal file
@@ -0,0 +1,112 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* HID driver for PhoenixRC 8-axis flight controller
|
||||
*
|
||||
* Copyright (C) 2022 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
struct pxrc_priv {
|
||||
u8 slider;
|
||||
u8 dial;
|
||||
bool alternate;
|
||||
};
|
||||
|
||||
static __u8 pxrc_rdesc_fixed[] = {
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x04, // Usage (Joystick)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x09, 0x01, // Usage (Pointer)
|
||||
0xA1, 0x00, // Collection (Physical)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x36, // Usage (Slider)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x32, // Usage (Z)
|
||||
0x09, 0x33, // Usage (Rx)
|
||||
0x09, 0x34, // Usage (Ry)
|
||||
0x09, 0x35, // Usage (Rz)
|
||||
0x09, 0x37, // Usage (Dial)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x46, 0xFF, 0x00, // Physical Maximum (255)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x08, // Report Count (8)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
};
|
||||
|
||||
static __u8 *pxrc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
hid_info(hdev, "fixing up PXRC report descriptor\n");
|
||||
*rsize = sizeof(pxrc_rdesc_fixed);
|
||||
return pxrc_rdesc_fixed;
|
||||
}
|
||||
|
||||
static int pxrc_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||
u8 *data, int size)
|
||||
{
|
||||
struct pxrc_priv *priv = hid_get_drvdata(hdev);
|
||||
|
||||
if (priv->alternate)
|
||||
priv->slider = data[7];
|
||||
else
|
||||
priv->dial = data[7];
|
||||
|
||||
data[1] = priv->slider;
|
||||
data[7] = priv->dial;
|
||||
|
||||
priv->alternate = !priv->alternate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxrc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct pxrc_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
hid_set_drvdata(hdev, priv);
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret) {
|
||||
hid_err(hdev, "parse failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||
if (ret) {
|
||||
hid_err(hdev, "hw start failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_device_id pxrc_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_PHOENIXRC) },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, pxrc_devices);
|
||||
|
||||
static struct hid_driver pxrc_driver = {
|
||||
.name = "hid-pxrc",
|
||||
.id_table = pxrc_devices,
|
||||
.report_fixup = pxrc_report_fixup,
|
||||
.probe = pxrc_probe,
|
||||
.raw_event = pxrc_raw_event,
|
||||
};
|
||||
module_hid_driver(pxrc_driver);
|
||||
|
||||
MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
|
||||
MODULE_DESCRIPTION("HID driver for PXRC 8-axis flight controller");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -237,8 +237,7 @@ static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr,
|
||||
|
||||
read_input_count = data->readReport[1];
|
||||
memcpy(buf + bytes_read, &data->readReport[2],
|
||||
read_input_count < bytes_needed ?
|
||||
read_input_count : bytes_needed);
|
||||
min(read_input_count, bytes_needed));
|
||||
|
||||
bytes_read += read_input_count;
|
||||
bytes_needed -= read_input_count;
|
||||
@@ -347,8 +346,7 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(hdata->readReport, data, size < hdata->input_report_size ?
|
||||
size : hdata->input_report_size);
|
||||
memcpy(hdata->readReport, data, min((u32)size, hdata->input_report_size));
|
||||
set_bit(RMI_READ_DATA_PENDING, &hdata->flags);
|
||||
wake_up(&hdata->wait);
|
||||
|
||||
|
||||
@@ -257,6 +257,8 @@ int roccat_report_event(int minor, u8 const *data)
|
||||
if (!new_value)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&device->cbuf_lock);
|
||||
|
||||
report = &device->cbuf[device->cbuf_end];
|
||||
|
||||
/* passing NULL is safe */
|
||||
@@ -276,6 +278,8 @@ int roccat_report_event(int minor, u8 const *data)
|
||||
reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
|
||||
}
|
||||
|
||||
mutex_unlock(&device->cbuf_lock);
|
||||
|
||||
wake_up_interruptible(&device->wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ static const unsigned int buzz_keymap[] = {
|
||||
};
|
||||
|
||||
/* The Navigation controller is a partial DS3 and uses the same HID report
|
||||
* and hence the same keymap indices, however not not all axes/buttons
|
||||
* and hence the same keymap indices, however not all axes/buttons
|
||||
* are physically present. We use the same axis and button mapping as
|
||||
* the DS3, which uses the Linux gamepad spec.
|
||||
*/
|
||||
|
||||
@@ -256,7 +256,7 @@ static int steam_get_serial(struct steam_device *steam)
|
||||
if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01)
|
||||
return -EIO;
|
||||
reply[3 + STEAM_SERIAL_LEN] = 0;
|
||||
strlcpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
|
||||
strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ static int steam_register(struct steam_device *steam)
|
||||
*/
|
||||
mutex_lock(&steam->mutex);
|
||||
if (steam_get_serial(steam) < 0)
|
||||
strlcpy(steam->serial_no, "XXXXXXXXXX",
|
||||
strscpy(steam->serial_no, "XXXXXXXXXX",
|
||||
sizeof(steam->serial_no));
|
||||
mutex_unlock(&steam->mutex);
|
||||
|
||||
@@ -699,9 +699,9 @@ static struct hid_device *steam_create_client_hid(struct hid_device *hdev)
|
||||
client_hdev->version = hdev->version;
|
||||
client_hdev->type = hdev->type;
|
||||
client_hdev->country = hdev->country;
|
||||
strlcpy(client_hdev->name, hdev->name,
|
||||
strscpy(client_hdev->name, hdev->name,
|
||||
sizeof(client_hdev->name));
|
||||
strlcpy(client_hdev->phys, hdev->phys,
|
||||
strscpy(client_hdev->phys, hdev->phys,
|
||||
sizeof(client_hdev->phys));
|
||||
/*
|
||||
* Since we use the same device info than the real interface to
|
||||
|
||||
49
drivers/hid/hid-topre.c
Normal file
49
drivers/hid/hid-topre.c
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* HID driver for Topre REALFORCE Keyboards
|
||||
*
|
||||
* Copyright (c) 2022 Harry Stern <harry@harrystern.net>
|
||||
*
|
||||
* Based on the hid-macally driver
|
||||
*/
|
||||
|
||||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "hid-ids.h"
|
||||
|
||||
MODULE_AUTHOR("Harry Stern <harry@harrystern.net>");
|
||||
MODULE_DESCRIPTION("REALFORCE R2 Keyboard driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Fix the REALFORCE R2's non-boot interface's report descriptor to match the
|
||||
* events it's actually sending. It claims to send array events but is instead
|
||||
* sending variable events.
|
||||
*/
|
||||
static __u8 *topre_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 119 && rdesc[69] == 0x29 && rdesc[70] == 0xe7 &&
|
||||
rdesc[71] == 0x81 && rdesc[72] == 0x00) {
|
||||
hid_info(hdev,
|
||||
"fixing up Topre REALFORCE keyboard report descriptor\n");
|
||||
rdesc[72] = 0x02;
|
||||
}
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
static const struct hid_device_id topre_id_table[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPRE,
|
||||
USB_DEVICE_ID_TOPRE_REALFORCE_R2_108) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(hid, topre_id_table);
|
||||
|
||||
static struct hid_driver topre_driver = {
|
||||
.name = "topre",
|
||||
.id_table = topre_id_table,
|
||||
.report_fixup = topre_report_fixup,
|
||||
};
|
||||
|
||||
module_hid_driver(topre_driver);
|
||||
@@ -153,6 +153,7 @@ static int uclogic_input_configured(struct hid_device *hdev,
|
||||
suffix = "Pad";
|
||||
break;
|
||||
case HID_DG_PEN:
|
||||
case HID_DG_DIGITIZER:
|
||||
suffix = "Pen";
|
||||
break;
|
||||
case HID_CP_CONSUMER_CONTROL:
|
||||
@@ -509,6 +510,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
||||
USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
|
||||
USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_PARBLO_A610_PRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_TABLET_G5) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
@@ -523,6 +526,8 @@ static const struct hid_device_id uclogic_devices[] = {
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
|
||||
{ }
|
||||
|
||||
192
drivers/hid/hid-uclogic-params-test.c
Normal file
192
drivers/hid/hid-uclogic-params-test.c
Normal file
@@ -0,0 +1,192 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/*
|
||||
* HID driver for UC-Logic devices not fully compliant with HID standard
|
||||
*
|
||||
* Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com>
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include "./hid-uclogic-params.h"
|
||||
#include "./hid-uclogic-rdesc.h"
|
||||
|
||||
#define MAX_STR_DESC_SIZE 14
|
||||
|
||||
struct uclogic_parse_ugee_v2_desc_case {
|
||||
const char *name;
|
||||
int res;
|
||||
const __u8 str_desc[MAX_STR_DESC_SIZE];
|
||||
size_t str_desc_size;
|
||||
const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
|
||||
enum uclogic_params_frame_type frame_type;
|
||||
};
|
||||
|
||||
static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = {
|
||||
{
|
||||
.name = "invalid_str_desc",
|
||||
.res = -EINVAL,
|
||||
.str_desc = {},
|
||||
.str_desc_size = 0,
|
||||
.desc_params = {},
|
||||
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
|
||||
},
|
||||
{
|
||||
.name = "resolution_with_value_0",
|
||||
.res = 0,
|
||||
.str_desc = {
|
||||
0x0E, 0x03,
|
||||
0x70, 0xB2,
|
||||
0x10, 0x77,
|
||||
0x08,
|
||||
0x00,
|
||||
0xFF, 0x1F,
|
||||
0x00, 0x00,
|
||||
},
|
||||
.str_desc_size = 12,
|
||||
.desc_params = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
|
||||
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
|
||||
},
|
||||
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
|
||||
},
|
||||
/* XP-PEN Deco L str_desc: Frame with 8 buttons */
|
||||
{
|
||||
.name = "frame_type_buttons",
|
||||
.res = 0,
|
||||
.str_desc = {
|
||||
0x0E, 0x03,
|
||||
0x70, 0xB2,
|
||||
0x10, 0x77,
|
||||
0x08,
|
||||
0x00,
|
||||
0xFF, 0x1F,
|
||||
0xD8, 0x13,
|
||||
},
|
||||
.str_desc_size = 12,
|
||||
.desc_params = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB270,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2320,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7710,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1770,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
|
||||
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
|
||||
},
|
||||
.frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
|
||||
},
|
||||
/* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */
|
||||
{
|
||||
.name = "frame_type_dial",
|
||||
.res = 0,
|
||||
.str_desc = {
|
||||
0x0E, 0x03,
|
||||
0x96, 0xC7,
|
||||
0xF9, 0x7C,
|
||||
0x09,
|
||||
0x01,
|
||||
0xFF, 0x1F,
|
||||
0xD8, 0x13,
|
||||
},
|
||||
.str_desc_size = 12,
|
||||
.desc_params = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xC796,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2749,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x7CF9,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x1899,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
|
||||
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09,
|
||||
},
|
||||
.frame_type = UCLOGIC_PARAMS_FRAME_DIAL,
|
||||
},
|
||||
/* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */
|
||||
{
|
||||
.name = "frame_type_mouse",
|
||||
.res = 0,
|
||||
.str_desc = {
|
||||
0x0E, 0x03,
|
||||
0xC8, 0xB3,
|
||||
0x34, 0x65,
|
||||
0x08,
|
||||
0x02,
|
||||
0xFF, 0x1F,
|
||||
0xD8, 0x13,
|
||||
},
|
||||
.str_desc_size = 12,
|
||||
.desc_params = {
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC,
|
||||
[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
|
||||
[UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
|
||||
},
|
||||
.frame_type = UCLOGIC_PARAMS_FRAME_MOUSE,
|
||||
},
|
||||
};
|
||||
|
||||
static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_desc_case *t,
|
||||
char *desc)
|
||||
{
|
||||
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases,
|
||||
uclogic_parse_ugee_v2_desc_case_desc);
|
||||
|
||||
static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
|
||||
{
|
||||
int res;
|
||||
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
|
||||
enum uclogic_params_frame_type frame_type;
|
||||
const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value;
|
||||
|
||||
res = uclogic_params_parse_ugee_v2_desc(params->str_desc,
|
||||
params->str_desc_size,
|
||||
desc_params,
|
||||
ARRAY_SIZE(desc_params),
|
||||
&frame_type);
|
||||
KUNIT_ASSERT_EQ(test, res, params->res);
|
||||
|
||||
if (res)
|
||||
return;
|
||||
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM],
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM]);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM],
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM]);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM],
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM]);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM],
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM]);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM],
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM]);
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM],
|
||||
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]);
|
||||
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
|
||||
}
|
||||
|
||||
static struct kunit_case hid_uclogic_params_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(uclogic_parse_ugee_v2_desc_test,
|
||||
uclogic_parse_ugee_v2_desc_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite hid_uclogic_params_test_suite = {
|
||||
.name = "hid_uclogic_params_test",
|
||||
.test_cases = hid_uclogic_params_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(hid_uclogic_params_test_suite);
|
||||
|
||||
MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
|
||||
@@ -1056,6 +1056,161 @@ cleanup:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_parse_ugee_v2_desc - parse the string descriptor containing
|
||||
* pen and frame parameters returned by UGEE v2 devices.
|
||||
*
|
||||
* @str_desc: String descriptor, cannot be NULL.
|
||||
* @str_desc_size: Size of the string descriptor.
|
||||
* @desc_params: Output description params list.
|
||||
* @desc_params_size: Size of the output description params list.
|
||||
* @frame_type: Output frame type.
|
||||
*
|
||||
* Returns:
|
||||
* Zero, if successful. A negative errno code on error.
|
||||
*/
|
||||
static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
|
||||
size_t str_desc_size,
|
||||
s32 *desc_params,
|
||||
size_t desc_params_size,
|
||||
enum uclogic_params_frame_type *frame_type)
|
||||
{
|
||||
s32 pen_x_lm, pen_y_lm;
|
||||
s32 pen_x_pm, pen_y_pm;
|
||||
s32 pen_pressure_lm;
|
||||
s32 frame_num_buttons;
|
||||
s32 resolution;
|
||||
|
||||
/* Minimum descriptor length required, maximum seen so far is 14 */
|
||||
const int min_str_desc_size = 12;
|
||||
|
||||
if (!str_desc || str_desc_size < min_str_desc_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
pen_x_lm = get_unaligned_le16(str_desc + 2);
|
||||
pen_y_lm = get_unaligned_le16(str_desc + 4);
|
||||
frame_num_buttons = str_desc[6];
|
||||
*frame_type = str_desc[7];
|
||||
pen_pressure_lm = get_unaligned_le16(str_desc + 8);
|
||||
|
||||
resolution = get_unaligned_le16(str_desc + 10);
|
||||
if (resolution == 0) {
|
||||
pen_x_pm = 0;
|
||||
pen_y_pm = 0;
|
||||
} else {
|
||||
pen_x_pm = pen_x_lm * 1000 / resolution;
|
||||
pen_y_pm = pen_y_lm * 1000 / resolution;
|
||||
}
|
||||
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = pen_x_lm;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = pen_x_pm;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = pen_y_lm;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = pen_y_pm;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = pen_pressure_lm;
|
||||
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = frame_num_buttons;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_ugee_v2_init_frame_buttons() - initialize a UGEE v2 frame with
|
||||
* buttons.
|
||||
* @p: Parameters to fill in, cannot be NULL.
|
||||
* @desc_params: Device description params list.
|
||||
* @desc_params_size: Size of the description params list.
|
||||
*
|
||||
* Returns:
|
||||
* Zero, if successful. A negative errno code on error.
|
||||
*/
|
||||
static int uclogic_params_ugee_v2_init_frame_buttons(struct uclogic_params *p,
|
||||
const s32 *desc_params,
|
||||
size_t desc_params_size)
|
||||
{
|
||||
__u8 *rdesc_frame = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
rdesc_frame = uclogic_rdesc_template_apply(
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_arr,
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_size,
|
||||
desc_params, UCLOGIC_RDESC_PH_ID_NUM);
|
||||
if (!rdesc_frame)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
|
||||
rdesc_frame,
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_size,
|
||||
UCLOGIC_RDESC_V1_FRAME_ID);
|
||||
kfree(rdesc_frame);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_ugee_v2_init_frame_dial() - initialize a UGEE v2 frame with a
|
||||
* bitmap dial.
|
||||
* @p: Parameters to fill in, cannot be NULL.
|
||||
* @desc_params: Device description params list.
|
||||
* @desc_params_size: Size of the description params list.
|
||||
*
|
||||
* Returns:
|
||||
* Zero, if successful. A negative errno code on error.
|
||||
*/
|
||||
static int uclogic_params_ugee_v2_init_frame_dial(struct uclogic_params *p,
|
||||
const s32 *desc_params,
|
||||
size_t desc_params_size)
|
||||
{
|
||||
__u8 *rdesc_frame = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!p || desc_params_size != UCLOGIC_RDESC_PH_ID_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
rdesc_frame = uclogic_rdesc_template_apply(
|
||||
uclogic_rdesc_ugee_v2_frame_dial_template_arr,
|
||||
uclogic_rdesc_ugee_v2_frame_dial_template_size,
|
||||
desc_params, UCLOGIC_RDESC_PH_ID_NUM);
|
||||
if (!rdesc_frame)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = uclogic_params_frame_init_with_desc(&p->frame_list[0],
|
||||
rdesc_frame,
|
||||
uclogic_rdesc_ugee_v2_frame_dial_template_size,
|
||||
UCLOGIC_RDESC_V1_FRAME_ID);
|
||||
kfree(rdesc_frame);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
p->frame_list[0].bitmap_dial_byte = 7;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_ugee_v2_init_frame_mouse() - initialize a UGEE v2 frame with a
|
||||
* mouse.
|
||||
* @p: Parameters to fill in, cannot be NULL.
|
||||
*
|
||||
* Returns:
|
||||
* Zero, if successful. A negative errno code on error.
|
||||
*/
|
||||
static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
|
||||
uclogic_rdesc_ugee_v2_frame_mouse_template_arr,
|
||||
uclogic_rdesc_ugee_v2_frame_mouse_template_size,
|
||||
UCLOGIC_RDESC_V1_FRAME_ID);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
|
||||
* discovering their parameters.
|
||||
@@ -1084,9 +1239,8 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
|
||||
const int str_desc_len = 12;
|
||||
__u8 *str_desc = NULL;
|
||||
__u8 *rdesc_pen = NULL;
|
||||
__u8 *rdesc_frame = NULL;
|
||||
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
|
||||
s32 resolution;
|
||||
enum uclogic_params_frame_type frame_type;
|
||||
__u8 magic_arr[] = {
|
||||
0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
@@ -1100,6 +1254,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
|
||||
|
||||
iface = to_usb_interface(hdev->dev.parent);
|
||||
bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
|
||||
|
||||
if (bInterfaceNumber == 0) {
|
||||
rc = uclogic_params_ugee_v2_init_frame_mouse(&p);
|
||||
if (rc)
|
||||
goto cleanup;
|
||||
|
||||
goto output;
|
||||
}
|
||||
|
||||
if (bInterfaceNumber != 2) {
|
||||
uclogic_params_init_invalid(&p);
|
||||
goto output;
|
||||
@@ -1128,25 +1291,13 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
|
||||
goto output;
|
||||
}
|
||||
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
|
||||
get_unaligned_le16(str_desc + 2);
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
|
||||
get_unaligned_le16(str_desc + 4);
|
||||
desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6];
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
|
||||
get_unaligned_le16(str_desc + 8);
|
||||
resolution = get_unaligned_le16(str_desc + 10);
|
||||
if (resolution == 0) {
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
|
||||
} else {
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
|
||||
resolution;
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
|
||||
desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
|
||||
resolution;
|
||||
}
|
||||
rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
|
||||
desc_params,
|
||||
ARRAY_SIZE(desc_params),
|
||||
&frame_type);
|
||||
if (rc)
|
||||
goto cleanup;
|
||||
|
||||
kfree(str_desc);
|
||||
str_desc = NULL;
|
||||
|
||||
@@ -1167,24 +1318,21 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
|
||||
p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
|
||||
|
||||
/* Initialize the frame interface */
|
||||
rdesc_frame = uclogic_rdesc_template_apply(
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_arr,
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_size,
|
||||
desc_params, ARRAY_SIZE(desc_params));
|
||||
if (!rdesc_frame) {
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
switch (frame_type) {
|
||||
case UCLOGIC_PARAMS_FRAME_DIAL:
|
||||
case UCLOGIC_PARAMS_FRAME_MOUSE:
|
||||
rc = uclogic_params_ugee_v2_init_frame_dial(&p, desc_params,
|
||||
ARRAY_SIZE(desc_params));
|
||||
break;
|
||||
case UCLOGIC_PARAMS_FRAME_BUTTONS:
|
||||
default:
|
||||
rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
|
||||
ARRAY_SIZE(desc_params));
|
||||
break;
|
||||
}
|
||||
|
||||
rc = uclogic_params_frame_init_with_desc(&p.frame_list[0],
|
||||
rdesc_frame,
|
||||
uclogic_rdesc_ugee_v2_frame_btn_template_size,
|
||||
UCLOGIC_RDESC_V1_FRAME_ID);
|
||||
kfree(rdesc_frame);
|
||||
if (rc) {
|
||||
uclogic_params_init_invalid(&p);
|
||||
goto output;
|
||||
}
|
||||
if (rc)
|
||||
goto cleanup;
|
||||
|
||||
output:
|
||||
/* Output parameters */
|
||||
@@ -1432,8 +1580,12 @@ int uclogic_params_init(struct uclogic_params *params,
|
||||
uclogic_params_init_invalid(&p);
|
||||
}
|
||||
break;
|
||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_PARBLO_A610_PRO):
|
||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
|
||||
case VID_PID(USB_VENDOR_ID_UGEE,
|
||||
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_S):
|
||||
rc = uclogic_params_ugee_v2_init(&p, hdev);
|
||||
if (rc != 0)
|
||||
goto cleanup;
|
||||
@@ -1517,3 +1669,7 @@ cleanup:
|
||||
uclogic_params_cleanup(&p);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HID_KUNIT_TEST
|
||||
#include "hid-uclogic-params-test.c"
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user