mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-4.20/logitech-highres' into for-linus
High-resolution support for hid-logitech
This commit is contained in:
commit
276e722761
|
@ -190,7 +190,16 @@ A few EV_REL codes have special meanings:
|
||||||
* REL_WHEEL, REL_HWHEEL:
|
* REL_WHEEL, REL_HWHEEL:
|
||||||
|
|
||||||
- These codes are used for vertical and horizontal scroll wheels,
|
- These codes are used for vertical and horizontal scroll wheels,
|
||||||
respectively.
|
respectively. The value is the number of "notches" moved on the wheel, the
|
||||||
|
physical size of which varies by device. For high-resolution wheels (which
|
||||||
|
report multiple events for each notch of movement, or do not have notches)
|
||||||
|
this may be an approximation based on the high-resolution scroll events.
|
||||||
|
|
||||||
|
* REL_WHEEL_HI_RES:
|
||||||
|
|
||||||
|
- If a vertical scroll wheel supports high-resolution scrolling, this code
|
||||||
|
will be emitted in addition to REL_WHEEL. The value is the (approximate)
|
||||||
|
distance travelled by the user's finger, in microns.
|
||||||
|
|
||||||
EV_ABS
|
EV_ABS
|
||||||
------
|
------
|
||||||
|
|
|
@ -1838,3 +1838,48 @@ void hidinput_disconnect(struct hid_device *hid)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(hidinput_disconnect);
|
EXPORT_SYMBOL_GPL(hidinput_disconnect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hid_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
|
||||||
|
* events given a high-resolution wheel
|
||||||
|
* movement.
|
||||||
|
* @counter: a hid_scroll_counter struct describing the wheel.
|
||||||
|
* @hi_res_value: the movement of the wheel, in the mouse's high-resolution
|
||||||
|
* units.
|
||||||
|
*
|
||||||
|
* Given a high-resolution movement, this function converts the movement into
|
||||||
|
* microns and emits high-resolution scroll events for the input device. It also
|
||||||
|
* uses the multiplier from &struct hid_scroll_counter to emit low-resolution
|
||||||
|
* scroll events when appropriate for backwards-compatibility with userspace
|
||||||
|
* input libraries.
|
||||||
|
*/
|
||||||
|
void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
|
||||||
|
int hi_res_value)
|
||||||
|
{
|
||||||
|
int low_res_scroll_amount;
|
||||||
|
/* Some wheels will rest 7/8ths of a notch from the previous notch
|
||||||
|
* after slow movement, so we want the threshold for low-res events to
|
||||||
|
* be in the middle of the notches (e.g. after 4/8ths) as opposed to on
|
||||||
|
* the notches themselves (8/8ths).
|
||||||
|
*/
|
||||||
|
int threshold = counter->resolution_multiplier / 2;
|
||||||
|
|
||||||
|
input_report_rel(counter->dev, REL_WHEEL_HI_RES,
|
||||||
|
hi_res_value * counter->microns_per_hi_res_unit);
|
||||||
|
|
||||||
|
counter->remainder += hi_res_value;
|
||||||
|
if (abs(counter->remainder) >= threshold) {
|
||||||
|
/* Add (or subtract) 1 because we want to trigger when the wheel
|
||||||
|
* is half-way to the next notch (i.e. scroll 1 notch after a
|
||||||
|
* 1/2 notch movement, 2 notches after a 1 1/2 notch movement,
|
||||||
|
* etc.).
|
||||||
|
*/
|
||||||
|
low_res_scroll_amount =
|
||||||
|
counter->remainder / counter->resolution_multiplier
|
||||||
|
+ (hi_res_value > 0 ? 1 : -1);
|
||||||
|
input_report_rel(counter->dev, REL_WHEEL,
|
||||||
|
low_res_scroll_amount);
|
||||||
|
counter->remainder -=
|
||||||
|
low_res_scroll_amount * counter->resolution_multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(hid_scroll_counter_handle_scroll);
|
||||||
|
|
|
@ -64,6 +64,14 @@ MODULE_PARM_DESC(disable_tap_to_click,
|
||||||
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
#define HIDPP_QUIRK_NO_HIDINPUT BIT(23)
|
||||||
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
#define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24)
|
||||||
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
#define HIDPP_QUIRK_UNIFYING BIT(25)
|
||||||
|
#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26)
|
||||||
|
#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27)
|
||||||
|
#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28)
|
||||||
|
|
||||||
|
/* Convenience constant to check for any high-res support. */
|
||||||
|
#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \
|
||||||
|
HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \
|
||||||
|
HIDPP_QUIRK_HI_RES_SCROLL_X2121)
|
||||||
|
|
||||||
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
#define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT
|
||||||
|
|
||||||
|
@ -149,6 +157,7 @@ struct hidpp_device {
|
||||||
unsigned long capabilities;
|
unsigned long capabilities;
|
||||||
|
|
||||||
struct hidpp_battery battery;
|
struct hidpp_battery battery;
|
||||||
|
struct hid_scroll_counter vertical_wheel_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* HID++ 1.0 error codes */
|
/* HID++ 1.0 error codes */
|
||||||
|
@ -400,9 +409,15 @@ static void hidpp_prefix_name(char **name, int name_length)
|
||||||
#define HIDPP_SET_LONG_REGISTER 0x82
|
#define HIDPP_SET_LONG_REGISTER 0x82
|
||||||
#define HIDPP_GET_LONG_REGISTER 0x83
|
#define HIDPP_GET_LONG_REGISTER 0x83
|
||||||
|
|
||||||
#define HIDPP_REG_GENERAL 0x00
|
/**
|
||||||
|
* hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register.
|
||||||
static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
|
* @hidpp_dev: the device to set the register on.
|
||||||
|
* @register_address: the address of the register to modify.
|
||||||
|
* @byte: the byte of the register to modify. Should be less than 3.
|
||||||
|
* Return: 0 if successful, otherwise a negative error code.
|
||||||
|
*/
|
||||||
|
static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev,
|
||||||
|
u8 register_address, u8 byte, u8 bit)
|
||||||
{
|
{
|
||||||
struct hidpp_report response;
|
struct hidpp_report response;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -411,23 +426,38 @@ static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
|
||||||
ret = hidpp_send_rap_command_sync(hidpp_dev,
|
ret = hidpp_send_rap_command_sync(hidpp_dev,
|
||||||
REPORT_ID_HIDPP_SHORT,
|
REPORT_ID_HIDPP_SHORT,
|
||||||
HIDPP_GET_REGISTER,
|
HIDPP_GET_REGISTER,
|
||||||
HIDPP_REG_GENERAL,
|
register_address,
|
||||||
NULL, 0, &response);
|
NULL, 0, &response);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
memcpy(params, response.rap.params, 3);
|
memcpy(params, response.rap.params, 3);
|
||||||
|
|
||||||
/* Set the battery bit */
|
params[byte] |= BIT(bit);
|
||||||
params[0] |= BIT(4);
|
|
||||||
|
|
||||||
return hidpp_send_rap_command_sync(hidpp_dev,
|
return hidpp_send_rap_command_sync(hidpp_dev,
|
||||||
REPORT_ID_HIDPP_SHORT,
|
REPORT_ID_HIDPP_SHORT,
|
||||||
HIDPP_SET_REGISTER,
|
HIDPP_SET_REGISTER,
|
||||||
HIDPP_REG_GENERAL,
|
register_address,
|
||||||
params, 3, &response);
|
params, 3, &response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define HIDPP_REG_GENERAL 0x00
|
||||||
|
|
||||||
|
static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev)
|
||||||
|
{
|
||||||
|
return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HIDPP_REG_FEATURES 0x01
|
||||||
|
|
||||||
|
/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */
|
||||||
|
static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev)
|
||||||
|
{
|
||||||
|
return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
#define HIDPP_REG_BATTERY_STATUS 0x07
|
#define HIDPP_REG_BATTERY_STATUS 0x07
|
||||||
|
|
||||||
static int hidpp10_battery_status_map_level(u8 param)
|
static int hidpp10_battery_status_map_level(u8 param)
|
||||||
|
@ -1136,6 +1166,100 @@ static int hidpp_battery_get_property(struct power_supply *psy,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* 0x2120: Hi-resolution scrolling */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120
|
||||||
|
|
||||||
|
#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10
|
||||||
|
|
||||||
|
static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp,
|
||||||
|
bool enabled, u8 *multiplier)
|
||||||
|
{
|
||||||
|
u8 feature_index;
|
||||||
|
u8 feature_type;
|
||||||
|
int ret;
|
||||||
|
u8 params[1];
|
||||||
|
struct hidpp_report response;
|
||||||
|
|
||||||
|
ret = hidpp_root_get_feature(hidpp,
|
||||||
|
HIDPP_PAGE_HI_RESOLUTION_SCROLLING,
|
||||||
|
&feature_index,
|
||||||
|
&feature_type);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
params[0] = enabled ? BIT(0) : 0;
|
||||||
|
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||||
|
CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE,
|
||||||
|
params, sizeof(params), &response);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
*multiplier = response.fap.params[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* 0x2121: HiRes Wheel */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#define HIDPP_PAGE_HIRES_WHEEL 0x2121
|
||||||
|
|
||||||
|
#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00
|
||||||
|
#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20
|
||||||
|
|
||||||
|
static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp,
|
||||||
|
u8 *multiplier)
|
||||||
|
{
|
||||||
|
u8 feature_index;
|
||||||
|
u8 feature_type;
|
||||||
|
int ret;
|
||||||
|
struct hidpp_report response;
|
||||||
|
|
||||||
|
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
|
||||||
|
&feature_index, &feature_type);
|
||||||
|
if (ret)
|
||||||
|
goto return_default;
|
||||||
|
|
||||||
|
ret = hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||||
|
CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY,
|
||||||
|
NULL, 0, &response);
|
||||||
|
if (ret)
|
||||||
|
goto return_default;
|
||||||
|
|
||||||
|
*multiplier = response.fap.params[0];
|
||||||
|
return 0;
|
||||||
|
return_default:
|
||||||
|
hid_warn(hidpp->hid_dev,
|
||||||
|
"Couldn't get wheel multiplier (error %d), assuming %d.\n",
|
||||||
|
ret, *multiplier);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert,
|
||||||
|
bool high_resolution, bool use_hidpp)
|
||||||
|
{
|
||||||
|
u8 feature_index;
|
||||||
|
u8 feature_type;
|
||||||
|
int ret;
|
||||||
|
u8 params[1];
|
||||||
|
struct hidpp_report response;
|
||||||
|
|
||||||
|
ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL,
|
||||||
|
&feature_index, &feature_type);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
params[0] = (invert ? BIT(2) : 0) |
|
||||||
|
(high_resolution ? BIT(1) : 0) |
|
||||||
|
(use_hidpp ? BIT(0) : 0);
|
||||||
|
|
||||||
|
return hidpp_send_fap_command_sync(hidpp, feature_index,
|
||||||
|
CMD_HIRES_WHEEL_SET_WHEEL_MODE,
|
||||||
|
params, sizeof(params), &response);
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* 0x4301: Solar Keyboard */
|
/* 0x4301: Solar Keyboard */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
@ -2399,7 +2523,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size)
|
||||||
input_report_rel(mydata->input, REL_Y, v);
|
input_report_rel(mydata->input, REL_Y, v);
|
||||||
|
|
||||||
v = hid_snto32(data[6], 8);
|
v = hid_snto32(data[6], 8);
|
||||||
input_report_rel(mydata->input, REL_WHEEL, v);
|
hid_scroll_counter_handle_scroll(
|
||||||
|
&hidpp->vertical_wheel_counter, v);
|
||||||
|
|
||||||
input_sync(mydata->input);
|
input_sync(mydata->input);
|
||||||
}
|
}
|
||||||
|
@ -2527,6 +2652,72 @@ static int g920_get_config(struct hidpp_device *hidpp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* High-resolution scroll wheels */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hi_res_scroll_info - Stores info on a device's high-res scroll wheel.
|
||||||
|
* @product_id: the HID product ID of the device being described.
|
||||||
|
* @microns_per_hi_res_unit: the distance moved by the user's finger for each
|
||||||
|
* high-resolution unit reported by the device, in
|
||||||
|
* 256ths of a millimetre.
|
||||||
|
*/
|
||||||
|
struct hi_res_scroll_info {
|
||||||
|
__u32 product_id;
|
||||||
|
int microns_per_hi_res_unit;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct hi_res_scroll_info hi_res_scroll_devices[] = {
|
||||||
|
{ /* Anywhere MX */
|
||||||
|
.product_id = 0x1017, .microns_per_hi_res_unit = 445 },
|
||||||
|
{ /* Performance MX */
|
||||||
|
.product_id = 0x101a, .microns_per_hi_res_unit = 406 },
|
||||||
|
{ /* M560 */
|
||||||
|
.product_id = 0x402d, .microns_per_hi_res_unit = 435 },
|
||||||
|
{ /* MX Master 2S */
|
||||||
|
.product_id = 0x4069, .microns_per_hi_res_unit = 406 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hi_res_scroll_look_up_microns(__u32 product_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int num_devices = sizeof(hi_res_scroll_devices)
|
||||||
|
/ sizeof(hi_res_scroll_devices[0]);
|
||||||
|
for (i = 0; i < num_devices; i++) {
|
||||||
|
if (hi_res_scroll_devices[i].product_id == product_id)
|
||||||
|
return hi_res_scroll_devices[i].microns_per_hi_res_unit;
|
||||||
|
}
|
||||||
|
/* We don't have a value for this device, so use a sensible default. */
|
||||||
|
return 406;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hi_res_scroll_enable(struct hidpp_device *hidpp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u8 multiplier = 8;
|
||||||
|
|
||||||
|
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) {
|
||||||
|
ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
|
||||||
|
hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
|
||||||
|
} else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) {
|
||||||
|
ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true,
|
||||||
|
&multiplier);
|
||||||
|
} else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */
|
||||||
|
ret = hidpp10_enable_scrolling_acceleration(hidpp);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
hidpp->vertical_wheel_counter.resolution_multiplier = multiplier;
|
||||||
|
hidpp->vertical_wheel_counter.microns_per_hi_res_unit =
|
||||||
|
hi_res_scroll_look_up_microns(hidpp->hid_dev->product);
|
||||||
|
hid_info(hidpp->hid_dev, "multiplier = %d, microns = %d\n",
|
||||||
|
multiplier,
|
||||||
|
hidpp->vertical_wheel_counter.microns_per_hi_res_unit);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Generic HID++ devices */
|
/* Generic HID++ devices */
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
@ -2572,6 +2763,11 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
|
||||||
wtp_populate_input(hidpp, input, origin_is_hid_core);
|
wtp_populate_input(hidpp, input, origin_is_hid_core);
|
||||||
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
|
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560)
|
||||||
m560_populate_input(hidpp, input, origin_is_hid_core);
|
m560_populate_input(hidpp, input, origin_is_hid_core);
|
||||||
|
|
||||||
|
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) {
|
||||||
|
input_set_capability(input, EV_REL, REL_WHEEL_HI_RES);
|
||||||
|
hidpp->vertical_wheel_counter.dev = input;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hidpp_input_configured(struct hid_device *hdev,
|
static int hidpp_input_configured(struct hid_device *hdev,
|
||||||
|
@ -2690,6 +2886,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
|
||||||
|
struct hid_usage *usage, __s32 value)
|
||||||
|
{
|
||||||
|
/* This function will only be called for scroll events, due to the
|
||||||
|
* restriction imposed in hidpp_usages.
|
||||||
|
*/
|
||||||
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
|
struct hid_scroll_counter *counter = &hidpp->vertical_wheel_counter;
|
||||||
|
/* A scroll event may occur before the multiplier has been retrieved or
|
||||||
|
* the input device set, or high-res scroll enabling may fail. In such
|
||||||
|
* cases we must return early (falling back to default behaviour) to
|
||||||
|
* avoid a crash in hid_scroll_counter_handle_scroll.
|
||||||
|
*/
|
||||||
|
if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0
|
||||||
|
|| counter->dev == NULL || counter->resolution_multiplier == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hid_scroll_counter_handle_scroll(counter, value);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
static int hidpp_initialize_battery(struct hidpp_device *hidpp)
|
||||||
{
|
{
|
||||||
static atomic_t battery_no = ATOMIC_INIT(0);
|
static atomic_t battery_no = ATOMIC_INIT(0);
|
||||||
|
@ -2901,6 +3118,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
|
||||||
if (hidpp->battery.ps)
|
if (hidpp->battery.ps)
|
||||||
power_supply_changed(hidpp->battery.ps);
|
power_supply_changed(hidpp->battery.ps);
|
||||||
|
|
||||||
|
if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL)
|
||||||
|
hi_res_scroll_enable(hidpp);
|
||||||
|
|
||||||
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input)
|
||||||
/* if the input nodes are already created, we can stop now */
|
/* if the input nodes are already created, we can stop now */
|
||||||
return;
|
return;
|
||||||
|
@ -3086,35 +3306,63 @@ static void hidpp_remove(struct hid_device *hdev)
|
||||||
mutex_destroy(&hidpp->send_mutex);
|
mutex_destroy(&hidpp->send_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LDJ_DEVICE(product) \
|
||||||
|
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \
|
||||||
|
USB_VENDOR_ID_LOGITECH, (product))
|
||||||
|
|
||||||
static const struct hid_device_id hidpp_devices[] = {
|
static const struct hid_device_id hidpp_devices[] = {
|
||||||
{ /* wireless touchpad */
|
{ /* wireless touchpad */
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
LDJ_DEVICE(0x4011),
|
||||||
USB_VENDOR_ID_LOGITECH, 0x4011),
|
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
|
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT |
|
||||||
HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
|
HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS },
|
||||||
{ /* wireless touchpad T650 */
|
{ /* wireless touchpad T650 */
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
LDJ_DEVICE(0x4101),
|
||||||
USB_VENDOR_ID_LOGITECH, 0x4101),
|
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
|
.driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT },
|
||||||
{ /* wireless touchpad T651 */
|
{ /* wireless touchpad T651 */
|
||||||
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,
|
||||||
USB_DEVICE_ID_LOGITECH_T651),
|
USB_DEVICE_ID_LOGITECH_T651),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
.driver_data = HIDPP_QUIRK_CLASS_WTP },
|
||||||
|
{ /* Mouse Logitech Anywhere MX */
|
||||||
|
LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||||
|
{ /* Mouse Logitech Cube */
|
||||||
|
LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||||
|
{ /* Mouse Logitech M335 */
|
||||||
|
LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech M515 */
|
||||||
|
LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||||
{ /* Mouse logitech M560 */
|
{ /* Mouse logitech M560 */
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
LDJ_DEVICE(0x402d),
|
||||||
USB_VENDOR_ID_LOGITECH, 0x402d),
|
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560
|
||||||
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
|
| HIDPP_QUIRK_HI_RES_SCROLL_X2120 },
|
||||||
|
{ /* Mouse Logitech M705 (firmware RQM17) */
|
||||||
|
LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||||
|
{ /* Mouse Logitech M705 (firmware RQM67) */
|
||||||
|
LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech M720 */
|
||||||
|
LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech MX Anywhere 2 */
|
||||||
|
LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech MX Anywhere 2S */
|
||||||
|
LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech MX Master */
|
||||||
|
LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech MX Master 2S */
|
||||||
|
LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 },
|
||||||
|
{ /* Mouse Logitech Performance MX */
|
||||||
|
LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 },
|
||||||
{ /* Keyboard logitech K400 */
|
{ /* Keyboard logitech K400 */
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
LDJ_DEVICE(0x4024),
|
||||||
USB_VENDOR_ID_LOGITECH, 0x4024),
|
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
.driver_data = HIDPP_QUIRK_CLASS_K400 },
|
||||||
{ /* Solar Keyboard Logitech K750 */
|
{ /* Solar Keyboard Logitech K750 */
|
||||||
HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
LDJ_DEVICE(0x4002),
|
||||||
USB_VENDOR_ID_LOGITECH, 0x4002),
|
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_K750 },
|
.driver_data = HIDPP_QUIRK_CLASS_K750 },
|
||||||
|
|
||||||
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
|
{ LDJ_DEVICE(HID_ANY_ID) },
|
||||||
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
|
|
||||||
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
|
||||||
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
.driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
|
||||||
|
@ -3123,12 +3371,19 @@ static const struct hid_device_id hidpp_devices[] = {
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(hid, hidpp_devices);
|
MODULE_DEVICE_TABLE(hid, hidpp_devices);
|
||||||
|
|
||||||
|
static const struct hid_usage_id hidpp_usages[] = {
|
||||||
|
{ HID_GD_WHEEL, EV_REL, REL_WHEEL },
|
||||||
|
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
|
||||||
|
};
|
||||||
|
|
||||||
static struct hid_driver hidpp_driver = {
|
static struct hid_driver hidpp_driver = {
|
||||||
.name = "logitech-hidpp-device",
|
.name = "logitech-hidpp-device",
|
||||||
.id_table = hidpp_devices,
|
.id_table = hidpp_devices,
|
||||||
.probe = hidpp_probe,
|
.probe = hidpp_probe,
|
||||||
.remove = hidpp_remove,
|
.remove = hidpp_remove,
|
||||||
.raw_event = hidpp_raw_event,
|
.raw_event = hidpp_raw_event,
|
||||||
|
.usage_table = hidpp_usages,
|
||||||
|
.event = hidpp_event,
|
||||||
.input_configured = hidpp_input_configured,
|
.input_configured = hidpp_input_configured,
|
||||||
.input_mapping = hidpp_input_mapping,
|
.input_mapping = hidpp_input_mapping,
|
||||||
.input_mapped = hidpp_input_mapped,
|
.input_mapped = hidpp_input_mapped,
|
||||||
|
|
|
@ -1139,6 +1139,34 @@ static inline u32 hid_report_len(struct hid_report *report)
|
||||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
||||||
int interrupt);
|
int interrupt);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct hid_scroll_counter - Utility class for processing high-resolution
|
||||||
|
* scroll events.
|
||||||
|
* @dev: the input device for which events should be reported.
|
||||||
|
* @microns_per_hi_res_unit: the amount moved by the user's finger for each
|
||||||
|
* high-resolution unit reported by the mouse, in
|
||||||
|
* microns.
|
||||||
|
* @resolution_multiplier: the wheel's resolution in high-resolution mode as a
|
||||||
|
* multiple of its lower resolution. For example, if
|
||||||
|
* moving the wheel by one "notch" would result in a
|
||||||
|
* value of 1 in low-resolution mode but 8 in
|
||||||
|
* high-resolution, the multiplier is 8.
|
||||||
|
* @remainder: counts the number of high-resolution units moved since the last
|
||||||
|
* low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
|
||||||
|
* only be used by class methods.
|
||||||
|
*/
|
||||||
|
struct hid_scroll_counter {
|
||||||
|
struct input_dev *dev;
|
||||||
|
int microns_per_hi_res_unit;
|
||||||
|
int resolution_multiplier;
|
||||||
|
|
||||||
|
int remainder;
|
||||||
|
};
|
||||||
|
|
||||||
|
void hid_scroll_counter_handle_scroll(struct hid_scroll_counter *counter,
|
||||||
|
int hi_res_value);
|
||||||
|
|
||||||
/* HID quirks API */
|
/* HID quirks API */
|
||||||
unsigned long hid_lookup_quirk(const struct hid_device *hdev);
|
unsigned long hid_lookup_quirk(const struct hid_device *hdev);
|
||||||
int hid_quirks_init(char **quirks_param, __u16 bus, int count);
|
int hid_quirks_init(char **quirks_param, __u16 bus, int count);
|
||||||
|
|
|
@ -708,6 +708,15 @@
|
||||||
#define REL_DIAL 0x07
|
#define REL_DIAL 0x07
|
||||||
#define REL_WHEEL 0x08
|
#define REL_WHEEL 0x08
|
||||||
#define REL_MISC 0x09
|
#define REL_MISC 0x09
|
||||||
|
/*
|
||||||
|
* 0x0a is reserved and should not be used in input drivers.
|
||||||
|
* It was used by HID as REL_MISC+1 and userspace needs to detect if
|
||||||
|
* the next REL_* event is correct or is just REL_MISC + n.
|
||||||
|
* We define here REL_RESERVED so userspace can rely on it and detect
|
||||||
|
* the situation described above.
|
||||||
|
*/
|
||||||
|
#define REL_RESERVED 0x0a
|
||||||
|
#define REL_WHEEL_HI_RES 0x0b
|
||||||
#define REL_MAX 0x0f
|
#define REL_MAX 0x0f
|
||||||
#define REL_CNT (REL_MAX+1)
|
#define REL_CNT (REL_MAX+1)
|
||||||
|
|
||||||
|
@ -744,6 +753,15 @@
|
||||||
|
|
||||||
#define ABS_MISC 0x28
|
#define ABS_MISC 0x28
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0x2e is reserved and should not be used in input drivers.
|
||||||
|
* It was used by HID as ABS_MISC+6 and userspace needs to detect if
|
||||||
|
* the next ABS_* event is correct or is just ABS_MISC + n.
|
||||||
|
* We define here ABS_RESERVED so userspace can rely on it and detect
|
||||||
|
* the situation described above.
|
||||||
|
*/
|
||||||
|
#define ABS_RESERVED 0x2e
|
||||||
|
|
||||||
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
|
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
|
||||||
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
|
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
|
||||||
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
|
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
|
||||||
|
|
Loading…
Reference in New Issue