// SPDX-License-Identifier: GPL-2.0-or-later
/*
* HID driver for Lenovo:
* - ThinkPad USB Keyboard with TrackPoint (tpkbd)
* - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
* - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
* - ThinkPad TrackPoint Keyboard II USB/Bluetooth (cptkbd/tpIIkbd)
*
* Copyright (c) 2012 Bernhard Seibold
* Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
*
* Linux IBM/Lenovo Scrollpoint mouse driver:
* - IBM Scrollpoint III
* - IBM Scrollpoint Pro
* - IBM Scrollpoint Optical
* - IBM Scrollpoint Optical 800dpi
* - IBM Scrollpoint Optical 800dpi Pro
* - Lenovo Scrollpoint Optical
*
* Copyright (c) 2012 Peter De Wachter <pdewacht@gmail.com>
* Copyright (c) 2018 Peter Ganzhorn <peter.ganzhorn@gmail.com>
*/
/*
*/
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#include "hid-ids.h"
/* Userspace expects F20 for mic-mute KEY_MICMUTE does not work */
#define LENOVO_KEY_MICMUTE KEY_F20
struct lenovo_drvdata {
u8 led_report[3]; /* Must be first for proper alignment */
int led_state;
struct mutex led_report_mutex;
struct led_classdev led_mute;
struct led_classdev led_micmute;
struct work_struct fn_lock_sync_work;
struct hid_device *hdev;
int press_to_select;
int dragging;
int release_to_select;
int select_right;
int sensitivity;
int press_speed;
/* 0: Up
* 1: Down (undecided)
* 2: Scrolling
* 3: Patched firmware, disable workaround
*/
u8 middlebutton_state;
bool fn_lock;
};
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
#define TP10UBKBD_LED_OUTPUT_REPORT 9
#define TP10UBKBD_FN_LOCK_LED 0x54
#define TP10UBKBD_MUTE_LED 0x64
#define TP10UBKBD_MICMUTE_LED 0x74
#define TP10UBKBD_LED_OFF 1
#define TP10UBKBD_LED_ON 2
static int lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
enum led_brightness value)
{
struct lenovo_drvdata *data = hid_get_drvdata(hdev);
int ret;
mutex_lock(&data->led_report_mutex);
data->led_report[0] = TP10UBKBD_LED_OUTPUT_REPORT;
data->led_report[1] = led_code;
data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF;
ret = hid_hw_raw_request