blob: 81de88ab2ecc73d21b122a516c5b8716bda64006 [file] [log] [blame]
Thomas Gleixnerb886d83c2019-06-01 10:08:55 +02001// SPDX-License-Identifier: GPL-2.0-only
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002/*
Filipe Laínsc08ce252020-01-12 23:50:09 +00003 * HIDPP protocol for Logitech receivers
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004 *
5 * Copyright (c) 2011 Logitech (c)
6 * Copyright (c) 2012-2013 Google (c)
7 * Copyright (c) 2013-2014 Red Hat Inc.
8 */
9
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040010
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13#include <linux/device.h>
Edwin Veldsff21a632016-01-11 00:25:15 +010014#include <linux/input.h>
15#include <linux/usb.h>
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040016#include <linux/hid.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/sched.h>
Harry Cutts4435ff22018-12-05 10:42:27 +100020#include <linux/sched/clock.h>
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040021#include <linux/kfifo.h>
22#include <linux/input/mt.h>
Edwin Veldsff21a632016-01-11 00:25:15 +010023#include <linux/workqueue.h>
24#include <linux/atomic.h>
25#include <linux/fixp-arith.h>
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040026#include <asm/unaligned.h>
Edwin Veldsff21a632016-01-11 00:25:15 +010027#include "usbhid/usbhid.h"
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040028#include "hid-ids.h"
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
32MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
33
Benjamin Tissoires9188dba2015-03-26 12:41:57 -040034static bool disable_raw_mode;
35module_param(disable_raw_mode, bool, 0644);
36MODULE_PARM_DESC(disable_raw_mode,
37 "Disable Raw mode reporting for touchpads and keep firmware gestures.");
38
Benjamin Tissoires90cdd982015-09-03 09:08:30 -040039static bool disable_tap_to_click;
40module_param(disable_tap_to_click, bool, 0644);
41MODULE_PARM_DESC(disable_tap_to_click,
42 "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently).");
43
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040044#define REPORT_ID_HIDPP_SHORT 0x10
45#define REPORT_ID_HIDPP_LONG 0x11
Simon Wooda5ce8f52015-11-19 16:42:11 -070046#define REPORT_ID_HIDPP_VERY_LONG 0x12
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040047
48#define HIDPP_REPORT_SHORT_LENGTH 7
49#define HIDPP_REPORT_LONG_LENGTH 20
Hans de Goeded71b18f2019-04-20 13:22:12 +020050#define HIDPP_REPORT_VERY_LONG_MAX_LENGTH 64
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040051
Mazin Rezkc2a93272019-10-27 17:44:06 +000052#define HIDPP_REPORT_SHORT_SUPPORTED BIT(0)
53#define HIDPP_REPORT_LONG_SUPPORTED BIT(1)
54#define HIDPP_REPORT_VERY_LONG_SUPPORTED BIT(2)
55
Hans de Goede42bc4f32019-04-20 13:22:17 +020056#define HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS 0x03
Hans de Goede4a79bcc2019-04-20 13:22:15 +020057#define HIDPP_SUB_ID_ROLLER 0x05
58#define HIDPP_SUB_ID_MOUSE_EXTRA_BTNS 0x06
Hans de Goede73833542021-04-04 20:56:09 +020059#define HIDPP_SUB_ID_USER_IFACE_EVENT 0x08
60#define HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST BIT(5)
Hans de Goede4a79bcc2019-04-20 13:22:15 +020061
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040062#define HIDPP_QUIRK_CLASS_WTP BIT(0)
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +020063#define HIDPP_QUIRK_CLASS_M560 BIT(1)
Benjamin Tissoires90cdd982015-09-03 09:08:30 -040064#define HIDPP_QUIRK_CLASS_K400 BIT(2)
Simon Wood7bfd2922015-11-19 16:42:12 -070065#define HIDPP_QUIRK_CLASS_G920 BIT(3)
Benjamin Tissoires696ecef2017-03-27 16:59:37 +020066#define HIDPP_QUIRK_CLASS_K750 BIT(4)
Benjamin Tissoires2f31c522014-09-30 13:18:27 -040067
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +020068/* bits 2..20 are reserved for classes */
Benjamin Tissoires6bd4e652016-06-29 19:28:02 +100069/* #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) disabled */
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -040070#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
Benjamin Tissoires580a7e82015-09-03 09:08:29 -040071#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
Simon Wood7bfd2922015-11-19 16:42:12 -070072#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
Benjamin Tissoires843c6242017-03-27 16:59:26 +020073#define HIDPP_QUIRK_UNIFYING BIT(25)
Harry Cutts4435ff22018-12-05 10:42:27 +100074#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
75#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
76#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
Hans de Goede4a79bcc2019-04-20 13:22:15 +020077#define HIDPP_QUIRK_HIDPP_WHEELS BIT(29)
Hans de Goede7457bc12019-04-20 13:22:16 +020078#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(30)
Hans de Goede42bc4f32019-04-20 13:22:17 +020079#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(31)
Hans de Goede4a79bcc2019-04-20 13:22:15 +020080
81/* These are just aliases for now */
82#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
83#define HIDPP_QUIRK_KBD_ZOOM_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
Harry Cutts4435ff22018-12-05 10:42:27 +100084
85/* Convenience constant to check for any high-res support. */
86#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
87 HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
88 HIDPP_QUIRK_HI_RES_SCROLL_X2121)
Benjamin Tissoires580a7e82015-09-03 09:08:29 -040089
Benjamin Tissoires6bd4e652016-06-29 19:28:02 +100090#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -040091
Benjamin Tissoires206d7c62017-03-27 16:59:25 +020092#define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0)
93#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +020094#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
95#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
Pedro Vanzellabe281362019-10-26 19:25:06 -030096#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
Filipe Laínse037acf02021-01-04 18:29:37 +000097#define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5)
98#define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6)
Benjamin Tissoires206d7c62017-03-27 16:59:25 +020099
Hans de Goedeb4c00e72020-11-14 22:20:56 +0100100#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
101
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400102/*
103 * There are two hidpp protocols in use, the first version hidpp10 is known
104 * as register access protocol or RAP, the second version hidpp20 is known as
105 * feature access protocol or FAP
106 *
107 * Most older devices (including the Unifying usb receiver) use the RAP protocol
108 * where as most newer devices use the FAP protocol. Both protocols are
109 * compatible with the underlying transport, which could be usb, Unifiying, or
110 * bluetooth. The message lengths are defined by the hid vendor specific report
111 * descriptor for the HIDPP_SHORT report type (total message lenth 7 bytes) and
112 * the HIDPP_LONG report type (total message length 20 bytes)
113 *
114 * The RAP protocol uses both report types, whereas the FAP only uses HIDPP_LONG
115 * messages. The Unifying receiver itself responds to RAP messages (device index
116 * is 0xFF for the receiver), and all messages (short or long) with a device
117 * index between 1 and 6 are passed untouched to the corresponding paired
118 * Unifying device.
119 *
120 * The paired device can be RAP or FAP, it will receive the message untouched
121 * from the Unifiying receiver.
122 */
123
124struct fap {
125 u8 feature_index;
126 u8 funcindex_clientid;
Hans de Goeded71b18f2019-04-20 13:22:12 +0200127 u8 params[HIDPP_REPORT_VERY_LONG_MAX_LENGTH - 4U];
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400128};
129
130struct rap {
131 u8 sub_id;
132 u8 reg_address;
Hans de Goeded71b18f2019-04-20 13:22:12 +0200133 u8 params[HIDPP_REPORT_VERY_LONG_MAX_LENGTH - 4U];
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400134};
135
136struct hidpp_report {
137 u8 report_id;
138 u8 device_index;
139 union {
140 struct fap fap;
141 struct rap rap;
142 u8 rawbytes[sizeof(struct fap)];
143 };
144} __packed;
145
Peter Hutterer5a2b1902016-06-29 19:28:01 +1000146struct hidpp_battery {
147 u8 feature_index;
Benjamin Tissoires696ecef2017-03-27 16:59:37 +0200148 u8 solar_feature_index;
Pedro Vanzellabe281362019-10-26 19:25:06 -0300149 u8 voltage_feature_index;
Peter Hutterer5a2b1902016-06-29 19:28:01 +1000150 struct power_supply_desc desc;
151 struct power_supply *ps;
152 char name[64];
153 int status;
Benjamin Tissoires14f437a2017-03-27 16:59:35 +0200154 int capacity;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +0200155 int level;
Pedro Vanzellabe281362019-10-26 19:25:06 -0300156 int voltage;
157 int charge_type;
Benjamin Tissoires284f8d72017-03-27 16:59:34 +0200158 bool online;
Filipe Laínse037acf02021-01-04 18:29:37 +0000159 u8 supported_levels_1004;
Peter Hutterer5a2b1902016-06-29 19:28:01 +1000160};
161
Harry Cutts4435ff22018-12-05 10:42:27 +1000162/**
163 * struct hidpp_scroll_counter - Utility class for processing high-resolution
164 * scroll events.
165 * @dev: the input device for which events should be reported.
166 * @wheel_multiplier: the scalar multiplier to be applied to each wheel event
167 * @remainder: counts the number of high-resolution units moved since the last
168 * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
169 * only be used by class methods.
170 * @direction: direction of last movement (1 or -1)
171 * @last_time: last event time, used to reset remainder after inactivity
172 */
173struct hidpp_scroll_counter {
Harry Cutts4435ff22018-12-05 10:42:27 +1000174 int wheel_multiplier;
175 int remainder;
176 int direction;
177 unsigned long long last_time;
178};
179
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400180struct hidpp_device {
181 struct hid_device *hid_dev;
Hans de Goede06104302019-04-20 13:22:13 +0200182 struct input_dev *input;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400183 struct mutex send_mutex;
184 void *send_receive_buf;
Benjamin Tissoires005b3f52015-01-08 14:37:12 -0500185 char *name; /* will never be NULL and should not be freed */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400186 wait_queue_head_t wait;
Hans de Goeded71b18f2019-04-20 13:22:12 +0200187 int very_long_report_length;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400188 bool answer_available;
189 u8 protocol_major;
190 u8 protocol_minor;
191
192 void *private_data;
193
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -0400194 struct work_struct work;
195 struct kfifo delayed_work_fifo;
196 atomic_t connected;
197 struct input_dev *delayed_input;
198
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400199 unsigned long quirks;
Benjamin Tissoires206d7c62017-03-27 16:59:25 +0200200 unsigned long capabilities;
Mazin Rezkc2a93272019-10-27 17:44:06 +0000201 u8 supported_reports;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400202
Peter Hutterer5a2b1902016-06-29 19:28:01 +1000203 struct hidpp_battery battery;
Harry Cutts4435ff22018-12-05 10:42:27 +1000204 struct hidpp_scroll_counter vertical_wheel_counter;
Mazin Rezk0da0a63b2019-10-27 17:44:13 +0000205
206 u8 wireless_feature_index;
Peter Hutterer5a2b1902016-06-29 19:28:01 +1000207};
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400208
Peter Wuf677bb12014-12-16 01:50:14 +0100209/* HID++ 1.0 error codes */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400210#define HIDPP_ERROR 0x8f
211#define HIDPP_ERROR_SUCCESS 0x00
212#define HIDPP_ERROR_INVALID_SUBID 0x01
213#define HIDPP_ERROR_INVALID_ADRESS 0x02
214#define HIDPP_ERROR_INVALID_VALUE 0x03
215#define HIDPP_ERROR_CONNECT_FAIL 0x04
216#define HIDPP_ERROR_TOO_MANY_DEVICES 0x05
217#define HIDPP_ERROR_ALREADY_EXISTS 0x06
218#define HIDPP_ERROR_BUSY 0x07
219#define HIDPP_ERROR_UNKNOWN_DEVICE 0x08
220#define HIDPP_ERROR_RESOURCE_ERROR 0x09
221#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
222#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
223#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
Peter Wuf677bb12014-12-16 01:50:14 +0100224/* HID++ 2.0 error codes */
225#define HIDPP20_ERROR 0xff
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400226
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -0400227static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
228
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400229static int __hidpp_send_report(struct hid_device *hdev,
230 struct hidpp_report *hidpp_report)
231{
Simon Wood7bfd2922015-11-19 16:42:12 -0700232 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400233 int fields_count, ret;
234
235 switch (hidpp_report->report_id) {
236 case REPORT_ID_HIDPP_SHORT:
237 fields_count = HIDPP_REPORT_SHORT_LENGTH;
238 break;
239 case REPORT_ID_HIDPP_LONG:
240 fields_count = HIDPP_REPORT_LONG_LENGTH;
241 break;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700242 case REPORT_ID_HIDPP_VERY_LONG:
Hans de Goeded71b18f2019-04-20 13:22:12 +0200243 fields_count = hidpp->very_long_report_length;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700244 break;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400245 default:
246 return -ENODEV;
247 }
248
249 /*
250 * set the device_index as the receiver, it will be overwritten by
251 * hid_hw_request if needed
252 */
253 hidpp_report->device_index = 0xff;
254
Simon Wood7bfd2922015-11-19 16:42:12 -0700255 if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
256 ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
257 } else {
258 ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
259 (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
260 HID_REQ_SET_REPORT);
261 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400262
263 return ret == fields_count ? 0 : -1;
264}
265
Lee Jones3f37fdc2021-03-26 14:34:49 +0000266/*
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500267 * hidpp_send_message_sync() returns 0 in case of success, and something else
268 * in case of a failure.
269 * - If ' something else' is positive, that means that an error has been raised
270 * by the protocol itself.
271 * - If ' something else' is negative, that means that we had a classic error
272 * (-ENOMEM, -EPIPE, etc...)
273 */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400274static int hidpp_send_message_sync(struct hidpp_device *hidpp,
275 struct hidpp_report *message,
276 struct hidpp_report *response)
277{
278 int ret;
279
280 mutex_lock(&hidpp->send_mutex);
281
282 hidpp->send_receive_buf = response;
283 hidpp->answer_available = false;
284
285 /*
286 * So that we can later validate the answer when it arrives
287 * in hidpp_raw_event
288 */
289 *response = *message;
290
291 ret = __hidpp_send_report(hidpp->hid_dev, message);
292
293 if (ret) {
294 dbg_hid("__hidpp_send_report returned err: %d\n", ret);
295 memset(response, 0, sizeof(struct hidpp_report));
296 goto exit;
297 }
298
299 if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
300 5*HZ)) {
301 dbg_hid("%s:timeout waiting for response\n", __func__);
302 memset(response, 0, sizeof(struct hidpp_report));
303 ret = -ETIMEDOUT;
304 }
305
306 if (response->report_id == REPORT_ID_HIDPP_SHORT &&
Peter Wuf677bb12014-12-16 01:50:14 +0100307 response->rap.sub_id == HIDPP_ERROR) {
308 ret = response->rap.params[1];
309 dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
310 goto exit;
311 }
312
Simon Wooda5ce8f52015-11-19 16:42:11 -0700313 if ((response->report_id == REPORT_ID_HIDPP_LONG ||
314 response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
315 response->fap.feature_index == HIDPP20_ERROR) {
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400316 ret = response->fap.params[1];
Peter Wuf677bb12014-12-16 01:50:14 +0100317 dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400318 goto exit;
319 }
320
321exit:
322 mutex_unlock(&hidpp->send_mutex);
323 return ret;
324
325}
326
327static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
328 u8 feat_index, u8 funcindex_clientid, u8 *params, int param_count,
329 struct hidpp_report *response)
330{
Dan Carpenter3e7830c2014-10-31 12:14:39 +0300331 struct hidpp_report *message;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400332 int ret;
333
334 if (param_count > sizeof(message->fap.params))
335 return -EINVAL;
336
Dan Carpenter3e7830c2014-10-31 12:14:39 +0300337 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
338 if (!message)
339 return -ENOMEM;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700340
341 if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
342 message->report_id = REPORT_ID_HIDPP_VERY_LONG;
343 else
344 message->report_id = REPORT_ID_HIDPP_LONG;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400345 message->fap.feature_index = feat_index;
346 message->fap.funcindex_clientid = funcindex_clientid;
347 memcpy(&message->fap.params, params, param_count);
348
349 ret = hidpp_send_message_sync(hidpp, message, response);
350 kfree(message);
351 return ret;
352}
353
Benjamin Tissoires33797822014-09-30 13:18:30 -0400354static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
355 u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count,
356 struct hidpp_report *response)
357{
Dan Carpenter3e7830c2014-10-31 12:14:39 +0300358 struct hidpp_report *message;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700359 int ret, max_count;
Benjamin Tissoires33797822014-09-30 13:18:30 -0400360
Mazin Rezkc2a93272019-10-27 17:44:06 +0000361 /* Send as long report if short reports are not supported. */
362 if (report_id == REPORT_ID_HIDPP_SHORT &&
363 !(hidpp_dev->supported_reports & HIDPP_REPORT_SHORT_SUPPORTED))
364 report_id = REPORT_ID_HIDPP_LONG;
365
Simon Wooda5ce8f52015-11-19 16:42:11 -0700366 switch (report_id) {
367 case REPORT_ID_HIDPP_SHORT:
368 max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
369 break;
370 case REPORT_ID_HIDPP_LONG:
371 max_count = HIDPP_REPORT_LONG_LENGTH - 4;
372 break;
373 case REPORT_ID_HIDPP_VERY_LONG:
Hans de Goeded71b18f2019-04-20 13:22:12 +0200374 max_count = hidpp_dev->very_long_report_length - 4;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700375 break;
376 default:
Benjamin Tissoires33797822014-09-30 13:18:30 -0400377 return -EINVAL;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700378 }
Benjamin Tissoires33797822014-09-30 13:18:30 -0400379
Simon Wooda5ce8f52015-11-19 16:42:11 -0700380 if (param_count > max_count)
Benjamin Tissoires33797822014-09-30 13:18:30 -0400381 return -EINVAL;
382
Dan Carpenter3e7830c2014-10-31 12:14:39 +0300383 message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
384 if (!message)
385 return -ENOMEM;
Benjamin Tissoires33797822014-09-30 13:18:30 -0400386 message->report_id = report_id;
387 message->rap.sub_id = sub_id;
388 message->rap.reg_address = reg_address;
389 memcpy(&message->rap.params, params, param_count);
390
391 ret = hidpp_send_message_sync(hidpp_dev, message, response);
392 kfree(message);
393 return ret;
394}
395
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -0400396static void delayed_work_cb(struct work_struct *work)
397{
398 struct hidpp_device *hidpp = container_of(work, struct hidpp_device,
399 work);
400 hidpp_connect_event(hidpp);
401}
402
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400403static inline bool hidpp_match_answer(struct hidpp_report *question,
404 struct hidpp_report *answer)
405{
406 return (answer->fap.feature_index == question->fap.feature_index) &&
407 (answer->fap.funcindex_clientid == question->fap.funcindex_clientid);
408}
409
410static inline bool hidpp_match_error(struct hidpp_report *question,
411 struct hidpp_report *answer)
412{
Peter Wuf677bb12014-12-16 01:50:14 +0100413 return ((answer->rap.sub_id == HIDPP_ERROR) ||
414 (answer->fap.feature_index == HIDPP20_ERROR)) &&
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400415 (answer->fap.funcindex_clientid == question->fap.feature_index) &&
416 (answer->fap.params[0] == question->fap.funcindex_clientid);
417}
418
Mazin Rezk0da0a63b2019-10-27 17:44:13 +0000419static inline bool hidpp_report_is_connect_event(struct hidpp_device *hidpp,
420 struct hidpp_report *report)
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -0400421{
Mazin Rezk0da0a63b2019-10-27 17:44:13 +0000422 return (hidpp->wireless_feature_index &&
423 (report->fap.feature_index == hidpp->wireless_feature_index)) ||
424 ((report->report_id == REPORT_ID_HIDPP_SHORT) &&
425 (report->rap.sub_id == 0x41));
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -0400426}
427
Lee Jones3f37fdc2021-03-26 14:34:49 +0000428/*
Benjamin Tissoiresa0e625f2014-12-11 17:39:59 -0500429 * hidpp_prefix_name() prefixes the current given name with "Logitech ".
430 */
431static void hidpp_prefix_name(char **name, int name_length)
432{
433#define PREFIX_LENGTH 9 /* "Logitech " */
434
435 int new_length;
436 char *new_name;
437
438 if (name_length > PREFIX_LENGTH &&
439 strncmp(*name, "Logitech ", PREFIX_LENGTH) == 0)
440 /* The prefix has is already in the name */
441 return;
442
443 new_length = PREFIX_LENGTH + name_length;
444 new_name = kzalloc(new_length, GFP_KERNEL);
445 if (!new_name)
446 return;
447
448 snprintf(new_name, new_length, "Logitech %s", *name);
449
450 kfree(*name);
451
452 *name = new_name;
453}
454
Harry Cutts4435ff22018-12-05 10:42:27 +1000455/**
456 * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
457 * events given a high-resolution wheel
458 * movement.
Lee Jones3f37fdc2021-03-26 14:34:49 +0000459 * @input_dev: Pointer to the input device
Harry Cutts4435ff22018-12-05 10:42:27 +1000460 * @counter: a hid_scroll_counter struct describing the wheel.
461 * @hi_res_value: the movement of the wheel, in the mouse's high-resolution
462 * units.
463 *
464 * Given a high-resolution movement, this function converts the movement into
465 * fractions of 120 and emits high-resolution scroll events for the input
466 * device. It also uses the multiplier from &struct hid_scroll_counter to
467 * emit low-resolution scroll events when appropriate for
468 * backwards-compatibility with userspace input libraries.
469 */
Hans de Goede06104302019-04-20 13:22:13 +0200470static void hidpp_scroll_counter_handle_scroll(struct input_dev *input_dev,
471 struct hidpp_scroll_counter *counter,
Harry Cutts4435ff22018-12-05 10:42:27 +1000472 int hi_res_value)
473{
474 int low_res_value, remainder, direction;
475 unsigned long long now, previous;
476
477 hi_res_value = hi_res_value * 120/counter->wheel_multiplier;
Hans de Goede06104302019-04-20 13:22:13 +0200478 input_report_rel(input_dev, REL_WHEEL_HI_RES, hi_res_value);
Harry Cutts4435ff22018-12-05 10:42:27 +1000479
480 remainder = counter->remainder;
481 direction = hi_res_value > 0 ? 1 : -1;
482
483 now = sched_clock();
484 previous = counter->last_time;
485 counter->last_time = now;
486 /*
487 * Reset the remainder after a period of inactivity or when the
488 * direction changes. This prevents the REL_WHEEL emulation point
489 * from sliding for devices that don't always provide the same
490 * number of movements per detent.
491 */
492 if (now - previous > 1000000000 || direction != counter->direction)
493 remainder = 0;
494
495 counter->direction = direction;
496 remainder += hi_res_value;
497
498 /* Some wheels will rest 7/8ths of a detent from the previous detent
499 * after slow movement, so we want the threshold for low-res events to
500 * be in the middle between two detents (e.g. after 4/8ths) as
501 * opposed to on the detents themselves (8/8ths).
502 */
503 if (abs(remainder) >= 60) {
504 /* Add (or subtract) 1 because we want to trigger when the wheel
505 * is half-way to the next detent (i.e. scroll 1 detent after a
506 * 1/2 detent movement, 2 detents after a 1 1/2 detent movement,
507 * etc.).
508 */
509 low_res_value = remainder / 120;
510 if (low_res_value == 0)
511 low_res_value = (hi_res_value > 0 ? 1 : -1);
Hans de Goede06104302019-04-20 13:22:13 +0200512 input_report_rel(input_dev, REL_WHEEL, low_res_value);
Harry Cutts4435ff22018-12-05 10:42:27 +1000513 remainder -= low_res_value * 120;
514 }
515 counter->remainder = remainder;
516}
517
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400518/* -------------------------------------------------------------------------- */
Benjamin Tissoires33797822014-09-30 13:18:30 -0400519/* HIDP++ 1.0 commands */
520/* -------------------------------------------------------------------------- */
521
522#define HIDPP_SET_REGISTER 0x80
523#define HIDPP_GET_REGISTER 0x81
524#define HIDPP_SET_LONG_REGISTER 0x82
525#define HIDPP_GET_LONG_REGISTER 0x83
526
Harry Cutts95c3d002018-12-05 10:42:26 +1000527/**
Hans de Goede35839f72019-04-20 13:22:14 +0200528 * hidpp10_set_register - Modify a HID++ 1.0 register.
Harry Cutts95c3d002018-12-05 10:42:26 +1000529 * @hidpp_dev: the device to set the register on.
530 * @register_address: the address of the register to modify.
531 * @byte: the byte of the register to modify. Should be less than 3.
Hans de Goede35839f72019-04-20 13:22:14 +0200532 * @mask: mask of the bits to modify
533 * @value: new values for the bits in mask
Harry Cutts95c3d002018-12-05 10:42:26 +1000534 * Return: 0 if successful, otherwise a negative error code.
535 */
Hans de Goede35839f72019-04-20 13:22:14 +0200536static int hidpp10_set_register(struct hidpp_device *hidpp_dev,
537 u8 register_address, u8 byte, u8 mask, u8 value)
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +0200538{
539 struct hidpp_report response;
540 int ret;
541 u8 params[3] = { 0 };
542
543 ret = hidpp_send_rap_command_sync(hidpp_dev,
Harry Cutts95c3d002018-12-05 10:42:26 +1000544 REPORT_ID_HIDPP_SHORT,
545 HIDPP_GET_REGISTER,
546 register_address,
547 NULL, 0, &response);
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +0200548 if (ret)
549 return ret;
550
551 memcpy(params, response.rap.params, 3);
552
Hans de Goede35839f72019-04-20 13:22:14 +0200553 params[byte] &= ~mask;
554 params[byte] |= value & mask;
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +0200555
556 return hidpp_send_rap_command_sync(hidpp_dev,
Harry Cutts95c3d002018-12-05 10:42:26 +1000557 REPORT_ID_HIDPP_SHORT,
558 HIDPP_SET_REGISTER,
559 register_address,
560 params, 3, &response);
561}
562
Hans de Goede35839f72019-04-20 13:22:14 +0200563#define HIDPP_REG_ENABLE_REPORTS 0x00
564#define HIDPP_ENABLE_CONSUMER_REPORT BIT(0)
565#define HIDPP_ENABLE_WHEEL_REPORT BIT(2)
566#define HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT BIT(3)
567#define HIDPP_ENABLE_BAT_REPORT BIT(4)
568#define HIDPP_ENABLE_HWHEEL_REPORT BIT(5)
Harry Cutts95c3d002018-12-05 10:42:26 +1000569
570static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
571{
Hans de Goede35839f72019-04-20 13:22:14 +0200572 return hidpp10_set_register(hidpp_dev, HIDPP_REG_ENABLE_REPORTS, 0,
573 HIDPP_ENABLE_BAT_REPORT, HIDPP_ENABLE_BAT_REPORT);
Harry Cutts95c3d002018-12-05 10:42:26 +1000574}
575
576#define HIDPP_REG_FEATURES 0x01
Hans de Goede35839f72019-04-20 13:22:14 +0200577#define HIDPP_ENABLE_SPECIAL_BUTTON_FUNC BIT(1)
578#define HIDPP_ENABLE_FAST_SCROLL BIT(6)
Harry Cutts95c3d002018-12-05 10:42:26 +1000579
580/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */
581static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev)
582{
Hans de Goede35839f72019-04-20 13:22:14 +0200583 return hidpp10_set_register(hidpp_dev, HIDPP_REG_FEATURES, 0,
584 HIDPP_ENABLE_FAST_SCROLL, HIDPP_ENABLE_FAST_SCROLL);
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +0200585}
586
587#define HIDPP_REG_BATTERY_STATUS 0x07
588
589static int hidpp10_battery_status_map_level(u8 param)
590{
591 int level;
592
593 switch (param) {
594 case 1 ... 2:
595 level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
596 break;
597 case 3 ... 4:
598 level = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
599 break;
600 case 5 ... 6:
601 level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
602 break;
603 case 7:
604 level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH;
605 break;
606 default:
607 level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
608 }
609
610 return level;
611}
612
613static int hidpp10_battery_status_map_status(u8 param)
614{
615 int status;
616
617 switch (param) {
618 case 0x00:
619 /* discharging (in use) */
620 status = POWER_SUPPLY_STATUS_DISCHARGING;
621 break;
622 case 0x21: /* (standard) charging */
623 case 0x24: /* fast charging */
624 case 0x25: /* slow charging */
625 status = POWER_SUPPLY_STATUS_CHARGING;
626 break;
627 case 0x26: /* topping charge */
628 case 0x22: /* charge complete */
629 status = POWER_SUPPLY_STATUS_FULL;
630 break;
631 case 0x20: /* unknown */
632 status = POWER_SUPPLY_STATUS_UNKNOWN;
633 break;
634 /*
635 * 0x01...0x1F = reserved (not charging)
636 * 0x23 = charging error
637 * 0x27..0xff = reserved
638 */
639 default:
640 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
641 break;
642 }
643
644 return status;
645}
646
647static int hidpp10_query_battery_status(struct hidpp_device *hidpp)
648{
649 struct hidpp_report response;
650 int ret, status;
651
652 ret = hidpp_send_rap_command_sync(hidpp,
653 REPORT_ID_HIDPP_SHORT,
654 HIDPP_GET_REGISTER,
655 HIDPP_REG_BATTERY_STATUS,
656 NULL, 0, &response);
657 if (ret)
658 return ret;
659
660 hidpp->battery.level =
661 hidpp10_battery_status_map_level(response.rap.params[0]);
662 status = hidpp10_battery_status_map_status(response.rap.params[1]);
663 hidpp->battery.status = status;
664 /* the capacity is only available when discharging or full */
665 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
666 status == POWER_SUPPLY_STATUS_FULL;
667
668 return 0;
669}
670
671#define HIDPP_REG_BATTERY_MILEAGE 0x0D
672
673static int hidpp10_battery_mileage_map_status(u8 param)
674{
675 int status;
676
677 switch (param >> 6) {
678 case 0x00:
679 /* discharging (in use) */
680 status = POWER_SUPPLY_STATUS_DISCHARGING;
681 break;
682 case 0x01: /* charging */
683 status = POWER_SUPPLY_STATUS_CHARGING;
684 break;
685 case 0x02: /* charge complete */
686 status = POWER_SUPPLY_STATUS_FULL;
687 break;
688 /*
689 * 0x03 = charging error
690 */
691 default:
692 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
693 break;
694 }
695
696 return status;
697}
698
699static int hidpp10_query_battery_mileage(struct hidpp_device *hidpp)
700{
701 struct hidpp_report response;
702 int ret, status;
703
704 ret = hidpp_send_rap_command_sync(hidpp,
705 REPORT_ID_HIDPP_SHORT,
706 HIDPP_GET_REGISTER,
707 HIDPP_REG_BATTERY_MILEAGE,
708 NULL, 0, &response);
709 if (ret)
710 return ret;
711
712 hidpp->battery.capacity = response.rap.params[0];
713 status = hidpp10_battery_mileage_map_status(response.rap.params[2]);
714 hidpp->battery.status = status;
715 /* the capacity is only available when discharging or full */
716 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
717 status == POWER_SUPPLY_STATUS_FULL;
718
719 return 0;
720}
721
722static int hidpp10_battery_event(struct hidpp_device *hidpp, u8 *data, int size)
723{
724 struct hidpp_report *report = (struct hidpp_report *)data;
725 int status, capacity, level;
726 bool changed;
727
728 if (report->report_id != REPORT_ID_HIDPP_SHORT)
729 return 0;
730
731 switch (report->rap.sub_id) {
732 case HIDPP_REG_BATTERY_STATUS:
733 capacity = hidpp->battery.capacity;
734 level = hidpp10_battery_status_map_level(report->rawbytes[1]);
735 status = hidpp10_battery_status_map_status(report->rawbytes[2]);
736 break;
737 case HIDPP_REG_BATTERY_MILEAGE:
738 capacity = report->rap.params[0];
739 level = hidpp->battery.level;
740 status = hidpp10_battery_mileage_map_status(report->rawbytes[3]);
741 break;
742 default:
743 return 0;
744 }
745
746 changed = capacity != hidpp->battery.capacity ||
747 level != hidpp->battery.level ||
748 status != hidpp->battery.status;
749
750 /* the capacity is only available when discharging or full */
751 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
752 status == POWER_SUPPLY_STATUS_FULL;
753
754 if (changed) {
755 hidpp->battery.level = level;
756 hidpp->battery.status = status;
757 if (hidpp->battery.ps)
758 power_supply_changed(hidpp->battery.ps);
759 }
760
761 return 0;
762}
763
Benjamin Tissoires33797822014-09-30 13:18:30 -0400764#define HIDPP_REG_PAIRING_INFORMATION 0xB5
Benjamin Tissoires843c6242017-03-27 16:59:26 +0200765#define HIDPP_EXTENDED_PAIRING 0x30
766#define HIDPP_DEVICE_NAME 0x40
Benjamin Tissoires33797822014-09-30 13:18:30 -0400767
Benjamin Tissoires843c6242017-03-27 16:59:26 +0200768static char *hidpp_unifying_get_name(struct hidpp_device *hidpp_dev)
Benjamin Tissoires33797822014-09-30 13:18:30 -0400769{
770 struct hidpp_report response;
771 int ret;
Benjamin Tissoires843c6242017-03-27 16:59:26 +0200772 u8 params[1] = { HIDPP_DEVICE_NAME };
Benjamin Tissoires33797822014-09-30 13:18:30 -0400773 char *name;
774 int len;
775
776 ret = hidpp_send_rap_command_sync(hidpp_dev,
777 REPORT_ID_HIDPP_SHORT,
778 HIDPP_GET_LONG_REGISTER,
779 HIDPP_REG_PAIRING_INFORMATION,
780 params, 1, &response);
781 if (ret)
782 return NULL;
783
784 len = response.rap.params[1];
785
Peter Wu3a034a72014-12-11 13:51:19 +0100786 if (2 + len > sizeof(response.rap.params))
787 return NULL;
788
Hans de Goede22bf6bd2019-04-20 13:22:06 +0200789 if (len < 4) /* logitech devices are usually at least Xddd */
790 return NULL;
791
Benjamin Tissoires33797822014-09-30 13:18:30 -0400792 name = kzalloc(len + 1, GFP_KERNEL);
793 if (!name)
794 return NULL;
795
796 memcpy(name, &response.rap.params[2], len);
Benjamin Tissoiresa0e625f2014-12-11 17:39:59 -0500797
798 /* include the terminating '\0' */
799 hidpp_prefix_name(&name, len + 1);
800
Benjamin Tissoires33797822014-09-30 13:18:30 -0400801 return name;
802}
803
Benjamin Tissoires843c6242017-03-27 16:59:26 +0200804static int hidpp_unifying_get_serial(struct hidpp_device *hidpp, u32 *serial)
805{
806 struct hidpp_report response;
807 int ret;
808 u8 params[1] = { HIDPP_EXTENDED_PAIRING };
809
810 ret = hidpp_send_rap_command_sync(hidpp,
811 REPORT_ID_HIDPP_SHORT,
812 HIDPP_GET_LONG_REGISTER,
813 HIDPP_REG_PAIRING_INFORMATION,
814 params, 1, &response);
815 if (ret)
816 return ret;
817
818 /*
819 * We don't care about LE or BE, we will output it as a string
820 * with %4phD, so we need to keep the order.
821 */
822 *serial = *((u32 *)&response.rap.params[1]);
823 return 0;
824}
825
826static int hidpp_unifying_init(struct hidpp_device *hidpp)
827{
828 struct hid_device *hdev = hidpp->hid_dev;
829 const char *name;
830 u32 serial;
831 int ret;
832
833 ret = hidpp_unifying_get_serial(hidpp, &serial);
834 if (ret)
835 return ret;
836
837 snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD",
838 hdev->product, &serial);
839 dbg_hid("HID++ Unifying: Got serial: %s\n", hdev->uniq);
840
841 name = hidpp_unifying_get_name(hidpp);
842 if (!name)
843 return -EIO;
844
845 snprintf(hdev->name, sizeof(hdev->name), "%s", name);
846 dbg_hid("HID++ Unifying: Got name: %s\n", name);
847
848 kfree(name);
849 return 0;
850}
851
Benjamin Tissoires33797822014-09-30 13:18:30 -0400852/* -------------------------------------------------------------------------- */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400853/* 0x0000: Root */
854/* -------------------------------------------------------------------------- */
855
856#define HIDPP_PAGE_ROOT 0x0000
857#define HIDPP_PAGE_ROOT_IDX 0x00
858
859#define CMD_ROOT_GET_FEATURE 0x01
860#define CMD_ROOT_GET_PROTOCOL_VERSION 0x11
861
862static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature,
863 u8 *feature_index, u8 *feature_type)
864{
865 struct hidpp_report response;
866 int ret;
867 u8 params[2] = { feature >> 8, feature & 0x00FF };
868
869 ret = hidpp_send_fap_command_sync(hidpp,
870 HIDPP_PAGE_ROOT_IDX,
871 CMD_ROOT_GET_FEATURE,
872 params, 2, &response);
873 if (ret)
874 return ret;
875
Benjamin Tissoiresa9525b82017-03-27 16:59:32 +0200876 if (response.fap.params[0] == 0)
877 return -ENOENT;
878
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400879 *feature_index = response.fap.params[0];
880 *feature_type = response.fap.params[1];
881
882 return ret;
883}
884
885static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
886{
Hans de Goede09637752019-04-20 13:22:10 +0200887 const u8 ping_byte = 0x5a;
888 u8 ping_data[3] = { 0, 0, ping_byte };
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400889 struct hidpp_report response;
890 int ret;
891
Hans de Goede09637752019-04-20 13:22:10 +0200892 ret = hidpp_send_rap_command_sync(hidpp,
893 REPORT_ID_HIDPP_SHORT,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400894 HIDPP_PAGE_ROOT_IDX,
895 CMD_ROOT_GET_PROTOCOL_VERSION,
Hans de Goede09637752019-04-20 13:22:10 +0200896 ping_data, sizeof(ping_data), &response);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400897
Benjamin Tissoires552f12e2014-11-03 16:09:59 -0500898 if (ret == HIDPP_ERROR_INVALID_SUBID) {
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400899 hidpp->protocol_major = 1;
900 hidpp->protocol_minor = 0;
Hans de Goede9576af62019-03-22 08:41:38 +0100901 goto print_version;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400902 }
903
Benjamin Tissoires552f12e2014-11-03 16:09:59 -0500904 /* the device might not be connected */
905 if (ret == HIDPP_ERROR_RESOURCE_ERROR)
906 return -EIO;
907
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500908 if (ret > 0) {
909 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
910 __func__, ret);
911 return -EPROTO;
912 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400913 if (ret)
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500914 return ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400915
Hans de Goede09637752019-04-20 13:22:10 +0200916 if (response.rap.params[2] != ping_byte) {
917 hid_err(hidpp->hid_dev, "%s: ping mismatch 0x%02x != 0x%02x\n",
918 __func__, response.rap.params[2], ping_byte);
919 return -EPROTO;
920 }
921
922 hidpp->protocol_major = response.rap.params[0];
923 hidpp->protocol_minor = response.rap.params[1];
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400924
Hans de Goede9576af62019-03-22 08:41:38 +0100925print_version:
926 hid_info(hidpp->hid_dev, "HID++ %u.%u device connected.\n",
927 hidpp->protocol_major, hidpp->protocol_minor);
928 return 0;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400929}
930
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400931/* -------------------------------------------------------------------------- */
932/* 0x0005: GetDeviceNameType */
933/* -------------------------------------------------------------------------- */
934
935#define HIDPP_PAGE_GET_DEVICE_NAME_TYPE 0x0005
936
937#define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x01
938#define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x11
939#define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x21
940
941static int hidpp_devicenametype_get_count(struct hidpp_device *hidpp,
942 u8 feature_index, u8 *nameLength)
943{
944 struct hidpp_report response;
945 int ret;
946
947 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
948 CMD_GET_DEVICE_NAME_TYPE_GET_COUNT, NULL, 0, &response);
949
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500950 if (ret > 0) {
951 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
952 __func__, ret);
953 return -EPROTO;
954 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400955 if (ret)
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500956 return ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400957
958 *nameLength = response.fap.params[0];
959
960 return ret;
961}
962
963static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
964 u8 feature_index, u8 char_index, char *device_name, int len_buf)
965{
966 struct hidpp_report response;
967 int ret, i;
968 int count;
969
970 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
971 CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME, &char_index, 1,
972 &response);
973
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500974 if (ret > 0) {
975 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
976 __func__, ret);
977 return -EPROTO;
978 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400979 if (ret)
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -0500980 return ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400981
Simon Wooda5ce8f52015-11-19 16:42:11 -0700982 switch (response.report_id) {
983 case REPORT_ID_HIDPP_VERY_LONG:
Hans de Goeded71b18f2019-04-20 13:22:12 +0200984 count = hidpp->very_long_report_length - 4;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700985 break;
986 case REPORT_ID_HIDPP_LONG:
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400987 count = HIDPP_REPORT_LONG_LENGTH - 4;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700988 break;
989 case REPORT_ID_HIDPP_SHORT:
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400990 count = HIDPP_REPORT_SHORT_LENGTH - 4;
Simon Wooda5ce8f52015-11-19 16:42:11 -0700991 break;
992 default:
993 return -EPROTO;
994 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -0400995
996 if (len_buf < count)
997 count = len_buf;
998
999 for (i = 0; i < count; i++)
1000 device_name[i] = response.fap.params[i];
1001
1002 return count;
1003}
1004
Peter Wu02cc0972014-12-11 13:51:17 +01001005static char *hidpp_get_device_name(struct hidpp_device *hidpp)
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001006{
1007 u8 feature_type;
1008 u8 feature_index;
1009 u8 __name_length;
1010 char *name;
1011 unsigned index = 0;
1012 int ret;
1013
1014 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_GET_DEVICE_NAME_TYPE,
1015 &feature_index, &feature_type);
1016 if (ret)
Peter Wu02cc0972014-12-11 13:51:17 +01001017 return NULL;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001018
1019 ret = hidpp_devicenametype_get_count(hidpp, feature_index,
1020 &__name_length);
1021 if (ret)
Peter Wu02cc0972014-12-11 13:51:17 +01001022 return NULL;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001023
1024 name = kzalloc(__name_length + 1, GFP_KERNEL);
1025 if (!name)
Peter Wu02cc0972014-12-11 13:51:17 +01001026 return NULL;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001027
Peter Wu1430ee72014-12-11 13:51:18 +01001028 while (index < __name_length) {
1029 ret = hidpp_devicenametype_get_device_name(hidpp,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001030 feature_index, index, name + index,
1031 __name_length - index);
Peter Wu1430ee72014-12-11 13:51:18 +01001032 if (ret <= 0) {
1033 kfree(name);
1034 return NULL;
1035 }
1036 index += ret;
1037 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001038
Benjamin Tissoiresa0e625f2014-12-11 17:39:59 -05001039 /* include the terminating '\0' */
1040 hidpp_prefix_name(&name, __name_length + 1);
1041
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001042 return name;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001043}
1044
1045/* -------------------------------------------------------------------------- */
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001046/* 0x1000: Battery level status */
1047/* -------------------------------------------------------------------------- */
1048
1049#define HIDPP_PAGE_BATTERY_LEVEL_STATUS 0x1000
1050
1051#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS 0x00
1052#define CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY 0x10
1053
1054#define EVENT_BATTERY_LEVEL_STATUS_BROADCAST 0x00
1055
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001056#define FLAG_BATTERY_LEVEL_DISABLE_OSD BIT(0)
1057#define FLAG_BATTERY_LEVEL_MILEAGE BIT(1)
1058#define FLAG_BATTERY_LEVEL_RECHARGEABLE BIT(2)
1059
1060static int hidpp_map_battery_level(int capacity)
1061{
1062 if (capacity < 11)
1063 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
Hans de Goede1f87b0c2019-03-22 08:41:40 +01001064 /*
1065 * The spec says this should be < 31 but some devices report 30
1066 * with brand new batteries and Windows reports 30 as "Good".
1067 */
1068 else if (capacity < 30)
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001069 return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
1070 else if (capacity < 81)
1071 return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1072 return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1073}
1074
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001075static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001076 int *next_capacity,
1077 int *level)
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001078{
1079 int status;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001080
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001081 *capacity = data[0];
1082 *next_capacity = data[1];
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001083 *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001084
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001085 /* When discharging, we can rely on the device reported capacity.
1086 * For all other states the device reports 0 (unknown).
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001087 */
1088 switch (data[2]) {
1089 case 0: /* discharging (in use) */
1090 status = POWER_SUPPLY_STATUS_DISCHARGING;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001091 *level = hidpp_map_battery_level(*capacity);
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001092 break;
1093 case 1: /* recharging */
1094 status = POWER_SUPPLY_STATUS_CHARGING;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001095 break;
1096 case 2: /* charge in final stage */
1097 status = POWER_SUPPLY_STATUS_CHARGING;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001098 break;
1099 case 3: /* charge complete */
1100 status = POWER_SUPPLY_STATUS_FULL;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001101 *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001102 *capacity = 100;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001103 break;
1104 case 4: /* recharging below optimal speed */
1105 status = POWER_SUPPLY_STATUS_CHARGING;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001106 break;
1107 /* 5 = invalid battery type
1108 6 = thermal error
1109 7 = other charging error */
1110 default:
1111 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001112 break;
1113 }
1114
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001115 return status;
1116}
1117
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001118static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
1119 u8 feature_index,
1120 int *status,
1121 int *capacity,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001122 int *next_capacity,
1123 int *level)
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001124{
1125 struct hidpp_report response;
1126 int ret;
1127 u8 *params = (u8 *)response.fap.params;
1128
1129 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1130 CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_LEVEL_STATUS,
1131 NULL, 0, &response);
Hans de Goede61005d62019-11-14 15:30:46 +01001132 /* Ignore these intermittent errors */
1133 if (ret == HIDPP_ERROR_RESOURCE_ERROR)
1134 return -EIO;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001135 if (ret > 0) {
1136 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1137 __func__, ret);
1138 return -EPROTO;
1139 }
1140 if (ret)
1141 return ret;
1142
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001143 *status = hidpp20_batterylevel_map_status_capacity(params, capacity,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001144 next_capacity,
1145 level);
1146
1147 return 0;
1148}
1149
1150static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
1151 u8 feature_index)
1152{
1153 struct hidpp_report response;
1154 int ret;
1155 u8 *params = (u8 *)response.fap.params;
1156 unsigned int level_count, flags;
1157
1158 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1159 CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY,
1160 NULL, 0, &response);
1161 if (ret > 0) {
1162 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1163 __func__, ret);
1164 return -EPROTO;
1165 }
1166 if (ret)
1167 return ret;
1168
1169 level_count = params[0];
1170 flags = params[1];
1171
1172 if (level_count < 10 || !(flags & FLAG_BATTERY_LEVEL_MILEAGE))
1173 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
1174 else
1175 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001176
1177 return 0;
1178}
1179
Filipe Laínse037acf02021-01-04 18:29:37 +00001180static int hidpp20_query_battery_info_1000(struct hidpp_device *hidpp)
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001181{
1182 u8 feature_type;
1183 int ret;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001184 int status, capacity, next_capacity, level;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001185
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02001186 if (hidpp->battery.feature_index == 0xff) {
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001187 ret = hidpp_root_get_feature(hidpp,
1188 HIDPP_PAGE_BATTERY_LEVEL_STATUS,
1189 &hidpp->battery.feature_index,
1190 &feature_type);
1191 if (ret)
1192 return ret;
1193 }
1194
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001195 ret = hidpp20_batterylevel_get_battery_capacity(hidpp,
1196 hidpp->battery.feature_index,
1197 &status, &capacity,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001198 &next_capacity, &level);
1199 if (ret)
1200 return ret;
1201
1202 ret = hidpp20_batterylevel_get_battery_info(hidpp,
1203 hidpp->battery.feature_index);
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001204 if (ret)
1205 return ret;
1206
1207 hidpp->battery.status = status;
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001208 hidpp->battery.capacity = capacity;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001209 hidpp->battery.level = level;
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02001210 /* the capacity is only available when discharging or full */
1211 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
1212 status == POWER_SUPPLY_STATUS_FULL;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001213
1214 return 0;
1215}
1216
Filipe Laínse037acf02021-01-04 18:29:37 +00001217static int hidpp20_battery_event_1000(struct hidpp_device *hidpp,
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001218 u8 *data, int size)
1219{
1220 struct hidpp_report *report = (struct hidpp_report *)data;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001221 int status, capacity, next_capacity, level;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001222 bool changed;
1223
1224 if (report->fap.feature_index != hidpp->battery.feature_index ||
1225 report->fap.funcindex_clientid != EVENT_BATTERY_LEVEL_STATUS_BROADCAST)
1226 return 0;
1227
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001228 status = hidpp20_batterylevel_map_status_capacity(report->fap.params,
1229 &capacity,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001230 &next_capacity,
1231 &level);
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001232
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02001233 /* the capacity is only available when discharging or full */
1234 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
1235 status == POWER_SUPPLY_STATUS_FULL;
1236
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001237 changed = capacity != hidpp->battery.capacity ||
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001238 level != hidpp->battery.level ||
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001239 status != hidpp->battery.status;
1240
1241 if (changed) {
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001242 hidpp->battery.level = level;
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001243 hidpp->battery.capacity = capacity;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001244 hidpp->battery.status = status;
1245 if (hidpp->battery.ps)
1246 power_supply_changed(hidpp->battery.ps);
1247 }
1248
1249 return 0;
1250}
1251
Pedro Vanzellabe281362019-10-26 19:25:06 -03001252/* -------------------------------------------------------------------------- */
1253/* 0x1001: Battery voltage */
1254/* -------------------------------------------------------------------------- */
1255
1256#define HIDPP_PAGE_BATTERY_VOLTAGE 0x1001
1257
1258#define CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE 0x00
1259
1260#define EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST 0x00
1261
1262static int hidpp20_battery_map_status_voltage(u8 data[3], int *voltage,
1263 int *level, int *charge_type)
1264{
1265 int status;
1266
Filipe Laíns4ab2bb32020-01-11 19:24:19 +00001267 long flags = (long) data[2];
Tom Rix81c8bf92021-05-07 12:18:19 -07001268 *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
Pedro Vanzellabe281362019-10-26 19:25:06 -03001269
Filipe Laíns4ab2bb32020-01-11 19:24:19 +00001270 if (flags & 0x80)
1271 switch (flags & 0x07) {
1272 case 0:
1273 status = POWER_SUPPLY_STATUS_CHARGING;
1274 break;
1275 case 1:
1276 status = POWER_SUPPLY_STATUS_FULL;
1277 *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1278 break;
1279 case 2:
1280 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1281 break;
1282 default:
1283 status = POWER_SUPPLY_STATUS_UNKNOWN;
1284 break;
1285 }
1286 else
Pedro Vanzellabe281362019-10-26 19:25:06 -03001287 status = POWER_SUPPLY_STATUS_DISCHARGING;
Pedro Vanzellabe281362019-10-26 19:25:06 -03001288
1289 *charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
Filipe Laíns4ab2bb32020-01-11 19:24:19 +00001290 if (test_bit(3, &flags)) {
Pedro Vanzellabe281362019-10-26 19:25:06 -03001291 *charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
1292 }
Filipe Laíns4ab2bb32020-01-11 19:24:19 +00001293 if (test_bit(4, &flags)) {
Pedro Vanzellabe281362019-10-26 19:25:06 -03001294 *charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
1295 }
Filipe Laíns4ab2bb32020-01-11 19:24:19 +00001296 if (test_bit(5, &flags)) {
Pedro Vanzellabe281362019-10-26 19:25:06 -03001297 *level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
1298 }
1299
1300 *voltage = get_unaligned_be16(data);
1301
1302 return status;
1303}
1304
1305static int hidpp20_battery_get_battery_voltage(struct hidpp_device *hidpp,
1306 u8 feature_index,
1307 int *status, int *voltage,
1308 int *level, int *charge_type)
1309{
1310 struct hidpp_report response;
1311 int ret;
1312 u8 *params = (u8 *)response.fap.params;
1313
1314 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1315 CMD_BATTERY_VOLTAGE_GET_BATTERY_VOLTAGE,
1316 NULL, 0, &response);
1317
1318 if (ret > 0) {
1319 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1320 __func__, ret);
1321 return -EPROTO;
1322 }
1323 if (ret)
1324 return ret;
1325
1326 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_VOLTAGE;
1327
1328 *status = hidpp20_battery_map_status_voltage(params, voltage,
1329 level, charge_type);
1330
1331 return 0;
1332}
1333
Hamza Mahfoozb23cdfb2021-08-02 08:52:32 -04001334static int hidpp20_map_battery_capacity(struct hid_device *hid_dev, int voltage)
1335{
1336 /* NB: This voltage curve doesn't necessarily map perfectly to all
1337 * devices that implement the BATTERY_VOLTAGE feature. This is because
1338 * there are a few devices that use different battery technology.
1339 */
1340
1341 static const int voltages[] = {
1342 4186, 4156, 4143, 4133, 4122, 4113, 4103, 4094, 4086, 4075,
1343 4067, 4059, 4051, 4043, 4035, 4027, 4019, 4011, 4003, 3997,
1344 3989, 3983, 3976, 3969, 3961, 3955, 3949, 3942, 3935, 3929,
1345 3922, 3916, 3909, 3902, 3896, 3890, 3883, 3877, 3870, 3865,
1346 3859, 3853, 3848, 3842, 3837, 3833, 3828, 3824, 3819, 3815,
1347 3811, 3808, 3804, 3800, 3797, 3793, 3790, 3787, 3784, 3781,
1348 3778, 3775, 3772, 3770, 3767, 3764, 3762, 3759, 3757, 3754,
1349 3751, 3748, 3744, 3741, 3737, 3734, 3730, 3726, 3724, 3720,
1350 3717, 3714, 3710, 3706, 3702, 3697, 3693, 3688, 3683, 3677,
1351 3671, 3666, 3662, 3658, 3654, 3646, 3633, 3612, 3579, 3537
1352 };
1353
1354 int i;
1355
1356 BUILD_BUG_ON(ARRAY_SIZE(voltages) != 100);
1357
1358 if (unlikely(voltage < 3500 || voltage >= 5000))
1359 hid_warn_once(hid_dev,
1360 "%s: possibly using the wrong voltage curve\n",
1361 __func__);
1362
1363 for (i = 0; i < ARRAY_SIZE(voltages); i++) {
1364 if (voltage >= voltages[i])
1365 return ARRAY_SIZE(voltages) - i;
1366 }
1367
1368 return 0;
1369}
1370
Pedro Vanzellabe281362019-10-26 19:25:06 -03001371static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp)
1372{
1373 u8 feature_type;
1374 int ret;
1375 int status, voltage, level, charge_type;
1376
1377 if (hidpp->battery.voltage_feature_index == 0xff) {
1378 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_BATTERY_VOLTAGE,
1379 &hidpp->battery.voltage_feature_index,
1380 &feature_type);
1381 if (ret)
1382 return ret;
1383 }
1384
1385 ret = hidpp20_battery_get_battery_voltage(hidpp,
1386 hidpp->battery.voltage_feature_index,
1387 &status, &voltage, &level, &charge_type);
1388
1389 if (ret)
1390 return ret;
1391
1392 hidpp->battery.status = status;
1393 hidpp->battery.voltage = voltage;
Hamza Mahfoozb23cdfb2021-08-02 08:52:32 -04001394 hidpp->battery.capacity = hidpp20_map_battery_capacity(hidpp->hid_dev,
1395 voltage);
Pedro Vanzellabe281362019-10-26 19:25:06 -03001396 hidpp->battery.level = level;
1397 hidpp->battery.charge_type = charge_type;
1398 hidpp->battery.online = status != POWER_SUPPLY_STATUS_NOT_CHARGING;
1399
1400 return 0;
1401}
1402
1403static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp,
1404 u8 *data, int size)
1405{
1406 struct hidpp_report *report = (struct hidpp_report *)data;
1407 int status, voltage, level, charge_type;
1408
1409 if (report->fap.feature_index != hidpp->battery.voltage_feature_index ||
1410 report->fap.funcindex_clientid != EVENT_BATTERY_VOLTAGE_STATUS_BROADCAST)
1411 return 0;
1412
1413 status = hidpp20_battery_map_status_voltage(report->fap.params, &voltage,
1414 &level, &charge_type);
1415
1416 hidpp->battery.online = status != POWER_SUPPLY_STATUS_NOT_CHARGING;
1417
1418 if (voltage != hidpp->battery.voltage || status != hidpp->battery.status) {
1419 hidpp->battery.voltage = voltage;
Hamza Mahfoozb23cdfb2021-08-02 08:52:32 -04001420 hidpp->battery.capacity = hidpp20_map_battery_capacity(hidpp->hid_dev,
1421 voltage);
Pedro Vanzellabe281362019-10-26 19:25:06 -03001422 hidpp->battery.status = status;
1423 hidpp->battery.level = level;
1424 hidpp->battery.charge_type = charge_type;
1425 if (hidpp->battery.ps)
1426 power_supply_changed(hidpp->battery.ps);
1427 }
1428 return 0;
1429}
1430
Filipe Laínse037acf02021-01-04 18:29:37 +00001431/* -------------------------------------------------------------------------- */
1432/* 0x1004: Unified battery */
1433/* -------------------------------------------------------------------------- */
1434
1435#define HIDPP_PAGE_UNIFIED_BATTERY 0x1004
1436
1437#define CMD_UNIFIED_BATTERY_GET_CAPABILITIES 0x00
1438#define CMD_UNIFIED_BATTERY_GET_STATUS 0x10
1439
1440#define EVENT_UNIFIED_BATTERY_STATUS_EVENT 0x00
1441
1442#define FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL BIT(0)
1443#define FLAG_UNIFIED_BATTERY_LEVEL_LOW BIT(1)
1444#define FLAG_UNIFIED_BATTERY_LEVEL_GOOD BIT(2)
1445#define FLAG_UNIFIED_BATTERY_LEVEL_FULL BIT(3)
1446
1447#define FLAG_UNIFIED_BATTERY_FLAGS_RECHARGEABLE BIT(0)
1448#define FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE BIT(1)
1449
1450static int hidpp20_unifiedbattery_get_capabilities(struct hidpp_device *hidpp,
1451 u8 feature_index)
1452{
1453 struct hidpp_report response;
1454 int ret;
1455 u8 *params = (u8 *)response.fap.params;
1456
1457 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS ||
1458 hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) {
1459 /* we have already set the device capabilities, so let's skip */
1460 return 0;
1461 }
1462
1463 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1464 CMD_UNIFIED_BATTERY_GET_CAPABILITIES,
1465 NULL, 0, &response);
1466 /* Ignore these intermittent errors */
1467 if (ret == HIDPP_ERROR_RESOURCE_ERROR)
1468 return -EIO;
1469 if (ret > 0) {
1470 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1471 __func__, ret);
1472 return -EPROTO;
1473 }
1474 if (ret)
1475 return ret;
1476
1477 /*
1478 * If the device supports state of charge (battery percentage) we won't
1479 * export the battery level information. there are 4 possible battery
1480 * levels and they all are optional, this means that the device might
1481 * not support any of them, we are just better off with the battery
1482 * percentage.
1483 */
1484 if (params[1] & FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE) {
1485 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_PERCENTAGE;
1486 hidpp->battery.supported_levels_1004 = 0;
1487 } else {
1488 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
1489 hidpp->battery.supported_levels_1004 = params[0];
1490 }
1491
1492 return 0;
1493}
1494
1495static int hidpp20_unifiedbattery_map_status(struct hidpp_device *hidpp,
1496 u8 charging_status,
1497 u8 external_power_status)
1498{
1499 int status;
1500
1501 switch (charging_status) {
1502 case 0: /* discharging */
1503 status = POWER_SUPPLY_STATUS_DISCHARGING;
1504 break;
1505 case 1: /* charging */
1506 case 2: /* charging slow */
1507 status = POWER_SUPPLY_STATUS_CHARGING;
1508 break;
1509 case 3: /* complete */
1510 status = POWER_SUPPLY_STATUS_FULL;
1511 break;
1512 case 4: /* error */
1513 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1514 hid_info(hidpp->hid_dev, "%s: charging error",
1515 hidpp->name);
1516 break;
1517 default:
1518 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
1519 break;
1520 }
1521
1522 return status;
1523}
1524
1525static int hidpp20_unifiedbattery_map_level(struct hidpp_device *hidpp,
1526 u8 battery_level)
1527{
1528 /* cler unsupported level bits */
1529 battery_level &= hidpp->battery.supported_levels_1004;
1530
1531 if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_FULL)
1532 return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
1533 else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_GOOD)
1534 return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
1535 else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_LOW)
1536 return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
1537 else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL)
1538 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
1539
1540 return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
1541}
1542
1543static int hidpp20_unifiedbattery_get_status(struct hidpp_device *hidpp,
1544 u8 feature_index,
1545 u8 *state_of_charge,
1546 int *status,
1547 int *level)
1548{
1549 struct hidpp_report response;
1550 int ret;
1551 u8 *params = (u8 *)response.fap.params;
1552
1553 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1554 CMD_UNIFIED_BATTERY_GET_STATUS,
1555 NULL, 0, &response);
1556 /* Ignore these intermittent errors */
1557 if (ret == HIDPP_ERROR_RESOURCE_ERROR)
1558 return -EIO;
1559 if (ret > 0) {
1560 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1561 __func__, ret);
1562 return -EPROTO;
1563 }
1564 if (ret)
1565 return ret;
1566
1567 *state_of_charge = params[0];
1568 *status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
1569 *level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
1570
1571 return 0;
1572}
1573
1574static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp)
1575{
1576 u8 feature_type;
1577 int ret;
1578 u8 state_of_charge;
1579 int status, level;
1580
1581 if (hidpp->battery.feature_index == 0xff) {
1582 ret = hidpp_root_get_feature(hidpp,
1583 HIDPP_PAGE_UNIFIED_BATTERY,
1584 &hidpp->battery.feature_index,
1585 &feature_type);
1586 if (ret)
1587 return ret;
1588 }
1589
1590 ret = hidpp20_unifiedbattery_get_capabilities(hidpp,
1591 hidpp->battery.feature_index);
1592 if (ret)
1593 return ret;
1594
1595 ret = hidpp20_unifiedbattery_get_status(hidpp,
1596 hidpp->battery.feature_index,
1597 &state_of_charge,
1598 &status,
1599 &level);
1600 if (ret)
1601 return ret;
1602
1603 hidpp->capabilities |= HIDPP_CAPABILITY_UNIFIED_BATTERY;
1604 hidpp->battery.capacity = state_of_charge;
1605 hidpp->battery.status = status;
1606 hidpp->battery.level = level;
1607 hidpp->battery.online = true;
1608
1609 return 0;
1610}
1611
1612static int hidpp20_battery_event_1004(struct hidpp_device *hidpp,
1613 u8 *data, int size)
1614{
1615 struct hidpp_report *report = (struct hidpp_report *)data;
1616 u8 *params = (u8 *)report->fap.params;
1617 int state_of_charge, status, level;
1618 bool changed;
1619
1620 if (report->fap.feature_index != hidpp->battery.feature_index ||
1621 report->fap.funcindex_clientid != EVENT_UNIFIED_BATTERY_STATUS_EVENT)
1622 return 0;
1623
1624 state_of_charge = params[0];
1625 status = hidpp20_unifiedbattery_map_status(hidpp, params[2], params[3]);
1626 level = hidpp20_unifiedbattery_map_level(hidpp, params[1]);
1627
1628 changed = status != hidpp->battery.status ||
1629 (state_of_charge != hidpp->battery.capacity &&
1630 hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE) ||
1631 (level != hidpp->battery.level &&
1632 hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS);
1633
1634 if (changed) {
1635 hidpp->battery.capacity = state_of_charge;
1636 hidpp->battery.status = status;
1637 hidpp->battery.level = level;
1638 if (hidpp->battery.ps)
1639 power_supply_changed(hidpp->battery.ps);
1640 }
1641
1642 return 0;
1643}
1644
1645/* -------------------------------------------------------------------------- */
1646/* Battery feature helpers */
1647/* -------------------------------------------------------------------------- */
1648
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001649static enum power_supply_property hidpp_battery_props[] = {
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02001650 POWER_SUPPLY_PROP_ONLINE,
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001651 POWER_SUPPLY_PROP_STATUS,
Bastien Nocera3861e6c2017-03-27 16:59:22 +02001652 POWER_SUPPLY_PROP_SCOPE,
Benjamin Tissoires32043d02017-03-27 16:59:30 +02001653 POWER_SUPPLY_PROP_MODEL_NAME,
1654 POWER_SUPPLY_PROP_MANUFACTURER,
1655 POWER_SUPPLY_PROP_SERIAL_NUMBER,
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001656 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */
1657 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */
Pedro Vanzellabe281362019-10-26 19:25:06 -03001658 0, /* placeholder for POWER_SUPPLY_PROP_VOLTAGE_NOW, */
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001659};
1660
1661static int hidpp_battery_get_property(struct power_supply *psy,
1662 enum power_supply_property psp,
1663 union power_supply_propval *val)
1664{
1665 struct hidpp_device *hidpp = power_supply_get_drvdata(psy);
1666 int ret = 0;
1667
1668 switch(psp) {
1669 case POWER_SUPPLY_PROP_STATUS:
1670 val->intval = hidpp->battery.status;
1671 break;
1672 case POWER_SUPPLY_PROP_CAPACITY:
Benjamin Tissoires14f437a2017-03-27 16:59:35 +02001673 val->intval = hidpp->battery.capacity;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001674 break;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02001675 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
1676 val->intval = hidpp->battery.level;
1677 break;
Bastien Nocera3861e6c2017-03-27 16:59:22 +02001678 case POWER_SUPPLY_PROP_SCOPE:
1679 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
1680 break;
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02001681 case POWER_SUPPLY_PROP_ONLINE:
1682 val->intval = hidpp->battery.online;
1683 break;
Benjamin Tissoires32043d02017-03-27 16:59:30 +02001684 case POWER_SUPPLY_PROP_MODEL_NAME:
1685 if (!strncmp(hidpp->name, "Logitech ", 9))
1686 val->strval = hidpp->name + 9;
1687 else
1688 val->strval = hidpp->name;
1689 break;
1690 case POWER_SUPPLY_PROP_MANUFACTURER:
1691 val->strval = "Logitech";
1692 break;
1693 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
1694 val->strval = hidpp->hid_dev->uniq;
1695 break;
Pedro Vanzellabe281362019-10-26 19:25:06 -03001696 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
1697 /* hardware reports voltage in in mV. sysfs expects uV */
1698 val->intval = hidpp->battery.voltage * 1000;
1699 break;
1700 case POWER_SUPPLY_PROP_CHARGE_TYPE:
1701 val->intval = hidpp->battery.charge_type;
1702 break;
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001703 default:
1704 ret = -EINVAL;
1705 break;
1706 }
1707
1708 return ret;
1709}
1710
Peter Hutterer5a2b1902016-06-29 19:28:01 +10001711/* -------------------------------------------------------------------------- */
Mazin Rezk0da0a63b2019-10-27 17:44:13 +00001712/* 0x1d4b: Wireless device status */
1713/* -------------------------------------------------------------------------- */
1714#define HIDPP_PAGE_WIRELESS_DEVICE_STATUS 0x1d4b
1715
1716static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
1717{
1718 u8 feature_type;
1719 int ret;
1720
1721 ret = hidpp_root_get_feature(hidpp,
1722 HIDPP_PAGE_WIRELESS_DEVICE_STATUS,
1723 &hidpp->wireless_feature_index,
1724 &feature_type);
1725
1726 return ret;
1727}
1728
1729/* -------------------------------------------------------------------------- */
Harry Cutts4435ff22018-12-05 10:42:27 +10001730/* 0x2120: Hi-resolution scrolling */
1731/* -------------------------------------------------------------------------- */
1732
1733#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120
1734
1735#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10
1736
1737static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp,
1738 bool enabled, u8 *multiplier)
1739{
1740 u8 feature_index;
1741 u8 feature_type;
1742 int ret;
1743 u8 params[1];
1744 struct hidpp_report response;
1745
1746 ret = hidpp_root_get_feature(hidpp,
1747 HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
1748 &feature_index,
1749 &feature_type);
1750 if (ret)
1751 return ret;
1752
1753 params[0] = enabled ? BIT(0) : 0;
1754 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1755 CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE,
1756 params, sizeof(params), &response);
1757 if (ret)
1758 return ret;
1759 *multiplier = response.fap.params[1];
1760 return 0;
1761}
1762
1763/* -------------------------------------------------------------------------- */
1764/* 0x2121: HiRes Wheel */
1765/* -------------------------------------------------------------------------- */
1766
1767#define HIDPP_PAGE_HIRES_WHEEL 0x2121
1768
1769#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00
1770#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20
1771
1772static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp,
1773 u8 *multiplier)
1774{
1775 u8 feature_index;
1776 u8 feature_type;
1777 int ret;
1778 struct hidpp_report response;
1779
1780 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
1781 &feature_index, &feature_type);
1782 if (ret)
1783 goto return_default;
1784
1785 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1786 CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY,
1787 NULL, 0, &response);
1788 if (ret)
1789 goto return_default;
1790
1791 *multiplier = response.fap.params[0];
1792 return 0;
1793return_default:
1794 hid_warn(hidpp->hid_dev,
1795 "Couldn't get wheel multiplier (error %d)\n", ret);
1796 return ret;
1797}
1798
1799static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert,
1800 bool high_resolution, bool use_hidpp)
1801{
1802 u8 feature_index;
1803 u8 feature_type;
1804 int ret;
1805 u8 params[1];
1806 struct hidpp_report response;
1807
1808 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
1809 &feature_index, &feature_type);
1810 if (ret)
1811 return ret;
1812
1813 params[0] = (invert ? BIT(2) : 0) |
1814 (high_resolution ? BIT(1) : 0) |
1815 (use_hidpp ? BIT(0) : 0);
1816
1817 return hidpp_send_fap_command_sync(hidpp, feature_index,
1818 CMD_HIRES_WHEEL_SET_WHEEL_MODE,
1819 params, sizeof(params), &response);
1820}
1821
1822/* -------------------------------------------------------------------------- */
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02001823/* 0x4301: Solar Keyboard */
1824/* -------------------------------------------------------------------------- */
1825
1826#define HIDPP_PAGE_SOLAR_KEYBOARD 0x4301
1827
1828#define CMD_SOLAR_SET_LIGHT_MEASURE 0x00
1829
1830#define EVENT_SOLAR_BATTERY_BROADCAST 0x00
1831#define EVENT_SOLAR_BATTERY_LIGHT_MEASURE 0x10
1832#define EVENT_SOLAR_CHECK_LIGHT_BUTTON 0x20
1833
1834static int hidpp_solar_request_battery_event(struct hidpp_device *hidpp)
1835{
1836 struct hidpp_report response;
1837 u8 params[2] = { 1, 1 };
1838 u8 feature_type;
1839 int ret;
1840
1841 if (hidpp->battery.feature_index == 0xff) {
1842 ret = hidpp_root_get_feature(hidpp,
1843 HIDPP_PAGE_SOLAR_KEYBOARD,
1844 &hidpp->battery.solar_feature_index,
1845 &feature_type);
1846 if (ret)
1847 return ret;
1848 }
1849
1850 ret = hidpp_send_fap_command_sync(hidpp,
1851 hidpp->battery.solar_feature_index,
1852 CMD_SOLAR_SET_LIGHT_MEASURE,
1853 params, 2, &response);
1854 if (ret > 0) {
1855 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1856 __func__, ret);
1857 return -EPROTO;
1858 }
1859 if (ret)
1860 return ret;
1861
1862 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
1863
1864 return 0;
1865}
1866
1867static int hidpp_solar_battery_event(struct hidpp_device *hidpp,
1868 u8 *data, int size)
1869{
1870 struct hidpp_report *report = (struct hidpp_report *)data;
1871 int capacity, lux, status;
1872 u8 function;
1873
1874 function = report->fap.funcindex_clientid;
1875
1876
1877 if (report->fap.feature_index != hidpp->battery.solar_feature_index ||
1878 !(function == EVENT_SOLAR_BATTERY_BROADCAST ||
1879 function == EVENT_SOLAR_BATTERY_LIGHT_MEASURE ||
1880 function == EVENT_SOLAR_CHECK_LIGHT_BUTTON))
1881 return 0;
1882
1883 capacity = report->fap.params[0];
1884
1885 switch (function) {
1886 case EVENT_SOLAR_BATTERY_LIGHT_MEASURE:
1887 lux = (report->fap.params[1] << 8) | report->fap.params[2];
1888 if (lux > 200)
1889 status = POWER_SUPPLY_STATUS_CHARGING;
1890 else
1891 status = POWER_SUPPLY_STATUS_DISCHARGING;
1892 break;
1893 case EVENT_SOLAR_CHECK_LIGHT_BUTTON:
1894 default:
1895 if (capacity < hidpp->battery.capacity)
1896 status = POWER_SUPPLY_STATUS_DISCHARGING;
1897 else
1898 status = POWER_SUPPLY_STATUS_CHARGING;
1899
1900 }
1901
1902 if (capacity == 100)
1903 status = POWER_SUPPLY_STATUS_FULL;
1904
1905 hidpp->battery.online = true;
1906 if (capacity != hidpp->battery.capacity ||
1907 status != hidpp->battery.status) {
1908 hidpp->battery.capacity = capacity;
1909 hidpp->battery.status = status;
1910 if (hidpp->battery.ps)
1911 power_supply_changed(hidpp->battery.ps);
1912 }
1913
1914 return 0;
1915}
1916
1917/* -------------------------------------------------------------------------- */
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04001918/* 0x6010: Touchpad FW items */
1919/* -------------------------------------------------------------------------- */
1920
1921#define HIDPP_PAGE_TOUCHPAD_FW_ITEMS 0x6010
1922
1923#define CMD_TOUCHPAD_FW_ITEMS_SET 0x10
1924
1925struct hidpp_touchpad_fw_items {
1926 uint8_t presence;
1927 uint8_t desired_state;
1928 uint8_t state;
1929 uint8_t persistent;
1930};
1931
Lee Jones3f37fdc2021-03-26 14:34:49 +00001932/*
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04001933 * send a set state command to the device by reading the current items->state
1934 * field. items is then filled with the current state.
1935 */
1936static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp,
1937 u8 feature_index,
1938 struct hidpp_touchpad_fw_items *items)
1939{
1940 struct hidpp_report response;
1941 int ret;
1942 u8 *params = (u8 *)response.fap.params;
1943
1944 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
1945 CMD_TOUCHPAD_FW_ITEMS_SET, &items->state, 1, &response);
1946
1947 if (ret > 0) {
1948 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
1949 __func__, ret);
1950 return -EPROTO;
1951 }
1952 if (ret)
1953 return ret;
1954
1955 items->presence = params[0];
1956 items->desired_state = params[1];
1957 items->state = params[2];
1958 items->persistent = params[3];
1959
1960 return 0;
1961}
1962
1963/* -------------------------------------------------------------------------- */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001964/* 0x6100: TouchPadRawXY */
1965/* -------------------------------------------------------------------------- */
1966
1967#define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100
1968
1969#define CMD_TOUCHPAD_GET_RAW_INFO 0x01
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04001970#define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x21
1971
1972#define EVENT_TOUCHPAD_RAW_XY 0x00
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04001973
1974#define TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT 0x01
1975#define TOUCHPAD_RAW_XY_ORIGIN_UPPER_LEFT 0x03
1976
1977struct hidpp_touchpad_raw_info {
1978 u16 x_size;
1979 u16 y_size;
1980 u8 z_range;
1981 u8 area_range;
1982 u8 timestamp_unit;
1983 u8 maxcontacts;
1984 u8 origin;
1985 u16 res;
1986};
1987
1988struct hidpp_touchpad_raw_xy_finger {
1989 u8 contact_type;
1990 u8 contact_status;
1991 u16 x;
1992 u16 y;
1993 u8 z;
1994 u8 area;
1995 u8 finger_id;
1996};
1997
1998struct hidpp_touchpad_raw_xy {
1999 u16 timestamp;
2000 struct hidpp_touchpad_raw_xy_finger fingers[2];
2001 u8 spurious_flag;
2002 u8 end_of_frame;
2003 u8 finger_count;
2004 u8 button;
2005};
2006
2007static int hidpp_touchpad_get_raw_info(struct hidpp_device *hidpp,
2008 u8 feature_index, struct hidpp_touchpad_raw_info *raw_info)
2009{
2010 struct hidpp_report response;
2011 int ret;
2012 u8 *params = (u8 *)response.fap.params;
2013
2014 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
2015 CMD_TOUCHPAD_GET_RAW_INFO, NULL, 0, &response);
2016
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -05002017 if (ret > 0) {
2018 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
2019 __func__, ret);
2020 return -EPROTO;
2021 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002022 if (ret)
Benjamin Tissoires8c9952b2014-11-03 16:09:58 -05002023 return ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002024
2025 raw_info->x_size = get_unaligned_be16(&params[0]);
2026 raw_info->y_size = get_unaligned_be16(&params[2]);
2027 raw_info->z_range = params[4];
2028 raw_info->area_range = params[5];
2029 raw_info->maxcontacts = params[7];
2030 raw_info->origin = params[8];
2031 /* res is given in unit per inch */
2032 raw_info->res = get_unaligned_be16(&params[13]) * 2 / 51;
2033
2034 return ret;
2035}
2036
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002037static int hidpp_touchpad_set_raw_report_state(struct hidpp_device *hidpp_dev,
2038 u8 feature_index, bool send_raw_reports,
2039 bool sensor_enhanced_settings)
2040{
2041 struct hidpp_report response;
2042
2043 /*
2044 * Params:
2045 * bit 0 - enable raw
2046 * bit 1 - 16bit Z, no area
2047 * bit 2 - enhanced sensitivity
2048 * bit 3 - width, height (4 bits each) instead of area
2049 * bit 4 - send raw + gestures (degrades smoothness)
2050 * remaining bits - reserved
2051 */
2052 u8 params = send_raw_reports | (sensor_enhanced_settings << 2);
2053
2054 return hidpp_send_fap_command_sync(hidpp_dev, feature_index,
2055 CMD_TOUCHPAD_SET_RAW_REPORT_STATE, &params, 1, &response);
2056}
2057
2058static void hidpp_touchpad_touch_event(u8 *data,
2059 struct hidpp_touchpad_raw_xy_finger *finger)
2060{
2061 u8 x_m = data[0] << 2;
2062 u8 y_m = data[2] << 2;
2063
2064 finger->x = x_m << 6 | data[1];
2065 finger->y = y_m << 6 | data[3];
2066
2067 finger->contact_type = data[0] >> 6;
2068 finger->contact_status = data[2] >> 6;
2069
2070 finger->z = data[4];
2071 finger->area = data[5];
2072 finger->finger_id = data[6] >> 4;
2073}
2074
2075static void hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev,
2076 u8 *data, struct hidpp_touchpad_raw_xy *raw_xy)
2077{
2078 memset(raw_xy, 0, sizeof(struct hidpp_touchpad_raw_xy));
2079 raw_xy->end_of_frame = data[8] & 0x01;
2080 raw_xy->spurious_flag = (data[8] >> 1) & 0x01;
2081 raw_xy->finger_count = data[15] & 0x0f;
2082 raw_xy->button = (data[8] >> 2) & 0x01;
2083
2084 if (raw_xy->finger_count) {
2085 hidpp_touchpad_touch_event(&data[2], &raw_xy->fingers[0]);
2086 hidpp_touchpad_touch_event(&data[9], &raw_xy->fingers[1]);
2087 }
2088}
2089
Edwin Veldsff21a632016-01-11 00:25:15 +01002090/* -------------------------------------------------------------------------- */
2091/* 0x8123: Force feedback support */
2092/* -------------------------------------------------------------------------- */
2093
2094#define HIDPP_FF_GET_INFO 0x01
2095#define HIDPP_FF_RESET_ALL 0x11
2096#define HIDPP_FF_DOWNLOAD_EFFECT 0x21
2097#define HIDPP_FF_SET_EFFECT_STATE 0x31
2098#define HIDPP_FF_DESTROY_EFFECT 0x41
2099#define HIDPP_FF_GET_APERTURE 0x51
2100#define HIDPP_FF_SET_APERTURE 0x61
2101#define HIDPP_FF_GET_GLOBAL_GAINS 0x71
2102#define HIDPP_FF_SET_GLOBAL_GAINS 0x81
2103
2104#define HIDPP_FF_EFFECT_STATE_GET 0x00
2105#define HIDPP_FF_EFFECT_STATE_STOP 0x01
2106#define HIDPP_FF_EFFECT_STATE_PLAY 0x02
2107#define HIDPP_FF_EFFECT_STATE_PAUSE 0x03
2108
2109#define HIDPP_FF_EFFECT_CONSTANT 0x00
2110#define HIDPP_FF_EFFECT_PERIODIC_SINE 0x01
2111#define HIDPP_FF_EFFECT_PERIODIC_SQUARE 0x02
2112#define HIDPP_FF_EFFECT_PERIODIC_TRIANGLE 0x03
2113#define HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHUP 0x04
2114#define HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHDOWN 0x05
2115#define HIDPP_FF_EFFECT_SPRING 0x06
2116#define HIDPP_FF_EFFECT_DAMPER 0x07
2117#define HIDPP_FF_EFFECT_FRICTION 0x08
2118#define HIDPP_FF_EFFECT_INERTIA 0x09
2119#define HIDPP_FF_EFFECT_RAMP 0x0A
2120
2121#define HIDPP_FF_EFFECT_AUTOSTART 0x80
2122
2123#define HIDPP_FF_EFFECTID_NONE -1
2124#define HIDPP_FF_EFFECTID_AUTOCENTER -2
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07002125#define HIDPP_AUTOCENTER_PARAMS_LENGTH 18
Edwin Veldsff21a632016-01-11 00:25:15 +01002126
2127#define HIDPP_FF_MAX_PARAMS 20
2128#define HIDPP_FF_RESERVED_SLOTS 1
2129
2130struct hidpp_ff_private_data {
2131 struct hidpp_device *hidpp;
2132 u8 feature_index;
2133 u8 version;
2134 u16 gain;
2135 s16 range;
2136 u8 slot_autocenter;
2137 u8 num_effects;
2138 int *effect_ids;
2139 struct workqueue_struct *wq;
2140 atomic_t workqueue_size;
2141};
2142
2143struct hidpp_ff_work_data {
2144 struct work_struct work;
2145 struct hidpp_ff_private_data *data;
2146 int effect_id;
2147 u8 command;
2148 u8 params[HIDPP_FF_MAX_PARAMS];
2149 u8 size;
2150};
2151
Peter Huttererfef33602018-12-05 10:42:25 +10002152static const signed short hidpp_ff_effects[] = {
Edwin Veldsff21a632016-01-11 00:25:15 +01002153 FF_CONSTANT,
2154 FF_PERIODIC,
2155 FF_SINE,
2156 FF_SQUARE,
2157 FF_SAW_UP,
2158 FF_SAW_DOWN,
2159 FF_TRIANGLE,
2160 FF_SPRING,
2161 FF_DAMPER,
2162 FF_AUTOCENTER,
2163 FF_GAIN,
2164 -1
2165};
2166
Peter Huttererfef33602018-12-05 10:42:25 +10002167static const signed short hidpp_ff_effects_v2[] = {
Edwin Veldsff21a632016-01-11 00:25:15 +01002168 FF_RAMP,
2169 FF_FRICTION,
2170 FF_INERTIA,
2171 -1
2172};
2173
2174static const u8 HIDPP_FF_CONDITION_CMDS[] = {
2175 HIDPP_FF_EFFECT_SPRING,
2176 HIDPP_FF_EFFECT_FRICTION,
2177 HIDPP_FF_EFFECT_DAMPER,
2178 HIDPP_FF_EFFECT_INERTIA
2179};
2180
2181static const char *HIDPP_FF_CONDITION_NAMES[] = {
2182 "spring",
2183 "friction",
2184 "damper",
2185 "inertia"
2186};
2187
2188
2189static u8 hidpp_ff_find_effect(struct hidpp_ff_private_data *data, int effect_id)
2190{
2191 int i;
2192
2193 for (i = 0; i < data->num_effects; i++)
2194 if (data->effect_ids[i] == effect_id)
2195 return i+1;
2196
2197 return 0;
2198}
2199
2200static void hidpp_ff_work_handler(struct work_struct *w)
2201{
2202 struct hidpp_ff_work_data *wd = container_of(w, struct hidpp_ff_work_data, work);
2203 struct hidpp_ff_private_data *data = wd->data;
2204 struct hidpp_report response;
2205 u8 slot;
2206 int ret;
2207
2208 /* add slot number if needed */
2209 switch (wd->effect_id) {
2210 case HIDPP_FF_EFFECTID_AUTOCENTER:
2211 wd->params[0] = data->slot_autocenter;
2212 break;
2213 case HIDPP_FF_EFFECTID_NONE:
2214 /* leave slot as zero */
2215 break;
2216 default:
2217 /* find current slot for effect */
2218 wd->params[0] = hidpp_ff_find_effect(data, wd->effect_id);
2219 break;
2220 }
2221
2222 /* send command and wait for reply */
2223 ret = hidpp_send_fap_command_sync(data->hidpp, data->feature_index,
2224 wd->command, wd->params, wd->size, &response);
2225
2226 if (ret) {
2227 hid_err(data->hidpp->hid_dev, "Failed to send command to device!\n");
2228 goto out;
2229 }
2230
2231 /* parse return data */
2232 switch (wd->command) {
2233 case HIDPP_FF_DOWNLOAD_EFFECT:
2234 slot = response.fap.params[0];
2235 if (slot > 0 && slot <= data->num_effects) {
2236 if (wd->effect_id >= 0)
2237 /* regular effect uploaded */
2238 data->effect_ids[slot-1] = wd->effect_id;
2239 else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER)
2240 /* autocenter spring uploaded */
2241 data->slot_autocenter = slot;
2242 }
2243 break;
2244 case HIDPP_FF_DESTROY_EFFECT:
2245 if (wd->effect_id >= 0)
2246 /* regular effect destroyed */
2247 data->effect_ids[wd->params[0]-1] = -1;
2248 else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER)
2249 /* autocenter spring destoyed */
2250 data->slot_autocenter = 0;
2251 break;
2252 case HIDPP_FF_SET_GLOBAL_GAINS:
2253 data->gain = (wd->params[0] << 8) + wd->params[1];
2254 break;
2255 case HIDPP_FF_SET_APERTURE:
2256 data->range = (wd->params[0] << 8) + wd->params[1];
2257 break;
2258 default:
2259 /* no action needed */
2260 break;
2261 }
2262
2263out:
2264 atomic_dec(&data->workqueue_size);
2265 kfree(wd);
2266}
2267
2268static int hidpp_ff_queue_work(struct hidpp_ff_private_data *data, int effect_id, u8 command, u8 *params, u8 size)
2269{
2270 struct hidpp_ff_work_data *wd = kzalloc(sizeof(*wd), GFP_KERNEL);
2271 int s;
2272
2273 if (!wd)
2274 return -ENOMEM;
2275
2276 INIT_WORK(&wd->work, hidpp_ff_work_handler);
2277
2278 wd->data = data;
2279 wd->effect_id = effect_id;
2280 wd->command = command;
2281 wd->size = size;
2282 memcpy(wd->params, params, size);
2283
Christophe JAILLET46dcd1c2021-07-23 17:41:52 +02002284 s = atomic_inc_return(&data->workqueue_size);
Edwin Veldsff21a632016-01-11 00:25:15 +01002285 queue_work(data->wq, &wd->work);
2286
2287 /* warn about excessive queue size */
Edwin Veldsff21a632016-01-11 00:25:15 +01002288 if (s >= 20 && s % 20 == 0)
2289 hid_warn(data->hidpp->hid_dev, "Force feedback command queue contains %d commands, causing substantial delays!", s);
2290
2291 return 0;
2292}
2293
2294static int hidpp_ff_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
2295{
2296 struct hidpp_ff_private_data *data = dev->ff->private;
2297 u8 params[20];
2298 u8 size;
2299 int force;
2300
2301 /* set common parameters */
2302 params[2] = effect->replay.length >> 8;
2303 params[3] = effect->replay.length & 255;
2304 params[4] = effect->replay.delay >> 8;
2305 params[5] = effect->replay.delay & 255;
2306
2307 switch (effect->type) {
2308 case FF_CONSTANT:
2309 force = (effect->u.constant.level * fixp_sin16((effect->direction * 360) >> 16)) >> 15;
2310 params[1] = HIDPP_FF_EFFECT_CONSTANT;
2311 params[6] = force >> 8;
2312 params[7] = force & 255;
2313 params[8] = effect->u.constant.envelope.attack_level >> 7;
2314 params[9] = effect->u.constant.envelope.attack_length >> 8;
2315 params[10] = effect->u.constant.envelope.attack_length & 255;
2316 params[11] = effect->u.constant.envelope.fade_level >> 7;
2317 params[12] = effect->u.constant.envelope.fade_length >> 8;
2318 params[13] = effect->u.constant.envelope.fade_length & 255;
2319 size = 14;
2320 dbg_hid("Uploading constant force level=%d in dir %d = %d\n",
2321 effect->u.constant.level,
2322 effect->direction, force);
2323 dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n",
2324 effect->u.constant.envelope.attack_level,
2325 effect->u.constant.envelope.attack_length,
2326 effect->u.constant.envelope.fade_level,
2327 effect->u.constant.envelope.fade_length);
2328 break;
2329 case FF_PERIODIC:
2330 {
2331 switch (effect->u.periodic.waveform) {
2332 case FF_SINE:
2333 params[1] = HIDPP_FF_EFFECT_PERIODIC_SINE;
2334 break;
2335 case FF_SQUARE:
2336 params[1] = HIDPP_FF_EFFECT_PERIODIC_SQUARE;
2337 break;
2338 case FF_SAW_UP:
2339 params[1] = HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHUP;
2340 break;
2341 case FF_SAW_DOWN:
2342 params[1] = HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHDOWN;
2343 break;
2344 case FF_TRIANGLE:
2345 params[1] = HIDPP_FF_EFFECT_PERIODIC_TRIANGLE;
2346 break;
2347 default:
2348 hid_err(data->hidpp->hid_dev, "Unexpected periodic waveform type %i!\n", effect->u.periodic.waveform);
2349 return -EINVAL;
2350 }
2351 force = (effect->u.periodic.magnitude * fixp_sin16((effect->direction * 360) >> 16)) >> 15;
2352 params[6] = effect->u.periodic.magnitude >> 8;
2353 params[7] = effect->u.periodic.magnitude & 255;
2354 params[8] = effect->u.periodic.offset >> 8;
2355 params[9] = effect->u.periodic.offset & 255;
2356 params[10] = effect->u.periodic.period >> 8;
2357 params[11] = effect->u.periodic.period & 255;
2358 params[12] = effect->u.periodic.phase >> 8;
2359 params[13] = effect->u.periodic.phase & 255;
2360 params[14] = effect->u.periodic.envelope.attack_level >> 7;
2361 params[15] = effect->u.periodic.envelope.attack_length >> 8;
2362 params[16] = effect->u.periodic.envelope.attack_length & 255;
2363 params[17] = effect->u.periodic.envelope.fade_level >> 7;
2364 params[18] = effect->u.periodic.envelope.fade_length >> 8;
2365 params[19] = effect->u.periodic.envelope.fade_length & 255;
2366 size = 20;
2367 dbg_hid("Uploading periodic force mag=%d/dir=%d, offset=%d, period=%d ms, phase=%d\n",
2368 effect->u.periodic.magnitude, effect->direction,
2369 effect->u.periodic.offset,
2370 effect->u.periodic.period,
2371 effect->u.periodic.phase);
2372 dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n",
2373 effect->u.periodic.envelope.attack_level,
2374 effect->u.periodic.envelope.attack_length,
2375 effect->u.periodic.envelope.fade_level,
2376 effect->u.periodic.envelope.fade_length);
2377 break;
2378 }
2379 case FF_RAMP:
2380 params[1] = HIDPP_FF_EFFECT_RAMP;
2381 force = (effect->u.ramp.start_level * fixp_sin16((effect->direction * 360) >> 16)) >> 15;
2382 params[6] = force >> 8;
2383 params[7] = force & 255;
2384 force = (effect->u.ramp.end_level * fixp_sin16((effect->direction * 360) >> 16)) >> 15;
2385 params[8] = force >> 8;
2386 params[9] = force & 255;
2387 params[10] = effect->u.ramp.envelope.attack_level >> 7;
2388 params[11] = effect->u.ramp.envelope.attack_length >> 8;
2389 params[12] = effect->u.ramp.envelope.attack_length & 255;
2390 params[13] = effect->u.ramp.envelope.fade_level >> 7;
2391 params[14] = effect->u.ramp.envelope.fade_length >> 8;
2392 params[15] = effect->u.ramp.envelope.fade_length & 255;
2393 size = 16;
2394 dbg_hid("Uploading ramp force level=%d -> %d in dir %d = %d\n",
2395 effect->u.ramp.start_level,
2396 effect->u.ramp.end_level,
2397 effect->direction, force);
2398 dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n",
2399 effect->u.ramp.envelope.attack_level,
2400 effect->u.ramp.envelope.attack_length,
2401 effect->u.ramp.envelope.fade_level,
2402 effect->u.ramp.envelope.fade_length);
2403 break;
2404 case FF_FRICTION:
2405 case FF_INERTIA:
2406 case FF_SPRING:
2407 case FF_DAMPER:
2408 params[1] = HIDPP_FF_CONDITION_CMDS[effect->type - FF_SPRING];
2409 params[6] = effect->u.condition[0].left_saturation >> 9;
2410 params[7] = (effect->u.condition[0].left_saturation >> 1) & 255;
2411 params[8] = effect->u.condition[0].left_coeff >> 8;
2412 params[9] = effect->u.condition[0].left_coeff & 255;
2413 params[10] = effect->u.condition[0].deadband >> 9;
2414 params[11] = (effect->u.condition[0].deadband >> 1) & 255;
2415 params[12] = effect->u.condition[0].center >> 8;
2416 params[13] = effect->u.condition[0].center & 255;
2417 params[14] = effect->u.condition[0].right_coeff >> 8;
2418 params[15] = effect->u.condition[0].right_coeff & 255;
2419 params[16] = effect->u.condition[0].right_saturation >> 9;
2420 params[17] = (effect->u.condition[0].right_saturation >> 1) & 255;
2421 size = 18;
2422 dbg_hid("Uploading %s force left coeff=%d, left sat=%d, right coeff=%d, right sat=%d\n",
2423 HIDPP_FF_CONDITION_NAMES[effect->type - FF_SPRING],
2424 effect->u.condition[0].left_coeff,
2425 effect->u.condition[0].left_saturation,
2426 effect->u.condition[0].right_coeff,
2427 effect->u.condition[0].right_saturation);
2428 dbg_hid(" deadband=%d, center=%d\n",
2429 effect->u.condition[0].deadband,
2430 effect->u.condition[0].center);
2431 break;
2432 default:
2433 hid_err(data->hidpp->hid_dev, "Unexpected force type %i!\n", effect->type);
2434 return -EINVAL;
2435 }
2436
2437 return hidpp_ff_queue_work(data, effect->id, HIDPP_FF_DOWNLOAD_EFFECT, params, size);
2438}
2439
2440static int hidpp_ff_playback(struct input_dev *dev, int effect_id, int value)
2441{
2442 struct hidpp_ff_private_data *data = dev->ff->private;
2443 u8 params[2];
2444
2445 params[1] = value ? HIDPP_FF_EFFECT_STATE_PLAY : HIDPP_FF_EFFECT_STATE_STOP;
2446
2447 dbg_hid("St%sing playback of effect %d.\n", value?"art":"opp", effect_id);
2448
2449 return hidpp_ff_queue_work(data, effect_id, HIDPP_FF_SET_EFFECT_STATE, params, ARRAY_SIZE(params));
2450}
2451
2452static int hidpp_ff_erase_effect(struct input_dev *dev, int effect_id)
2453{
2454 struct hidpp_ff_private_data *data = dev->ff->private;
2455 u8 slot = 0;
2456
2457 dbg_hid("Erasing effect %d.\n", effect_id);
2458
2459 return hidpp_ff_queue_work(data, effect_id, HIDPP_FF_DESTROY_EFFECT, &slot, 1);
2460}
2461
2462static void hidpp_ff_set_autocenter(struct input_dev *dev, u16 magnitude)
2463{
2464 struct hidpp_ff_private_data *data = dev->ff->private;
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07002465 u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH];
Edwin Veldsff21a632016-01-11 00:25:15 +01002466
2467 dbg_hid("Setting autocenter to %d.\n", magnitude);
2468
2469 /* start a standard spring effect */
2470 params[1] = HIDPP_FF_EFFECT_SPRING | HIDPP_FF_EFFECT_AUTOSTART;
2471 /* zero delay and duration */
2472 params[2] = params[3] = params[4] = params[5] = 0;
2473 /* set coeff to 25% of saturation */
2474 params[8] = params[14] = magnitude >> 11;
2475 params[9] = params[15] = (magnitude >> 3) & 255;
2476 params[6] = params[16] = magnitude >> 9;
2477 params[7] = params[17] = (magnitude >> 1) & 255;
2478 /* zero deadband and center */
2479 params[10] = params[11] = params[12] = params[13] = 0;
2480
2481 hidpp_ff_queue_work(data, HIDPP_FF_EFFECTID_AUTOCENTER, HIDPP_FF_DOWNLOAD_EFFECT, params, ARRAY_SIZE(params));
2482}
2483
2484static void hidpp_ff_set_gain(struct input_dev *dev, u16 gain)
2485{
2486 struct hidpp_ff_private_data *data = dev->ff->private;
2487 u8 params[4];
2488
2489 dbg_hid("Setting gain to %d.\n", gain);
2490
2491 params[0] = gain >> 8;
2492 params[1] = gain & 255;
2493 params[2] = 0; /* no boost */
2494 params[3] = 0;
2495
2496 hidpp_ff_queue_work(data, HIDPP_FF_EFFECTID_NONE, HIDPP_FF_SET_GLOBAL_GAINS, params, ARRAY_SIZE(params));
2497}
2498
2499static ssize_t hidpp_ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
2500{
2501 struct hid_device *hid = to_hid_device(dev);
2502 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
2503 struct input_dev *idev = hidinput->input;
2504 struct hidpp_ff_private_data *data = idev->ff->private;
2505
2506 return scnprintf(buf, PAGE_SIZE, "%u\n", data->range);
2507}
2508
2509static ssize_t hidpp_ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
2510{
2511 struct hid_device *hid = to_hid_device(dev);
2512 struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
2513 struct input_dev *idev = hidinput->input;
2514 struct hidpp_ff_private_data *data = idev->ff->private;
2515 u8 params[2];
2516 int range = simple_strtoul(buf, NULL, 10);
2517
2518 range = clamp(range, 180, 900);
2519
2520 params[0] = range >> 8;
2521 params[1] = range & 0x00FF;
2522
2523 hidpp_ff_queue_work(data, -1, HIDPP_FF_SET_APERTURE, params, ARRAY_SIZE(params));
2524
2525 return count;
2526}
2527
2528static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, hidpp_ff_range_show, hidpp_ff_range_store);
2529
2530static void hidpp_ff_destroy(struct ff_device *ff)
2531{
2532 struct hidpp_ff_private_data *data = ff->private;
Andrey Smirnov08c453f2019-10-17 21:45:17 -07002533 struct hid_device *hid = data->hidpp->hid_dev;
Edwin Veldsff21a632016-01-11 00:25:15 +01002534
Andrey Smirnov08c453f2019-10-17 21:45:17 -07002535 hid_info(hid, "Unloading HID++ force feedback.\n");
2536
2537 device_remove_file(&hid->dev, &dev_attr_range);
2538 destroy_workqueue(data->wq);
Edwin Veldsff21a632016-01-11 00:25:15 +01002539 kfree(data->effect_ids);
2540}
2541
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07002542static int hidpp_ff_init(struct hidpp_device *hidpp,
2543 struct hidpp_ff_private_data *data)
Edwin Veldsff21a632016-01-11 00:25:15 +01002544{
2545 struct hid_device *hid = hidpp->hid_dev;
Alan Sternd9d4b1e2019-10-03 14:53:59 -04002546 struct hid_input *hidinput;
2547 struct input_dev *dev;
Edwin Veldsff21a632016-01-11 00:25:15 +01002548 const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor);
2549 const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice);
2550 struct ff_device *ff;
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07002551 int error, j, num_slots = data->num_effects;
Edwin Veldsff21a632016-01-11 00:25:15 +01002552 u8 version;
2553
Alan Sternd9d4b1e2019-10-03 14:53:59 -04002554 if (list_empty(&hid->inputs)) {
2555 hid_err(hid, "no inputs found\n");
2556 return -ENODEV;
2557 }
2558 hidinput = list_entry(hid->inputs.next, struct hid_input, list);
2559 dev = hidinput->input;
2560
Edwin Veldsff21a632016-01-11 00:25:15 +01002561 if (!dev) {
2562 hid_err(hid, "Struct input_dev not set!\n");
2563 return -EINVAL;
2564 }
2565
2566 /* Get firmware release */
2567 version = bcdDevice & 255;
2568
2569 /* Set supported force feedback capabilities */
Peter Huttererfef33602018-12-05 10:42:25 +10002570 for (j = 0; hidpp_ff_effects[j] >= 0; j++)
2571 set_bit(hidpp_ff_effects[j], dev->ffbit);
Edwin Veldsff21a632016-01-11 00:25:15 +01002572 if (version > 1)
Peter Huttererfef33602018-12-05 10:42:25 +10002573 for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++)
2574 set_bit(hidpp_ff_effects_v2[j], dev->ffbit);
Edwin Veldsff21a632016-01-11 00:25:15 +01002575
Edwin Veldsff21a632016-01-11 00:25:15 +01002576 error = input_ff_create(dev, num_slots);
2577
2578 if (error) {
2579 hid_err(dev, "Failed to create FF device!\n");
2580 return error;
2581 }
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07002582 /*
2583 * Create a copy of passed data, so we can transfer memory
2584 * ownership to FF core
2585 */
2586 data = kmemdup(data, sizeof(*data), GFP_KERNEL);
Edwin Veldsff21a632016-01-11 00:25:15 +01002587 if (!data)
2588 return -ENOMEM;
2589 data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL);
2590 if (!data->effect_ids) {
2591 kfree(data);
2592 return -ENOMEM;
2593 }
Kangjie Lu6c44b152019-03-14 00:24:02 -05002594 data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue");
2595 if (!data->wq) {
2596 kfree(data->effect_ids);
2597 kfree(data);
2598 return -ENOMEM;
2599 }
2600
Edwin Veldsff21a632016-01-11 00:25:15 +01002601 data->hidpp = hidpp;
Edwin Veldsff21a632016-01-11 00:25:15 +01002602 data->version = version;
Edwin Veldsff21a632016-01-11 00:25:15 +01002603 for (j = 0; j < num_slots; j++)
2604 data->effect_ids[j] = -1;
2605
2606 ff = dev->ff;
2607 ff->private = data;
2608
2609 ff->upload = hidpp_ff_upload_effect;
2610 ff->erase = hidpp_ff_erase_effect;
2611 ff->playback = hidpp_ff_playback;
2612 ff->set_gain = hidpp_ff_set_gain;
2613 ff->set_autocenter = hidpp_ff_set_autocenter;
2614 ff->destroy = hidpp_ff_destroy;
2615
Edwin Veldsff21a632016-01-11 00:25:15 +01002616 /* Create sysfs interface */
2617 error = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
2618 if (error)
2619 hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d!\n", error);
2620
Edwin Veldsff21a632016-01-11 00:25:15 +01002621 /* init the hardware command queue */
Edwin Veldsff21a632016-01-11 00:25:15 +01002622 atomic_set(&data->workqueue_size, 0);
2623
Colin Ian Kingdf47b242017-07-14 14:37:12 +01002624 hid_info(hid, "Force feedback support loaded (firmware release %d).\n",
2625 version);
Edwin Veldsff21a632016-01-11 00:25:15 +01002626
2627 return 0;
2628}
2629
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002630/* ************************************************************************** */
2631/* */
2632/* Device Support */
2633/* */
2634/* ************************************************************************** */
2635
2636/* -------------------------------------------------------------------------- */
2637/* Touchpad HID++ devices */
2638/* -------------------------------------------------------------------------- */
2639
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002640#define WTP_MANUAL_RESOLUTION 39
2641
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002642struct wtp_data {
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002643 u16 x_size, y_size;
2644 u8 finger_count;
2645 u8 mt_feature_index;
2646 u8 button_feature_index;
2647 u8 maxcontacts;
2648 bool flip_y;
2649 unsigned int resolution;
2650};
2651
2652static int wtp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
2653 struct hid_field *field, struct hid_usage *usage,
2654 unsigned long **bit, int *max)
2655{
2656 return -1;
2657}
2658
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04002659static void wtp_populate_input(struct hidpp_device *hidpp,
Hans de Goedee54abaf2019-04-20 13:22:09 +02002660 struct input_dev *input_dev)
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002661{
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002662 struct wtp_data *wd = hidpp->private_data;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002663
2664 __set_bit(EV_ABS, input_dev->evbit);
2665 __set_bit(EV_KEY, input_dev->evbit);
2666 __clear_bit(EV_REL, input_dev->evbit);
2667 __clear_bit(EV_LED, input_dev->evbit);
2668
2669 input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, wd->x_size, 0, 0);
2670 input_abs_set_res(input_dev, ABS_MT_POSITION_X, wd->resolution);
2671 input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, wd->y_size, 0, 0);
2672 input_abs_set_res(input_dev, ABS_MT_POSITION_Y, wd->resolution);
2673
2674 /* Max pressure is not given by the devices, pick one */
2675 input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 50, 0, 0);
2676
2677 input_set_capability(input_dev, EV_KEY, BTN_LEFT);
2678
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002679 if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS)
2680 input_set_capability(input_dev, EV_KEY, BTN_RIGHT);
2681 else
2682 __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002683
2684 input_mt_init_slots(input_dev, wd->maxcontacts, INPUT_MT_POINTER |
2685 INPUT_MT_DROP_UNUSED);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002686}
2687
Hans de Goede06104302019-04-20 13:22:13 +02002688static void wtp_touch_event(struct hidpp_device *hidpp,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002689 struct hidpp_touchpad_raw_xy_finger *touch_report)
2690{
Hans de Goede06104302019-04-20 13:22:13 +02002691 struct wtp_data *wd = hidpp->private_data;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002692 int slot;
2693
2694 if (!touch_report->finger_id || touch_report->contact_type)
2695 /* no actual data */
2696 return;
2697
Hans de Goede06104302019-04-20 13:22:13 +02002698 slot = input_mt_get_slot_by_key(hidpp->input, touch_report->finger_id);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002699
Hans de Goede06104302019-04-20 13:22:13 +02002700 input_mt_slot(hidpp->input, slot);
2701 input_mt_report_slot_state(hidpp->input, MT_TOOL_FINGER,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002702 touch_report->contact_status);
2703 if (touch_report->contact_status) {
Hans de Goede06104302019-04-20 13:22:13 +02002704 input_event(hidpp->input, EV_ABS, ABS_MT_POSITION_X,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002705 touch_report->x);
Hans de Goede06104302019-04-20 13:22:13 +02002706 input_event(hidpp->input, EV_ABS, ABS_MT_POSITION_Y,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002707 wd->flip_y ? wd->y_size - touch_report->y :
2708 touch_report->y);
Hans de Goede06104302019-04-20 13:22:13 +02002709 input_event(hidpp->input, EV_ABS, ABS_MT_PRESSURE,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002710 touch_report->area);
2711 }
2712}
2713
2714static void wtp_send_raw_xy_event(struct hidpp_device *hidpp,
2715 struct hidpp_touchpad_raw_xy *raw)
2716{
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002717 int i;
2718
2719 for (i = 0; i < 2; i++)
Hans de Goede06104302019-04-20 13:22:13 +02002720 wtp_touch_event(hidpp, &(raw->fingers[i]));
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002721
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002722 if (raw->end_of_frame &&
2723 !(hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS))
Hans de Goede06104302019-04-20 13:22:13 +02002724 input_event(hidpp->input, EV_KEY, BTN_LEFT, raw->button);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002725
2726 if (raw->end_of_frame || raw->finger_count <= 2) {
Hans de Goede06104302019-04-20 13:22:13 +02002727 input_mt_sync_frame(hidpp->input);
2728 input_sync(hidpp->input);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002729 }
2730}
2731
2732static int wtp_mouse_raw_xy_event(struct hidpp_device *hidpp, u8 *data)
2733{
2734 struct wtp_data *wd = hidpp->private_data;
2735 u8 c1_area = ((data[7] & 0xf) * (data[7] & 0xf) +
2736 (data[7] >> 4) * (data[7] >> 4)) / 2;
2737 u8 c2_area = ((data[13] & 0xf) * (data[13] & 0xf) +
2738 (data[13] >> 4) * (data[13] >> 4)) / 2;
2739 struct hidpp_touchpad_raw_xy raw = {
2740 .timestamp = data[1],
2741 .fingers = {
2742 {
2743 .contact_type = 0,
2744 .contact_status = !!data[7],
2745 .x = get_unaligned_le16(&data[3]),
2746 .y = get_unaligned_le16(&data[5]),
2747 .z = c1_area,
2748 .area = c1_area,
2749 .finger_id = data[2],
2750 }, {
2751 .contact_type = 0,
2752 .contact_status = !!data[13],
2753 .x = get_unaligned_le16(&data[9]),
2754 .y = get_unaligned_le16(&data[11]),
2755 .z = c2_area,
2756 .area = c2_area,
2757 .finger_id = data[8],
2758 }
2759 },
2760 .finger_count = wd->maxcontacts,
2761 .spurious_flag = 0,
2762 .end_of_frame = (data[0] >> 7) == 0,
2763 .button = data[0] & 0x01,
2764 };
2765
2766 wtp_send_raw_xy_event(hidpp, &raw);
2767
2768 return 1;
2769}
2770
2771static int wtp_raw_event(struct hid_device *hdev, u8 *data, int size)
2772{
2773 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
2774 struct wtp_data *wd = hidpp->private_data;
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002775 struct hidpp_report *report = (struct hidpp_report *)data;
2776 struct hidpp_touchpad_raw_xy raw;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002777
Hans de Goede06104302019-04-20 13:22:13 +02002778 if (!wd || !hidpp->input)
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002779 return 1;
2780
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002781 switch (data[0]) {
2782 case 0x02:
Peter Wu0b3f6562014-12-16 16:55:22 +01002783 if (size < 2) {
2784 hid_err(hdev, "Received HID report of bad size (%d)",
2785 size);
2786 return 1;
2787 }
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002788 if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS) {
Hans de Goede06104302019-04-20 13:22:13 +02002789 input_event(hidpp->input, EV_KEY, BTN_LEFT,
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002790 !!(data[1] & 0x01));
Hans de Goede06104302019-04-20 13:22:13 +02002791 input_event(hidpp->input, EV_KEY, BTN_RIGHT,
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002792 !!(data[1] & 0x02));
Hans de Goede06104302019-04-20 13:22:13 +02002793 input_sync(hidpp->input);
Peter Wu8abd8202014-12-16 01:50:16 +01002794 return 0;
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002795 } else {
2796 if (size < 21)
2797 return 1;
2798 return wtp_mouse_raw_xy_event(hidpp, &data[7]);
2799 }
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002800 case REPORT_ID_HIDPP_LONG:
Peter Wu0b3f6562014-12-16 16:55:22 +01002801 /* size is already checked in hidpp_raw_event. */
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002802 if ((report->fap.feature_index != wd->mt_feature_index) ||
2803 (report->fap.funcindex_clientid != EVENT_TOUCHPAD_RAW_XY))
2804 return 1;
2805 hidpp_touchpad_raw_xy_event(hidpp, data + 4, &raw);
2806
2807 wtp_send_raw_xy_event(hidpp, &raw);
2808 return 0;
2809 }
2810
2811 return 0;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002812}
2813
2814static int wtp_get_config(struct hidpp_device *hidpp)
2815{
2816 struct wtp_data *wd = hidpp->private_data;
2817 struct hidpp_touchpad_raw_info raw_info = {0};
2818 u8 feature_type;
2819 int ret;
2820
2821 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_TOUCHPAD_RAW_XY,
2822 &wd->mt_feature_index, &feature_type);
2823 if (ret)
2824 /* means that the device is not powered up */
2825 return ret;
2826
2827 ret = hidpp_touchpad_get_raw_info(hidpp, wd->mt_feature_index,
2828 &raw_info);
2829 if (ret)
2830 return ret;
2831
2832 wd->x_size = raw_info.x_size;
2833 wd->y_size = raw_info.y_size;
2834 wd->maxcontacts = raw_info.maxcontacts;
2835 wd->flip_y = raw_info.origin == TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT;
2836 wd->resolution = raw_info.res;
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04002837 if (!wd->resolution)
2838 wd->resolution = WTP_MANUAL_RESOLUTION;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04002839
2840 return 0;
2841}
2842
2843static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
2844{
2845 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
2846 struct wtp_data *wd;
2847
2848 wd = devm_kzalloc(&hdev->dev, sizeof(struct wtp_data),
2849 GFP_KERNEL);
2850 if (!wd)
2851 return -ENOMEM;
2852
2853 hidpp->private_data = wd;
2854
2855 return 0;
2856};
2857
Benjamin Tissoiresbf159442014-12-16 17:06:01 -05002858static int wtp_connect(struct hid_device *hdev, bool connected)
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002859{
2860 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
2861 struct wtp_data *wd = hidpp->private_data;
2862 int ret;
2863
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002864 if (!wd->x_size) {
2865 ret = wtp_get_config(hidpp);
2866 if (ret) {
2867 hid_err(hdev, "Can not get wtp config: %d\n", ret);
Benjamin Tissoiresbf159442014-12-16 17:06:01 -05002868 return ret;
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002869 }
2870 }
2871
Benjamin Tissoiresbf159442014-12-16 17:06:01 -05002872 return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index,
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04002873 true, true);
2874}
2875
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002876/* ------------------------------------------------------------------------- */
2877/* Logitech M560 devices */
2878/* ------------------------------------------------------------------------- */
2879
2880/*
2881 * Logitech M560 protocol overview
2882 *
2883 * The Logitech M560 mouse, is designed for windows 8. When the middle and/or
2884 * the sides buttons are pressed, it sends some keyboard keys events
2885 * instead of buttons ones.
2886 * To complicate things further, the middle button keys sequence
2887 * is different from the odd press and the even press.
2888 *
2889 * forward button -> Super_R
2890 * backward button -> Super_L+'d' (press only)
2891 * middle button -> 1st time: Alt_L+SuperL+XF86TouchpadOff (press only)
2892 * 2nd time: left-click (press only)
2893 * NB: press-only means that when the button is pressed, the
2894 * KeyPress/ButtonPress and KeyRelease/ButtonRelease events are generated
2895 * together sequentially; instead when the button is released, no event is
2896 * generated !
2897 *
2898 * With the command
2899 * 10<xx>0a 3500af03 (where <xx> is the mouse id),
2900 * the mouse reacts differently:
2901 * - it never sends a keyboard key event
2902 * - for the three mouse button it sends:
2903 * middle button press 11<xx>0a 3500af00...
2904 * side 1 button (forward) press 11<xx>0a 3500b000...
2905 * side 2 button (backward) press 11<xx>0a 3500ae00...
2906 * middle/side1/side2 button release 11<xx>0a 35000000...
2907 */
2908
2909static const u8 m560_config_parameter[] = {0x00, 0xaf, 0x03};
2910
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002911/* how buttons are mapped in the report */
2912#define M560_MOUSE_BTN_LEFT 0x01
2913#define M560_MOUSE_BTN_RIGHT 0x02
2914#define M560_MOUSE_BTN_WHEEL_LEFT 0x08
2915#define M560_MOUSE_BTN_WHEEL_RIGHT 0x10
2916
2917#define M560_SUB_ID 0x0a
2918#define M560_BUTTON_MODE_REGISTER 0x35
2919
2920static int m560_send_config_command(struct hid_device *hdev, bool connected)
2921{
2922 struct hidpp_report response;
2923 struct hidpp_device *hidpp_dev;
2924
2925 hidpp_dev = hid_get_drvdata(hdev);
2926
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002927 return hidpp_send_rap_command_sync(
2928 hidpp_dev,
2929 REPORT_ID_HIDPP_SHORT,
2930 M560_SUB_ID,
2931 M560_BUTTON_MODE_REGISTER,
2932 (u8 *)m560_config_parameter,
2933 sizeof(m560_config_parameter),
2934 &response
2935 );
2936}
2937
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002938static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
2939{
2940 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002941
2942 /* sanity check */
Hans de Goede06104302019-04-20 13:22:13 +02002943 if (!hidpp->input) {
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002944 hid_err(hdev, "error in parameter\n");
2945 return -EINVAL;
2946 }
2947
2948 if (size < 7) {
2949 hid_err(hdev, "error in report\n");
2950 return 0;
2951 }
2952
2953 if (data[0] == REPORT_ID_HIDPP_LONG &&
2954 data[2] == M560_SUB_ID && data[6] == 0x00) {
2955 /*
2956 * m560 mouse report for middle, forward and backward button
2957 *
2958 * data[0] = 0x11
2959 * data[1] = device-id
2960 * data[2] = 0x0a
2961 * data[5] = 0xaf -> middle
2962 * 0xb0 -> forward
2963 * 0xae -> backward
2964 * 0x00 -> release all
2965 * data[6] = 0x00
2966 */
2967
2968 switch (data[5]) {
2969 case 0xaf:
Hans de Goede06104302019-04-20 13:22:13 +02002970 input_report_key(hidpp->input, BTN_MIDDLE, 1);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002971 break;
2972 case 0xb0:
Hans de Goede06104302019-04-20 13:22:13 +02002973 input_report_key(hidpp->input, BTN_FORWARD, 1);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002974 break;
2975 case 0xae:
Hans de Goede06104302019-04-20 13:22:13 +02002976 input_report_key(hidpp->input, BTN_BACK, 1);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002977 break;
2978 case 0x00:
Hans de Goede06104302019-04-20 13:22:13 +02002979 input_report_key(hidpp->input, BTN_BACK, 0);
2980 input_report_key(hidpp->input, BTN_FORWARD, 0);
2981 input_report_key(hidpp->input, BTN_MIDDLE, 0);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002982 break;
2983 default:
2984 hid_err(hdev, "error in report\n");
2985 return 0;
2986 }
Hans de Goede06104302019-04-20 13:22:13 +02002987 input_sync(hidpp->input);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02002988
2989 } else if (data[0] == 0x02) {
2990 /*
2991 * Logitech M560 mouse report
2992 *
2993 * data[0] = type (0x02)
2994 * data[1..2] = buttons
2995 * data[3..5] = xy
2996 * data[6] = wheel
2997 */
2998
2999 int v;
3000
Hans de Goede06104302019-04-20 13:22:13 +02003001 input_report_key(hidpp->input, BTN_LEFT,
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003002 !!(data[1] & M560_MOUSE_BTN_LEFT));
Hans de Goede06104302019-04-20 13:22:13 +02003003 input_report_key(hidpp->input, BTN_RIGHT,
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003004 !!(data[1] & M560_MOUSE_BTN_RIGHT));
3005
Harry Cutts4435ff22018-12-05 10:42:27 +10003006 if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) {
Hans de Goede06104302019-04-20 13:22:13 +02003007 input_report_rel(hidpp->input, REL_HWHEEL, -1);
3008 input_report_rel(hidpp->input, REL_HWHEEL_HI_RES,
Harry Cutts4435ff22018-12-05 10:42:27 +10003009 -120);
3010 } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) {
Hans de Goede06104302019-04-20 13:22:13 +02003011 input_report_rel(hidpp->input, REL_HWHEEL, 1);
3012 input_report_rel(hidpp->input, REL_HWHEEL_HI_RES,
Harry Cutts4435ff22018-12-05 10:42:27 +10003013 120);
3014 }
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003015
3016 v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12);
Hans de Goede06104302019-04-20 13:22:13 +02003017 input_report_rel(hidpp->input, REL_X, v);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003018
3019 v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12);
Hans de Goede06104302019-04-20 13:22:13 +02003020 input_report_rel(hidpp->input, REL_Y, v);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003021
3022 v = hid_snto32(data[6], 8);
Peter Huttererfd357592019-03-20 08:48:23 +10003023 if (v != 0)
Hans de Goede06104302019-04-20 13:22:13 +02003024 hidpp_scroll_counter_handle_scroll(hidpp->input,
Peter Huttererfd357592019-03-20 08:48:23 +10003025 &hidpp->vertical_wheel_counter, v);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003026
Hans de Goede06104302019-04-20 13:22:13 +02003027 input_sync(hidpp->input);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003028 }
3029
3030 return 1;
3031}
3032
3033static void m560_populate_input(struct hidpp_device *hidpp,
Hans de Goedee54abaf2019-04-20 13:22:09 +02003034 struct input_dev *input_dev)
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003035{
Hans de Goede06104302019-04-20 13:22:13 +02003036 __set_bit(EV_KEY, input_dev->evbit);
3037 __set_bit(BTN_MIDDLE, input_dev->keybit);
3038 __set_bit(BTN_RIGHT, input_dev->keybit);
3039 __set_bit(BTN_LEFT, input_dev->keybit);
3040 __set_bit(BTN_BACK, input_dev->keybit);
3041 __set_bit(BTN_FORWARD, input_dev->keybit);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003042
Hans de Goede06104302019-04-20 13:22:13 +02003043 __set_bit(EV_REL, input_dev->evbit);
3044 __set_bit(REL_X, input_dev->relbit);
3045 __set_bit(REL_Y, input_dev->relbit);
3046 __set_bit(REL_WHEEL, input_dev->relbit);
3047 __set_bit(REL_HWHEEL, input_dev->relbit);
3048 __set_bit(REL_WHEEL_HI_RES, input_dev->relbit);
3049 __set_bit(REL_HWHEEL_HI_RES, input_dev->relbit);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003050}
3051
3052static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
3053 struct hid_field *field, struct hid_usage *usage,
3054 unsigned long **bit, int *max)
3055{
3056 return -1;
3057}
3058
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04003059/* ------------------------------------------------------------------------- */
3060/* Logitech K400 devices */
3061/* ------------------------------------------------------------------------- */
3062
3063/*
3064 * The Logitech K400 keyboard has an embedded touchpad which is seen
3065 * as a mouse from the OS point of view. There is a hardware shortcut to disable
3066 * tap-to-click but the setting is not remembered accross reset, annoying some
3067 * users.
3068 *
3069 * We can toggle this feature from the host by using the feature 0x6010:
3070 * Touchpad FW items
3071 */
3072
3073struct k400_private_data {
3074 u8 feature_index;
3075};
3076
3077static int k400_disable_tap_to_click(struct hidpp_device *hidpp)
3078{
3079 struct k400_private_data *k400 = hidpp->private_data;
3080 struct hidpp_touchpad_fw_items items = {};
3081 int ret;
3082 u8 feature_type;
3083
3084 if (!k400->feature_index) {
3085 ret = hidpp_root_get_feature(hidpp,
3086 HIDPP_PAGE_TOUCHPAD_FW_ITEMS,
3087 &k400->feature_index, &feature_type);
3088 if (ret)
3089 /* means that the device is not powered up */
3090 return ret;
3091 }
3092
3093 ret = hidpp_touchpad_fw_items_set(hidpp, k400->feature_index, &items);
3094 if (ret)
3095 return ret;
3096
3097 return 0;
3098}
3099
3100static int k400_allocate(struct hid_device *hdev)
3101{
3102 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3103 struct k400_private_data *k400;
3104
3105 k400 = devm_kzalloc(&hdev->dev, sizeof(struct k400_private_data),
3106 GFP_KERNEL);
3107 if (!k400)
3108 return -ENOMEM;
3109
3110 hidpp->private_data = k400;
3111
3112 return 0;
3113};
3114
3115static int k400_connect(struct hid_device *hdev, bool connected)
3116{
3117 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3118
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04003119 if (!disable_tap_to_click)
3120 return 0;
3121
3122 return k400_disable_tap_to_click(hidpp);
3123}
3124
Simon Wood7f4b49f2015-11-19 16:42:13 -07003125/* ------------------------------------------------------------------------- */
3126/* Logitech G920 Driving Force Racing Wheel for Xbox One */
3127/* ------------------------------------------------------------------------- */
3128
3129#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
3130
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003131static int g920_ff_set_autocenter(struct hidpp_device *hidpp,
3132 struct hidpp_ff_private_data *data)
Simon Wood7f4b49f2015-11-19 16:42:13 -07003133{
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003134 struct hidpp_report response;
3135 u8 params[HIDPP_AUTOCENTER_PARAMS_LENGTH] = {
3136 [1] = HIDPP_FF_EFFECT_SPRING | HIDPP_FF_EFFECT_AUTOSTART,
3137 };
Simon Wood7f4b49f2015-11-19 16:42:13 -07003138 int ret;
3139
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003140 /* initialize with zero autocenter to get wheel in usable state */
3141
3142 dbg_hid("Setting autocenter to 0.\n");
3143 ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
3144 HIDPP_FF_DOWNLOAD_EFFECT,
3145 params, ARRAY_SIZE(params),
3146 &response);
3147 if (ret)
3148 hid_warn(hidpp->hid_dev, "Failed to autocenter device!\n");
3149 else
3150 data->slot_autocenter = response.fap.params[0];
3151
3152 return ret;
3153}
3154
3155static int g920_get_config(struct hidpp_device *hidpp,
3156 struct hidpp_ff_private_data *data)
3157{
3158 struct hidpp_report response;
3159 u8 feature_type;
3160 int ret;
3161
3162 memset(data, 0, sizeof(*data));
3163
Simon Wood7f4b49f2015-11-19 16:42:13 -07003164 /* Find feature and store for later use */
3165 ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003166 &data->feature_index, &feature_type);
Simon Wood7f4b49f2015-11-19 16:42:13 -07003167 if (ret)
3168 return ret;
3169
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003170 /* Read number of slots available in device */
3171 ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
3172 HIDPP_FF_GET_INFO,
3173 NULL, 0,
3174 &response);
3175 if (ret) {
3176 if (ret < 0)
3177 return ret;
3178 hid_err(hidpp->hid_dev,
3179 "%s: received protocol error 0x%02x\n", __func__, ret);
3180 return -EPROTO;
3181 }
Simon Wood7f4b49f2015-11-19 16:42:13 -07003182
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07003183 data->num_effects = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS;
3184
3185 /* reset all forces */
3186 ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
3187 HIDPP_FF_RESET_ALL,
3188 NULL, 0,
3189 &response);
3190 if (ret)
3191 hid_warn(hidpp->hid_dev, "Failed to reset all forces!\n");
3192
3193 ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
3194 HIDPP_FF_GET_APERTURE,
3195 NULL, 0,
3196 &response);
3197 if (ret) {
3198 hid_warn(hidpp->hid_dev,
3199 "Failed to read range from device!\n");
3200 }
3201 data->range = ret ?
3202 900 : get_unaligned_be16(&response.fap.params[0]);
3203
3204 /* Read the current gain values */
3205 ret = hidpp_send_fap_command_sync(hidpp, data->feature_index,
3206 HIDPP_FF_GET_GLOBAL_GAINS,
3207 NULL, 0,
3208 &response);
3209 if (ret)
3210 hid_warn(hidpp->hid_dev,
3211 "Failed to read gain values from device!\n");
3212 data->gain = ret ?
3213 0xffff : get_unaligned_be16(&response.fap.params[0]);
3214
3215 /* ignore boost value at response.fap.params[2] */
3216
3217 return g920_ff_set_autocenter(hidpp, data);
Simon Wood7f4b49f2015-11-19 16:42:13 -07003218}
3219
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003220/* -------------------------------------------------------------------------- */
Hans de Goedeb4c00e72020-11-14 22:20:56 +01003221/* Logitech Dinovo Mini keyboard with builtin touchpad */
3222/* -------------------------------------------------------------------------- */
3223#define DINOVO_MINI_PRODUCT_ID 0xb30c
3224
3225static int lg_dinovo_input_mapping(struct hid_device *hdev, struct hid_input *hi,
3226 struct hid_field *field, struct hid_usage *usage,
3227 unsigned long **bit, int *max)
3228{
3229 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
3230 return 0;
3231
3232 switch (usage->hid & HID_USAGE) {
3233 case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
3234 default:
3235 return 0;
3236 }
3237 return 1;
3238}
3239
3240/* -------------------------------------------------------------------------- */
Hans de Goede4a79bcc2019-04-20 13:22:15 +02003241/* HID++1.0 devices which use HID++ reports for their wheels */
3242/* -------------------------------------------------------------------------- */
3243static int hidpp10_wheel_connect(struct hidpp_device *hidpp)
3244{
3245 return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0,
3246 HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT,
3247 HIDPP_ENABLE_WHEEL_REPORT | HIDPP_ENABLE_HWHEEL_REPORT);
3248}
3249
3250static int hidpp10_wheel_raw_event(struct hidpp_device *hidpp,
3251 u8 *data, int size)
3252{
3253 s8 value, hvalue;
3254
3255 if (!hidpp->input)
3256 return -EINVAL;
3257
3258 if (size < 7)
3259 return 0;
3260
3261 if (data[0] != REPORT_ID_HIDPP_SHORT || data[2] != HIDPP_SUB_ID_ROLLER)
3262 return 0;
3263
3264 value = data[3];
3265 hvalue = data[4];
3266
3267 input_report_rel(hidpp->input, REL_WHEEL, value);
3268 input_report_rel(hidpp->input, REL_WHEEL_HI_RES, value * 120);
3269 input_report_rel(hidpp->input, REL_HWHEEL, hvalue);
3270 input_report_rel(hidpp->input, REL_HWHEEL_HI_RES, hvalue * 120);
3271 input_sync(hidpp->input);
3272
3273 return 1;
3274}
3275
3276static void hidpp10_wheel_populate_input(struct hidpp_device *hidpp,
3277 struct input_dev *input_dev)
3278{
3279 __set_bit(EV_REL, input_dev->evbit);
3280 __set_bit(REL_WHEEL, input_dev->relbit);
3281 __set_bit(REL_WHEEL_HI_RES, input_dev->relbit);
3282 __set_bit(REL_HWHEEL, input_dev->relbit);
3283 __set_bit(REL_HWHEEL_HI_RES, input_dev->relbit);
3284}
3285
3286/* -------------------------------------------------------------------------- */
Hans de Goede7457bc12019-04-20 13:22:16 +02003287/* HID++1.0 mice which use HID++ reports for extra mouse buttons */
3288/* -------------------------------------------------------------------------- */
3289static int hidpp10_extra_mouse_buttons_connect(struct hidpp_device *hidpp)
3290{
3291 return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0,
3292 HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT,
3293 HIDPP_ENABLE_MOUSE_EXTRA_BTN_REPORT);
3294}
3295
3296static int hidpp10_extra_mouse_buttons_raw_event(struct hidpp_device *hidpp,
3297 u8 *data, int size)
3298{
3299 int i;
3300
3301 if (!hidpp->input)
3302 return -EINVAL;
3303
3304 if (size < 7)
3305 return 0;
3306
3307 if (data[0] != REPORT_ID_HIDPP_SHORT ||
3308 data[2] != HIDPP_SUB_ID_MOUSE_EXTRA_BTNS)
3309 return 0;
3310
3311 /*
3312 * Buttons are either delivered through the regular mouse report *or*
3313 * through the extra buttons report. At least for button 6 how it is
3314 * delivered differs per receiver firmware version. Even receivers with
3315 * the same usb-id show different behavior, so we handle both cases.
3316 */
3317 for (i = 0; i < 8; i++)
3318 input_report_key(hidpp->input, BTN_MOUSE + i,
3319 (data[3] & (1 << i)));
3320
3321 /* Some mice report events on button 9+, use BTN_MISC */
3322 for (i = 0; i < 8; i++)
3323 input_report_key(hidpp->input, BTN_MISC + i,
3324 (data[4] & (1 << i)));
3325
3326 input_sync(hidpp->input);
3327 return 1;
3328}
3329
3330static void hidpp10_extra_mouse_buttons_populate_input(
3331 struct hidpp_device *hidpp, struct input_dev *input_dev)
3332{
3333 /* BTN_MOUSE - BTN_MOUSE+7 are set already by the descriptor */
3334 __set_bit(BTN_0, input_dev->keybit);
3335 __set_bit(BTN_1, input_dev->keybit);
3336 __set_bit(BTN_2, input_dev->keybit);
3337 __set_bit(BTN_3, input_dev->keybit);
3338 __set_bit(BTN_4, input_dev->keybit);
3339 __set_bit(BTN_5, input_dev->keybit);
3340 __set_bit(BTN_6, input_dev->keybit);
3341 __set_bit(BTN_7, input_dev->keybit);
3342}
3343
3344/* -------------------------------------------------------------------------- */
Hans de Goede42bc4f32019-04-20 13:22:17 +02003345/* HID++1.0 kbds which only report 0x10xx consumer usages through sub-id 0x03 */
3346/* -------------------------------------------------------------------------- */
3347
3348/* Find the consumer-page input report desc and change Maximums to 0x107f */
3349static u8 *hidpp10_consumer_keys_report_fixup(struct hidpp_device *hidpp,
3350 u8 *_rdesc, unsigned int *rsize)
3351{
3352 /* Note 0 terminated so we can use strnstr to search for this. */
Colin Ian Kinga96a8a52019-05-10 14:17:22 +01003353 static const char consumer_rdesc_start[] = {
Hans de Goede42bc4f32019-04-20 13:22:17 +02003354 0x05, 0x0C, /* USAGE_PAGE (Consumer Devices) */
3355 0x09, 0x01, /* USAGE (Consumer Control) */
3356 0xA1, 0x01, /* COLLECTION (Application) */
3357 0x85, 0x03, /* REPORT_ID = 3 */
3358 0x75, 0x10, /* REPORT_SIZE (16) */
3359 0x95, 0x02, /* REPORT_COUNT (2) */
3360 0x15, 0x01, /* LOGICAL_MIN (1) */
3361 0x26, 0x00 /* LOGICAL_MAX (... */
3362 };
3363 char *consumer_rdesc, *rdesc = (char *)_rdesc;
3364 unsigned int size;
3365
3366 consumer_rdesc = strnstr(rdesc, consumer_rdesc_start, *rsize);
3367 size = *rsize - (consumer_rdesc - rdesc);
3368 if (consumer_rdesc && size >= 25) {
3369 consumer_rdesc[15] = 0x7f;
3370 consumer_rdesc[16] = 0x10;
3371 consumer_rdesc[20] = 0x7f;
3372 consumer_rdesc[21] = 0x10;
3373 }
3374 return _rdesc;
3375}
3376
3377static int hidpp10_consumer_keys_connect(struct hidpp_device *hidpp)
3378{
3379 return hidpp10_set_register(hidpp, HIDPP_REG_ENABLE_REPORTS, 0,
3380 HIDPP_ENABLE_CONSUMER_REPORT,
3381 HIDPP_ENABLE_CONSUMER_REPORT);
3382}
3383
3384static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
3385 u8 *data, int size)
3386{
3387 u8 consumer_report[5];
3388
3389 if (size < 7)
3390 return 0;
3391
3392 if (data[0] != REPORT_ID_HIDPP_SHORT ||
3393 data[2] != HIDPP_SUB_ID_CONSUMER_VENDOR_KEYS)
3394 return 0;
3395
3396 /*
3397 * Build a normal consumer report (3) out of the data, this detour
3398 * is necessary to get some keyboards to report their 0x10xx usages.
3399 */
3400 consumer_report[0] = 0x03;
3401 memcpy(&consumer_report[1], &data[3], 4);
3402 /* We are called from atomic context */
3403 hid_report_raw_event(hidpp->hid_dev, HID_INPUT_REPORT,
3404 consumer_report, 5, 1);
3405
3406 return 1;
3407}
3408
3409/* -------------------------------------------------------------------------- */
Harry Cutts4435ff22018-12-05 10:42:27 +10003410/* High-resolution scroll wheels */
3411/* -------------------------------------------------------------------------- */
3412
3413static int hi_res_scroll_enable(struct hidpp_device *hidpp)
3414{
3415 int ret;
3416 u8 multiplier = 1;
3417
3418 if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
3419 ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
3420 if (ret == 0)
3421 ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
3422 } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
3423 ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
3424 &multiplier);
3425 } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ {
3426 ret = hidpp10_enable_scrolling_acceleration(hidpp);
3427 multiplier = 8;
3428 }
3429 if (ret)
3430 return ret;
3431
3432 if (multiplier == 0)
3433 multiplier = 1;
3434
3435 hidpp->vertical_wheel_counter.wheel_multiplier = multiplier;
Maciej S. Szmigieroe13762a2020-07-05 19:34:57 +02003436 hid_dbg(hidpp->hid_dev, "wheel multiplier = %d\n", multiplier);
Harry Cutts4435ff22018-12-05 10:42:27 +10003437 return 0;
3438}
3439
3440/* -------------------------------------------------------------------------- */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003441/* Generic HID++ devices */
3442/* -------------------------------------------------------------------------- */
3443
Hans de Goede42bc4f32019-04-20 13:22:17 +02003444static u8 *hidpp_report_fixup(struct hid_device *hdev, u8 *rdesc,
3445 unsigned int *rsize)
3446{
3447 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3448
3449 if (!hidpp)
3450 return rdesc;
3451
3452 /* For 27 MHz keyboards the quirk gets set after hid_parse. */
3453 if (hdev->group == HID_GROUP_LOGITECH_27MHZ_DEVICE ||
3454 (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS))
3455 rdesc = hidpp10_consumer_keys_report_fixup(hidpp, rdesc, rsize);
3456
3457 return rdesc;
3458}
3459
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003460static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
3461 struct hid_field *field, struct hid_usage *usage,
3462 unsigned long **bit, int *max)
3463{
3464 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3465
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003466 if (!hidpp)
3467 return 0;
3468
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003469 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
3470 return wtp_input_mapping(hdev, hi, field, usage, bit, max);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003471 else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560 &&
3472 field->application != HID_GD_MOUSE)
3473 return m560_input_mapping(hdev, hi, field, usage, bit, max);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003474
Hans de Goedeb4c00e72020-11-14 22:20:56 +01003475 if (hdev->product == DINOVO_MINI_PRODUCT_ID)
3476 return lg_dinovo_input_mapping(hdev, hi, field, usage, bit, max);
3477
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003478 return 0;
3479}
3480
Simon Wood0b1804e2015-11-19 16:42:15 -07003481static int hidpp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
3482 struct hid_field *field, struct hid_usage *usage,
3483 unsigned long **bit, int *max)
3484{
3485 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3486
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003487 if (!hidpp)
3488 return 0;
3489
Simon Wood0b1804e2015-11-19 16:42:15 -07003490 /* Ensure that Logitech G920 is not given a default fuzz/flat value */
3491 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
3492 if (usage->type == EV_ABS && (usage->code == ABS_X ||
3493 usage->code == ABS_Y || usage->code == ABS_Z ||
3494 usage->code == ABS_RZ)) {
3495 field->application = HID_GD_MULTIAXIS;
3496 }
3497 }
3498
3499 return 0;
3500}
3501
3502
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003503static void hidpp_populate_input(struct hidpp_device *hidpp,
Hans de Goedee54abaf2019-04-20 13:22:09 +02003504 struct input_dev *input)
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003505{
Hans de Goede06104302019-04-20 13:22:13 +02003506 hidpp->input = input;
3507
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003508 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
Hans de Goedee54abaf2019-04-20 13:22:09 +02003509 wtp_populate_input(hidpp, input);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003510 else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
Hans de Goedee54abaf2019-04-20 13:22:09 +02003511 m560_populate_input(hidpp, input);
Hans de Goede4a79bcc2019-04-20 13:22:15 +02003512
3513 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS)
3514 hidpp10_wheel_populate_input(hidpp, input);
Hans de Goede7457bc12019-04-20 13:22:16 +02003515
3516 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS)
3517 hidpp10_extra_mouse_buttons_populate_input(hidpp, input);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003518}
3519
Dmitry Torokhovb2c68a22015-09-29 15:52:59 -07003520static int hidpp_input_configured(struct hid_device *hdev,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003521 struct hid_input *hidinput)
3522{
3523 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003524 struct input_dev *input = hidinput->input;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003525
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003526 if (!hidpp)
3527 return 0;
3528
Hans de Goedee54abaf2019-04-20 13:22:09 +02003529 hidpp_populate_input(hidpp, input);
Dmitry Torokhovb2c68a22015-09-29 15:52:59 -07003530
3531 return 0;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003532}
3533
3534static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
3535 int size)
3536{
3537 struct hidpp_report *question = hidpp->send_receive_buf;
3538 struct hidpp_report *answer = hidpp->send_receive_buf;
3539 struct hidpp_report *report = (struct hidpp_report *)data;
Benjamin Tissoireseb626c52017-03-27 16:59:29 +02003540 int ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003541
3542 /*
3543 * If the mutex is locked then we have a pending answer from a
Peter Wue529fea2014-12-17 00:23:51 +01003544 * previously sent command.
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003545 */
3546 if (unlikely(mutex_is_locked(&hidpp->send_mutex))) {
3547 /*
3548 * Check for a correct hidpp20 answer or the corresponding
3549 * error
3550 */
3551 if (hidpp_match_answer(question, report) ||
3552 hidpp_match_error(question, report)) {
3553 *answer = *report;
3554 hidpp->answer_available = true;
3555 wake_up(&hidpp->wait);
3556 /*
3557 * This was an answer to a command that this driver sent
3558 * We return 1 to hid-core to avoid forwarding the
3559 * command upstream as it has been treated by the driver
3560 */
3561
3562 return 1;
3563 }
3564 }
3565
Mazin Rezk0da0a63b2019-10-27 17:44:13 +00003566 if (unlikely(hidpp_report_is_connect_event(hidpp, report))) {
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003567 atomic_set(&hidpp->connected,
3568 !(report->rap.params[0] & (1 << 6)));
Benjamin Tissoires6bd4e652016-06-29 19:28:02 +10003569 if (schedule_work(&hidpp->work) == 0)
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003570 dbg_hid("%s: connect event already queued\n", __func__);
3571 return 1;
3572 }
3573
Hans de Goede73833542021-04-04 20:56:09 +02003574 if (hidpp->hid_dev->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
3575 data[0] == REPORT_ID_HIDPP_SHORT &&
3576 data[2] == HIDPP_SUB_ID_USER_IFACE_EVENT &&
3577 (data[3] & HIDPP_USER_IFACE_EVENT_ENCRYPTION_KEY_LOST)) {
3578 dev_err_ratelimited(&hidpp->hid_dev->dev,
3579 "Error the keyboard's wireless encryption key has been lost, your keyboard will not work unless you re-configure encryption.\n");
3580 dev_err_ratelimited(&hidpp->hid_dev->dev,
3581 "See: https://gitlab.freedesktop.org/jwrdegoede/logitech-27mhz-keyboard-encryption-setup/\n");
3582 }
3583
Benjamin Tissoireseb626c52017-03-27 16:59:29 +02003584 if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
Filipe Laínse037acf02021-01-04 18:29:37 +00003585 ret = hidpp20_battery_event_1000(hidpp, data, size);
3586 if (ret != 0)
3587 return ret;
3588 ret = hidpp20_battery_event_1004(hidpp, data, size);
Benjamin Tissoireseb626c52017-03-27 16:59:29 +02003589 if (ret != 0)
3590 return ret;
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02003591 ret = hidpp_solar_battery_event(hidpp, data, size);
3592 if (ret != 0)
3593 return ret;
Pedro Vanzellabe281362019-10-26 19:25:06 -03003594 ret = hidpp20_battery_voltage_event(hidpp, data, size);
3595 if (ret != 0)
3596 return ret;
Benjamin Tissoireseb626c52017-03-27 16:59:29 +02003597 }
3598
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +02003599 if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
3600 ret = hidpp10_battery_event(hidpp, data, size);
3601 if (ret != 0)
3602 return ret;
3603 }
3604
Hans de Goede4a79bcc2019-04-20 13:22:15 +02003605 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) {
3606 ret = hidpp10_wheel_raw_event(hidpp, data, size);
3607 if (ret != 0)
3608 return ret;
3609 }
3610
Hans de Goede7457bc12019-04-20 13:22:16 +02003611 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS) {
3612 ret = hidpp10_extra_mouse_buttons_raw_event(hidpp, data, size);
3613 if (ret != 0)
3614 return ret;
3615 }
3616
Hans de Goede42bc4f32019-04-20 13:22:17 +02003617 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
3618 ret = hidpp10_consumer_keys_raw_event(hidpp, data, size);
3619 if (ret != 0)
3620 return ret;
3621 }
3622
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003623 return 0;
3624}
3625
3626static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
3627 u8 *data, int size)
3628{
3629 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Peter Wue529fea2014-12-17 00:23:51 +01003630 int ret = 0;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003631
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003632 if (!hidpp)
3633 return 0;
3634
Peter Wue529fea2014-12-17 00:23:51 +01003635 /* Generic HID++ processing. */
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003636 switch (data[0]) {
Simon Wooda5ce8f52015-11-19 16:42:11 -07003637 case REPORT_ID_HIDPP_VERY_LONG:
Hans de Goeded71b18f2019-04-20 13:22:12 +02003638 if (size != hidpp->very_long_report_length) {
Simon Wooda5ce8f52015-11-19 16:42:11 -07003639 hid_err(hdev, "received hid++ report of bad size (%d)",
3640 size);
3641 return 1;
3642 }
3643 ret = hidpp_raw_hidpp_event(hidpp, data, size);
3644 break;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003645 case REPORT_ID_HIDPP_LONG:
3646 if (size != HIDPP_REPORT_LONG_LENGTH) {
3647 hid_err(hdev, "received hid++ report of bad size (%d)",
3648 size);
3649 return 1;
3650 }
Peter Wue529fea2014-12-17 00:23:51 +01003651 ret = hidpp_raw_hidpp_event(hidpp, data, size);
3652 break;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003653 case REPORT_ID_HIDPP_SHORT:
3654 if (size != HIDPP_REPORT_SHORT_LENGTH) {
3655 hid_err(hdev, "received hid++ report of bad size (%d)",
3656 size);
3657 return 1;
3658 }
Peter Wue529fea2014-12-17 00:23:51 +01003659 ret = hidpp_raw_hidpp_event(hidpp, data, size);
3660 break;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003661 }
3662
Peter Wue529fea2014-12-17 00:23:51 +01003663 /* If no report is available for further processing, skip calling
3664 * raw_event of subclasses. */
3665 if (ret != 0)
3666 return ret;
3667
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003668 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
3669 return wtp_raw_event(hdev, data, size);
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003670 else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
3671 return m560_raw_event(hdev, data, size);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003672
3673 return 0;
3674}
3675
Harry Cutts4435ff22018-12-05 10:42:27 +10003676static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
3677 struct hid_usage *usage, __s32 value)
3678{
3679 /* This function will only be called for scroll events, due to the
3680 * restriction imposed in hidpp_usages.
3681 */
3682 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003683 struct hidpp_scroll_counter *counter;
3684
3685 if (!hidpp)
3686 return 0;
3687
3688 counter = &hidpp->vertical_wheel_counter;
Harry Cutts4435ff22018-12-05 10:42:27 +10003689 /* A scroll event may occur before the multiplier has been retrieved or
3690 * the input device set, or high-res scroll enabling may fail. In such
3691 * cases we must return early (falling back to default behaviour) to
3692 * avoid a crash in hidpp_scroll_counter_handle_scroll.
3693 */
3694 if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
Hans de Goede06104302019-04-20 13:22:13 +02003695 || hidpp->input == NULL || counter->wheel_multiplier == 0)
Harry Cutts4435ff22018-12-05 10:42:27 +10003696 return 0;
3697
Hans de Goede06104302019-04-20 13:22:13 +02003698 hidpp_scroll_counter_handle_scroll(hidpp->input, counter, value);
Harry Cutts4435ff22018-12-05 10:42:27 +10003699 return 1;
3700}
3701
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003702static int hidpp_initialize_battery(struct hidpp_device *hidpp)
3703{
3704 static atomic_t battery_no = ATOMIC_INIT(0);
3705 struct power_supply_config cfg = { .drv_data = hidpp };
3706 struct power_supply_desc *desc = &hidpp->battery.desc;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003707 enum power_supply_property *battery_props;
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003708 struct hidpp_battery *battery;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003709 unsigned int num_battery_props;
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003710 unsigned long n;
3711 int ret;
3712
3713 if (hidpp->battery.ps)
3714 return 0;
3715
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02003716 hidpp->battery.feature_index = 0xff;
3717 hidpp->battery.solar_feature_index = 0xff;
Pedro Vanzellabe281362019-10-26 19:25:06 -03003718 hidpp->battery.voltage_feature_index = 0xff;
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02003719
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003720 if (hidpp->protocol_major >= 2) {
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02003721 if (hidpp->quirks & HIDPP_QUIRK_CLASS_K750)
3722 ret = hidpp_solar_request_battery_event(hidpp);
Pedro Vanzellabe281362019-10-26 19:25:06 -03003723 else {
Filipe Laínse037acf02021-01-04 18:29:37 +00003724 /* we only support one battery feature right now, so let's
3725 first check the ones that support battery level first
3726 and leave voltage for last */
3727 ret = hidpp20_query_battery_info_1000(hidpp);
Pedro Vanzellabe281362019-10-26 19:25:06 -03003728 if (ret)
Filipe Laínse037acf02021-01-04 18:29:37 +00003729 ret = hidpp20_query_battery_info_1004(hidpp);
3730 if (ret)
3731 ret = hidpp20_query_battery_voltage_info(hidpp);
Pedro Vanzellabe281362019-10-26 19:25:06 -03003732 }
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02003733
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003734 if (ret)
3735 return ret;
3736 hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_BATTERY;
3737 } else {
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +02003738 ret = hidpp10_query_battery_status(hidpp);
3739 if (ret) {
3740 ret = hidpp10_query_battery_mileage(hidpp);
3741 if (ret)
3742 return -ENOENT;
3743 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
3744 } else {
3745 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
3746 }
3747 hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP10_BATTERY;
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003748 }
3749
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003750 battery_props = devm_kmemdup(&hidpp->hid_dev->dev,
3751 hidpp_battery_props,
3752 sizeof(hidpp_battery_props),
3753 GFP_KERNEL);
Gustavo A. R. Silva929b60a2017-07-07 00:12:13 -05003754 if (!battery_props)
3755 return -ENOMEM;
3756
Pedro Vanzellabe281362019-10-26 19:25:06 -03003757 num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 3;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003758
Filipe Laínse037acf02021-01-04 18:29:37 +00003759 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
Hamza Mahfoozb23cdfb2021-08-02 08:52:32 -04003760 hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ||
3761 hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003762 battery_props[num_battery_props++] =
3763 POWER_SUPPLY_PROP_CAPACITY;
3764
3765 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS)
3766 battery_props[num_battery_props++] =
3767 POWER_SUPPLY_PROP_CAPACITY_LEVEL;
3768
Pedro Vanzellabe281362019-10-26 19:25:06 -03003769 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
3770 battery_props[num_battery_props++] =
3771 POWER_SUPPLY_PROP_VOLTAGE_NOW;
3772
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003773 battery = &hidpp->battery;
3774
3775 n = atomic_inc_return(&battery_no) - 1;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003776 desc->properties = battery_props;
3777 desc->num_properties = num_battery_props;
Benjamin Tissoiresa52ec102017-03-27 16:59:31 +02003778 desc->get_property = hidpp_battery_get_property;
3779 sprintf(battery->name, "hidpp_battery_%ld", n);
3780 desc->name = battery->name;
3781 desc->type = POWER_SUPPLY_TYPE_BATTERY;
3782 desc->use_for_apm = 0;
3783
3784 battery->ps = devm_power_supply_register(&hidpp->hid_dev->dev,
3785 &battery->desc,
3786 &cfg);
3787 if (IS_ERR(battery->ps))
3788 return PTR_ERR(battery->ps);
3789
3790 power_supply_powers(battery->ps, &hidpp->hid_dev->dev);
3791
3792 return ret;
3793}
3794
Benjamin Tissoires843c6242017-03-27 16:59:26 +02003795static void hidpp_overwrite_name(struct hid_device *hdev)
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003796{
3797 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
3798 char *name;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003799
Benjamin Tissoires843c6242017-03-27 16:59:26 +02003800 if (hidpp->protocol_major < 2)
Benjamin Tissoiresb4f8ce02017-03-27 16:59:24 +02003801 return;
Benjamin Tissoires843c6242017-03-27 16:59:26 +02003802
3803 name = hidpp_get_device_name(hidpp);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003804
Simon Wood7bfd2922015-11-19 16:42:12 -07003805 if (!name) {
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003806 hid_err(hdev, "unable to retrieve the name of the device");
Simon Wood7bfd2922015-11-19 16:42:12 -07003807 } else {
3808 dbg_hid("HID++: Got name: %s\n", name);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003809 snprintf(hdev->name, sizeof(hdev->name), "%s", name);
Simon Wood7bfd2922015-11-19 16:42:12 -07003810 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04003811
3812 kfree(name);
3813}
3814
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003815static int hidpp_input_open(struct input_dev *dev)
3816{
3817 struct hid_device *hid = input_get_drvdata(dev);
3818
3819 return hid_hw_open(hid);
3820}
3821
3822static void hidpp_input_close(struct input_dev *dev)
3823{
3824 struct hid_device *hid = input_get_drvdata(dev);
3825
3826 hid_hw_close(hid);
3827}
3828
3829static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
3830{
3831 struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev);
Benjamin Tissoires005b3f52015-01-08 14:37:12 -05003832 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003833
3834 if (!input_dev)
3835 return NULL;
3836
3837 input_set_drvdata(input_dev, hdev);
3838 input_dev->open = hidpp_input_open;
3839 input_dev->close = hidpp_input_close;
3840
Benjamin Tissoires005b3f52015-01-08 14:37:12 -05003841 input_dev->name = hidpp->name;
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003842 input_dev->phys = hdev->phys;
3843 input_dev->uniq = hdev->uniq;
3844 input_dev->id.bustype = hdev->bus;
3845 input_dev->id.vendor = hdev->vendor;
3846 input_dev->id.product = hdev->product;
3847 input_dev->id.version = hdev->version;
3848 input_dev->dev.parent = &hdev->dev;
3849
3850 return input_dev;
3851}
3852
3853static void hidpp_connect_event(struct hidpp_device *hidpp)
3854{
3855 struct hid_device *hdev = hidpp->hid_dev;
3856 int ret = 0;
3857 bool connected = atomic_read(&hidpp->connected);
3858 struct input_dev *input;
3859 char *name, *devm_name;
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003860
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02003861 if (!connected) {
3862 if (hidpp->battery.ps) {
3863 hidpp->battery.online = false;
3864 hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN;
Benjamin Tissoires5b036ea2017-03-27 16:59:36 +02003865 hidpp->battery.level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02003866 power_supply_changed(hidpp->battery.ps);
3867 }
Benjamin Tissoires29368362017-03-27 16:59:28 +02003868 return;
Benjamin Tissoires284f8d72017-03-27 16:59:34 +02003869 }
Benjamin Tissoires29368362017-03-27 16:59:28 +02003870
Benjamin Tissoiresbf159442014-12-16 17:06:01 -05003871 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
3872 ret = wtp_connect(hdev, connected);
3873 if (ret)
3874 return;
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02003875 } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) {
3876 ret = m560_send_config_command(hdev, connected);
3877 if (ret)
3878 return;
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04003879 } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
3880 ret = k400_connect(hdev, connected);
3881 if (ret)
3882 return;
Benjamin Tissoiresbf159442014-12-16 17:06:01 -05003883 }
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04003884
Hans de Goede4a79bcc2019-04-20 13:22:15 +02003885 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_WHEELS) {
3886 ret = hidpp10_wheel_connect(hidpp);
3887 if (ret)
3888 return;
3889 }
3890
Hans de Goede7457bc12019-04-20 13:22:16 +02003891 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS) {
3892 ret = hidpp10_extra_mouse_buttons_connect(hidpp);
3893 if (ret)
3894 return;
3895 }
3896
Hans de Goede42bc4f32019-04-20 13:22:17 +02003897 if (hidpp->quirks & HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS) {
3898 ret = hidpp10_consumer_keys_connect(hidpp);
3899 if (ret)
3900 return;
3901 }
3902
Benjamin Tissoires580a7e82015-09-03 09:08:29 -04003903 /* the device is already connected, we can ask for its name and
3904 * protocol */
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003905 if (!hidpp->protocol_major) {
Hans de Goede090760d2019-03-22 08:41:39 +01003906 ret = hidpp_root_get_protocol_version(hidpp);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003907 if (ret) {
3908 hid_err(hdev, "Can not get the protocol version.\n");
3909 return;
3910 }
3911 }
3912
Benjamin Tissoires187f2bb2017-03-27 16:59:27 +02003913 if (hidpp->name == hdev->name && hidpp->protocol_major >= 2) {
Benjamin Tissoires005b3f52015-01-08 14:37:12 -05003914 name = hidpp_get_device_name(hidpp);
Hans de Goede2ddf07f2019-04-20 13:22:07 +02003915 if (name) {
3916 devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
3917 "%s", name);
3918 kfree(name);
3919 if (!devm_name)
3920 return;
3921
3922 hidpp->name = devm_name;
Benjamin Tissoires005b3f52015-01-08 14:37:12 -05003923 }
Benjamin Tissoires005b3f52015-01-08 14:37:12 -05003924 }
3925
Benjamin Tissoires187f2bb2017-03-27 16:59:27 +02003926 hidpp_initialize_battery(hidpp);
3927
Benjamin Tissoires9b9c5192017-03-27 16:59:33 +02003928 /* forward current battery state */
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +02003929 if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY) {
3930 hidpp10_enable_battery_reporting(hidpp);
3931 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
3932 hidpp10_query_battery_mileage(hidpp);
3933 else
3934 hidpp10_query_battery_status(hidpp);
3935 } else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY) {
Pedro Vanzellabe281362019-10-26 19:25:06 -03003936 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE)
3937 hidpp20_query_battery_voltage_info(hidpp);
Filipe Laínse037acf02021-01-04 18:29:37 +00003938 else if (hidpp->capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY)
3939 hidpp20_query_battery_info_1004(hidpp);
Pedro Vanzellabe281362019-10-26 19:25:06 -03003940 else
Filipe Laínse037acf02021-01-04 18:29:37 +00003941 hidpp20_query_battery_info_1000(hidpp);
Benjamin Tissoires9b9c5192017-03-27 16:59:33 +02003942 }
Benjamin Tissoires7f7ce2a2017-03-27 16:59:38 +02003943 if (hidpp->battery.ps)
3944 power_supply_changed(hidpp->battery.ps);
Benjamin Tissoires9b9c5192017-03-27 16:59:33 +02003945
Harry Cutts4435ff22018-12-05 10:42:27 +10003946 if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
3947 hi_res_scroll_enable(hidpp);
3948
Benjamin Tissoires29368362017-03-27 16:59:28 +02003949 if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
3950 /* if the input nodes are already created, we can stop now */
Benjamin Tissoires187f2bb2017-03-27 16:59:27 +02003951 return;
3952
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003953 input = hidpp_allocate_input(hdev);
3954 if (!input) {
3955 hid_err(hdev, "cannot allocate new input device: %d\n", ret);
3956 return;
3957 }
3958
Hans de Goedee54abaf2019-04-20 13:22:09 +02003959 hidpp_populate_input(hidpp, input);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04003960
3961 ret = input_register_device(input);
3962 if (ret)
3963 input_free_device(input);
3964
3965 hidpp->delayed_input = input;
3966}
3967
Benjamin Tissoiresa4bf61532017-03-27 16:59:39 +02003968static DEVICE_ATTR(builtin_power_supply, 0000, NULL, NULL);
3969
3970static struct attribute *sysfs_attrs[] = {
3971 &dev_attr_builtin_power_supply.attr,
3972 NULL
3973};
3974
Arvind Yadav35a33cb2017-08-03 16:59:04 +05303975static const struct attribute_group ps_attribute_group = {
Benjamin Tissoiresa4bf61532017-03-27 16:59:39 +02003976 .attrs = sysfs_attrs
3977};
3978
Hans de Goeded71b18f2019-04-20 13:22:12 +02003979static int hidpp_get_report_length(struct hid_device *hdev, int id)
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003980{
3981 struct hid_report_enum *re;
3982 struct hid_report *report;
3983
Hans de Goeded71b18f2019-04-20 13:22:12 +02003984 re = &(hdev->report_enum[HID_OUTPUT_REPORT]);
3985 report = re->report_id_hash[id];
3986 if (!report)
3987 return 0;
3988
3989 return report->field[0]->report_count + 1;
3990}
3991
Mazin Rezkc2a93272019-10-27 17:44:06 +00003992static u8 hidpp_validate_device(struct hid_device *hdev)
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02003993{
Andrey Smirnov905d7542019-10-17 21:45:16 -07003994 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
Mazin Rezkc2a93272019-10-27 17:44:06 +00003995 int id, report_length;
3996 u8 supported_reports = 0;
Andrey Smirnov905d7542019-10-17 21:45:16 -07003997
3998 id = REPORT_ID_HIDPP_SHORT;
3999 report_length = hidpp_get_report_length(hdev, id);
4000 if (report_length) {
4001 if (report_length < HIDPP_REPORT_SHORT_LENGTH)
4002 goto bad_device;
4003
Mazin Rezkc2a93272019-10-27 17:44:06 +00004004 supported_reports |= HIDPP_REPORT_SHORT_SUPPORTED;
Andrey Smirnov905d7542019-10-17 21:45:16 -07004005 }
4006
4007 id = REPORT_ID_HIDPP_LONG;
4008 report_length = hidpp_get_report_length(hdev, id);
4009 if (report_length) {
4010 if (report_length < HIDPP_REPORT_LONG_LENGTH)
4011 goto bad_device;
4012
Mazin Rezkc2a93272019-10-27 17:44:06 +00004013 supported_reports |= HIDPP_REPORT_LONG_SUPPORTED;
Andrey Smirnov905d7542019-10-17 21:45:16 -07004014 }
4015
4016 id = REPORT_ID_HIDPP_VERY_LONG;
4017 report_length = hidpp_get_report_length(hdev, id);
4018 if (report_length) {
4019 if (report_length < HIDPP_REPORT_LONG_LENGTH ||
4020 report_length > HIDPP_REPORT_VERY_LONG_MAX_LENGTH)
4021 goto bad_device;
4022
Mazin Rezkc2a93272019-10-27 17:44:06 +00004023 supported_reports |= HIDPP_REPORT_VERY_LONG_SUPPORTED;
Andrey Smirnov905d7542019-10-17 21:45:16 -07004024 hidpp->very_long_report_length = report_length;
4025 }
4026
4027 return supported_reports;
4028
4029bad_device:
4030 hid_warn(hdev, "not enough values in hidpp report %d\n", id);
4031 return false;
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02004032}
4033
Hans de Goede4a79bcc2019-04-20 13:22:15 +02004034static bool hidpp_application_equals(struct hid_device *hdev,
4035 unsigned int application)
4036{
4037 struct list_head *report_list;
4038 struct hid_report *report;
4039
4040 report_list = &hdev->report_enum[HID_INPUT_REPORT].report_list;
4041 report = list_first_entry_or_null(report_list, struct hid_report, list);
4042 return report && report->application == application;
4043}
4044
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004045static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
4046{
4047 struct hidpp_device *hidpp;
4048 int ret;
4049 bool connected;
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004050 unsigned int connect_mask = HID_CONNECT_DEFAULT;
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07004051 struct hidpp_ff_private_data data;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004052
Hans de Goede42bc4f32019-04-20 13:22:17 +02004053 /* report_fixup needs drvdata to be set before we call hid_parse */
4054 hidpp = devm_kzalloc(&hdev->dev, sizeof(*hidpp), GFP_KERNEL);
4055 if (!hidpp)
4056 return -ENOMEM;
4057
4058 hidpp->hid_dev = hdev;
4059 hidpp->name = hdev->name;
4060 hidpp->quirks = id->driver_data;
4061 hid_set_drvdata(hdev, hidpp);
4062
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02004063 ret = hid_parse(hdev);
4064 if (ret) {
4065 hid_err(hdev, "%s:parse failed\n", __func__);
4066 return ret;
4067 }
4068
4069 /*
4070 * Make sure the device is HID++ capable, otherwise treat as generic HID
4071 */
Mazin Rezkc2a93272019-10-27 17:44:06 +00004072 hidpp->supported_reports = hidpp_validate_device(hdev);
4073
4074 if (!hidpp->supported_reports) {
Hans de Goede42bc4f32019-04-20 13:22:17 +02004075 hid_set_drvdata(hdev, NULL);
4076 devm_kfree(&hdev->dev, hidpp);
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02004077 return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
Hans de Goede42bc4f32019-04-20 13:22:17 +02004078 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004079
Benjamin Tissoires843c6242017-03-27 16:59:26 +02004080 if (id->group == HID_GROUP_LOGITECH_DJ_DEVICE)
4081 hidpp->quirks |= HIDPP_QUIRK_UNIFYING;
4082
Hans de Goede4a79bcc2019-04-20 13:22:15 +02004083 if (id->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
4084 hidpp_application_equals(hdev, HID_GD_MOUSE))
Hans de Goede7457bc12019-04-20 13:22:16 +02004085 hidpp->quirks |= HIDPP_QUIRK_HIDPP_WHEELS |
4086 HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS;
Hans de Goede4a79bcc2019-04-20 13:22:15 +02004087
Hans de Goede42bc4f32019-04-20 13:22:17 +02004088 if (id->group == HID_GROUP_LOGITECH_27MHZ_DEVICE &&
4089 hidpp_application_equals(hdev, HID_GD_KEYBOARD))
4090 hidpp->quirks |= HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS;
4091
Benjamin Tissoires9188dba2015-03-26 12:41:57 -04004092 if (disable_raw_mode) {
4093 hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP;
Benjamin Tissoires580a7e82015-09-03 09:08:29 -04004094 hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT;
Benjamin Tissoires9188dba2015-03-26 12:41:57 -04004095 }
4096
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004097 if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
4098 ret = wtp_allocate(hdev, id);
4099 if (ret)
Benjamin Tissoires43cd97a2019-04-20 13:21:42 +02004100 return ret;
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04004101 } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) {
4102 ret = k400_allocate(hdev);
4103 if (ret)
Benjamin Tissoires43cd97a2019-04-20 13:21:42 +02004104 return ret;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004105 }
4106
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004107 INIT_WORK(&hidpp->work, delayed_work_cb);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004108 mutex_init(&hidpp->send_mutex);
4109 init_waitqueue_head(&hidpp->wait);
4110
Benjamin Tissoiresa4bf61532017-03-27 16:59:39 +02004111 /* indicates we are handling the battery properties in the kernel */
4112 ret = sysfs_create_group(&hdev->dev.kobj, &ps_attribute_group);
4113 if (ret)
4114 hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
4115 hdev->name);
4116
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004117 /*
4118 * Plain USB connections need to actually call start and open
4119 * on the transport driver to allow incoming data.
4120 */
4121 ret = hid_hw_start(hdev, 0);
4122 if (ret) {
4123 hid_err(hdev, "hw start failed\n");
4124 goto hid_hw_start_fail;
Simon Wood7bfd2922015-11-19 16:42:12 -07004125 }
4126
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004127 ret = hid_hw_open(hdev);
4128 if (ret < 0) {
4129 dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
4130 __func__, ret);
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004131 goto hid_hw_open_fail;
4132 }
Simon Wood7bfd2922015-11-19 16:42:12 -07004133
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004134 /* Allow incoming packets */
4135 hid_device_io_start(hdev);
4136
Benjamin Tissoires843c6242017-03-27 16:59:26 +02004137 if (hidpp->quirks & HIDPP_QUIRK_UNIFYING)
4138 hidpp_unifying_init(hidpp);
4139
Hans de Goede090760d2019-03-22 08:41:39 +01004140 connected = hidpp_root_get_protocol_version(hidpp) == 0;
Benjamin Tissoires843c6242017-03-27 16:59:26 +02004141 atomic_set(&hidpp->connected, connected);
4142 if (!(hidpp->quirks & HIDPP_QUIRK_UNIFYING)) {
Benjamin Tissoiresab94e562014-09-30 13:18:28 -04004143 if (!connected) {
Julia Lawallb832da52015-04-05 14:06:29 +02004144 ret = -ENODEV;
Benjamin Tissoiresab94e562014-09-30 13:18:28 -04004145 hid_err(hdev, "Device not connected");
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004146 goto hid_hw_init_fail;
Benjamin Tissoiresab94e562014-09-30 13:18:28 -04004147 }
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004148
Benjamin Tissoires843c6242017-03-27 16:59:26 +02004149 hidpp_overwrite_name(hdev);
4150 }
Benjamin Tissoires33797822014-09-30 13:18:30 -04004151
Mazin Rezk0da0a63b2019-10-27 17:44:13 +00004152 if (connected && hidpp->protocol_major >= 2) {
4153 ret = hidpp_set_wireless_feature_index(hidpp);
4154 if (ret == -ENOENT)
4155 hidpp->wireless_feature_index = 0;
4156 else if (ret)
4157 goto hid_hw_init_fail;
4158 }
4159
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004160 if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004161 ret = wtp_get_config(hidpp);
4162 if (ret)
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004163 goto hid_hw_init_fail;
Simon Wood7f4b49f2015-11-19 16:42:13 -07004164 } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07004165 ret = g920_get_config(hidpp, &data);
Simon Wood7f4b49f2015-11-19 16:42:13 -07004166 if (ret)
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004167 goto hid_hw_init_fail;
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004168 }
4169
Benjamin Tissoires6bd4e652016-06-29 19:28:02 +10004170 hidpp_connect_event(hidpp);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004171
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004172 /* Reset the HID node state */
4173 hid_device_io_stop(hdev);
4174 hid_hw_close(hdev);
4175 hid_hw_stop(hdev);
4176
4177 if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
4178 connect_mask &= ~HID_CONNECT_HIDINPUT;
4179
4180 /* Now export the actual inputs and hidraw nodes to the world */
4181 ret = hid_hw_start(hdev, connect_mask);
4182 if (ret) {
4183 hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
4184 goto hid_hw_start_fail;
4185 }
4186
Andrey Smirnovabdd3d02019-10-17 21:45:15 -07004187 if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
4188 ret = hidpp_ff_init(hidpp, &data);
4189 if (ret)
4190 hid_warn(hidpp->hid_dev,
4191 "Unable to initialize force feedback support, errno %d\n",
4192 ret);
4193 }
4194
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004195 return ret;
4196
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004197hid_hw_init_fail:
4198 hid_hw_close(hdev);
4199hid_hw_open_fail:
4200 hid_hw_stop(hdev);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004201hid_hw_start_fail:
Benjamin Tissoiresa4bf61532017-03-27 16:59:39 +02004202 sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004203 cancel_work_sync(&hidpp->work);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004204 mutex_destroy(&hidpp->send_mutex);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004205 return ret;
4206}
4207
4208static void hidpp_remove(struct hid_device *hdev)
4209{
4210 struct hidpp_device *hidpp = hid_get_drvdata(hdev);
4211
Benjamin Tissoiresfe3ee1e2019-04-20 13:22:04 +02004212 if (!hidpp)
4213 return hid_hw_stop(hdev);
4214
Benjamin Tissoiresa4bf61532017-03-27 16:59:39 +02004215 sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
4216
Simon Wood7bfd2922015-11-19 16:42:12 -07004217 hid_hw_stop(hdev);
Benjamin Tissoiresc39e3d52014-09-30 13:18:32 -04004218 cancel_work_sync(&hidpp->work);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004219 mutex_destroy(&hidpp->send_mutex);
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004220}
4221
Harry Cutts4435ff22018-12-05 10:42:27 +10004222#define LDJ_DEVICE(product) \
4223 HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
4224 USB_VENDOR_ID_LOGITECH, (product))
4225
Hans de Goede754a3082019-04-20 13:22:11 +02004226#define L27MHZ_DEVICE(product) \
4227 HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_27MHZ_DEVICE, \
4228 USB_VENDOR_ID_LOGITECH, (product))
4229
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004230static const struct hid_device_id hidpp_devices[] = {
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04004231 { /* wireless touchpad */
Harry Cutts16767222018-12-05 10:42:28 +10004232 LDJ_DEVICE(0x4011),
Benjamin Tissoires57ac86c2014-09-30 13:18:34 -04004233 .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
4234 HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04004235 { /* wireless touchpad T650 */
Harry Cutts16767222018-12-05 10:42:28 +10004236 LDJ_DEVICE(0x4101),
Benjamin Tissoires586bdc42014-09-30 13:18:33 -04004237 .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004238 { /* wireless touchpad T651 */
4239 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
4240 USB_DEVICE_ID_LOGITECH_T651),
4241 .driver_data = HIDPP_QUIRK_CLASS_WTP },
Harry Cutts4435ff22018-12-05 10:42:27 +10004242 { /* Mouse Logitech Anywhere MX */
4243 LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
4244 { /* Mouse Logitech Cube */
4245 LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
4246 { /* Mouse Logitech M335 */
4247 LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4248 { /* Mouse Logitech M515 */
4249 LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
Goffredo Baroncelli8a09b4f2015-05-30 11:00:27 +02004250 { /* Mouse logitech M560 */
Harry Cutts4435ff22018-12-05 10:42:27 +10004251 LDJ_DEVICE(0x402d),
4252 .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
4253 | HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
4254 { /* Mouse Logitech M705 (firmware RQM17) */
4255 LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
4256 { /* Mouse Logitech M705 (firmware RQM67) */
4257 LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4258 { /* Mouse Logitech M720 */
4259 LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4260 { /* Mouse Logitech MX Anywhere 2 */
4261 LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Harry Cuttsb59f38d2020-10-21 06:56:12 -07004262 { LDJ_DEVICE(0x4072), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Harry Cutts4435ff22018-12-05 10:42:27 +10004263 { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4264 { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4265 { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4266 { /* Mouse Logitech MX Anywhere 2S */
4267 LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4268 { /* Mouse Logitech MX Master */
4269 LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4270 { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4271 { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
4272 { /* Mouse Logitech MX Master 2S */
4273 LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Adrian Freund04bd6812019-10-25 22:59:29 +02004274 { /* Mouse Logitech MX Master 3 */
4275 LDJ_DEVICE(0x4082), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Harry Cutts4435ff22018-12-05 10:42:27 +10004276 { /* Mouse Logitech Performance MX */
4277 LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
Benjamin Tissoires90cdd982015-09-03 09:08:30 -04004278 { /* Keyboard logitech K400 */
Harry Cutts16767222018-12-05 10:42:28 +10004279 LDJ_DEVICE(0x4024),
Benjamin Tissoires6bd4e652016-06-29 19:28:02 +10004280 .driver_data = HIDPP_QUIRK_CLASS_K400 },
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02004281 { /* Solar Keyboard Logitech K750 */
Harry Cutts16767222018-12-05 10:42:28 +10004282 LDJ_DEVICE(0x4002),
Benjamin Tissoires696ecef2017-03-27 16:59:37 +02004283 .driver_data = HIDPP_QUIRK_CLASS_K750 },
Hans de Goede42bc4f32019-04-20 13:22:17 +02004284 { /* Keyboard MX5000 (Bluetooth-receiver in HID proxy mode) */
4285 LDJ_DEVICE(0xb305),
4286 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Hans de Goedec27168a2020-11-02 14:36:57 +01004287 { /* Dinovo Edge (Bluetooth-receiver in HID proxy mode) */
4288 LDJ_DEVICE(0xb309),
4289 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Hans de Goedeced2c0c2019-04-28 21:25:52 +02004290 { /* Keyboard MX5500 (Bluetooth-receiver in HID proxy mode) */
4291 LDJ_DEVICE(0xb30b),
4292 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Benjamin Tissoiresab94e562014-09-30 13:18:28 -04004293
Harry Cutts16767222018-12-05 10:42:28 +10004294 { LDJ_DEVICE(HID_ANY_ID) },
Simon Wood7bfd2922015-11-19 16:42:12 -07004295
Hans de Goede4a79bcc2019-04-20 13:22:15 +02004296 { /* Keyboard LX501 (Y-RR53) */
4297 L27MHZ_DEVICE(0x0049),
4298 .driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL },
4299 { /* Keyboard MX3000 (Y-RAM74) */
4300 L27MHZ_DEVICE(0x0057),
4301 .driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL },
4302 { /* Keyboard MX3200 (Y-RAV80) */
4303 L27MHZ_DEVICE(0x005c),
4304 .driver_data = HIDPP_QUIRK_KBD_ZOOM_WHEEL },
Hans de Goede24098772019-05-12 12:36:02 +02004305 { /* S510 Media Remote */
4306 L27MHZ_DEVICE(0x00fe),
4307 .driver_data = HIDPP_QUIRK_KBD_SCROLL_WHEEL },
Hans de Goede4a79bcc2019-04-20 13:22:15 +02004308
Hans de Goede754a3082019-04-20 13:22:11 +02004309 { L27MHZ_DEVICE(HID_ANY_ID) },
4310
Filipe Laíns27fc32f2019-07-16 08:37:26 +01004311 { /* Logitech G403 Wireless Gaming Mouse over USB */
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004312 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC082) },
Filipe Laíns27fc32f2019-07-16 08:37:26 +01004313 { /* Logitech G703 Gaming Mouse over USB */
4314 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC087) },
4315 { /* Logitech G703 Hero Gaming Mouse over USB */
4316 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC090) },
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004317 { /* Logitech G900 Gaming Mouse over USB */
4318 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC081) },
Filipe Laíns27fc32f2019-07-16 08:37:26 +01004319 { /* Logitech G903 Gaming Mouse over USB */
4320 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC086) },
4321 { /* Logitech G903 Hero Gaming Mouse over USB */
4322 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC091) },
Benjamin Tissoires91cf9a92019-04-20 13:22:05 +02004323 { /* Logitech G920 Wheel over USB */
4324 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
Simon Wood7bfd2922015-11-19 16:42:12 -07004325 .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
Filipe Laíns27fc32f2019-07-16 08:37:26 +01004326 { /* Logitech G Pro Gaming Mouse over USB */
4327 HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
Hans de Goede42bc4f32019-04-20 13:22:17 +02004328
4329 { /* MX5000 keyboard over Bluetooth */
4330 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb305),
4331 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Hans de Goedec27168a2020-11-02 14:36:57 +01004332 { /* Dinovo Edge keyboard over Bluetooth */
4333 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb309),
4334 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Hans de Goedeced2c0c2019-04-28 21:25:52 +02004335 { /* MX5500 keyboard over Bluetooth */
4336 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b),
4337 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
Hans de Goedeba876cd2020-11-19 14:27:27 +01004338 { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */
4339 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) },
Mazin Rezkc2a93272019-10-27 17:44:06 +00004340 { /* MX Master mouse over Bluetooth */
4341 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012),
4342 .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Nicholas Miell7de843d2021-01-10 22:09:25 -08004343 { /* MX Ergo trackball over Bluetooth */
4344 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01d) },
Mazin Rezkc2a93272019-10-27 17:44:06 +00004345 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb01e),
4346 .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Adrian Freund04bd6812019-10-25 22:59:29 +02004347 { /* MX Master 3 mouse over Bluetooth */
4348 HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb023),
4349 .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004350 {}
4351};
4352
4353MODULE_DEVICE_TABLE(hid, hidpp_devices);
4354
Harry Cutts4435ff22018-12-05 10:42:27 +10004355static const struct hid_usage_id hidpp_usages[] = {
4356 { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES },
4357 { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
4358};
4359
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004360static struct hid_driver hidpp_driver = {
4361 .name = "logitech-hidpp-device",
4362 .id_table = hidpp_devices,
Hans de Goede42bc4f32019-04-20 13:22:17 +02004363 .report_fixup = hidpp_report_fixup,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004364 .probe = hidpp_probe,
4365 .remove = hidpp_remove,
4366 .raw_event = hidpp_raw_event,
Harry Cutts4435ff22018-12-05 10:42:27 +10004367 .usage_table = hidpp_usages,
4368 .event = hidpp_event,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004369 .input_configured = hidpp_input_configured,
4370 .input_mapping = hidpp_input_mapping,
Simon Wood0b1804e2015-11-19 16:42:15 -07004371 .input_mapped = hidpp_input_mapped,
Benjamin Tissoires2f31c522014-09-30 13:18:27 -04004372};
4373
4374module_hid_driver(hidpp_driver);