Commit 4ea4ed22 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-2023110101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

 - fixes for crashes detected by CONFIG_KUNIT_ALL_TESTS in hid-uclogic
   driver (Jinjie Ruan)

 - HID selftests fixes and improvements (Benjamin Tissoires)

 - probe error handling path fixes in hid-nvidia-shield driver
   (Christophe JAILLET)

 - cleanup of LED handling in hid-nintendo (Martino Fontana)

 - big cleanup of logitech-hidpp probe code (Hans de Goede)

 - Suspend/Resume fix for USB Thinkpad Compact Keyboard (Jamie Lentin)

 - firmware detection improvement for Lenovo cptkbd (Mikhail
   Khvainitski)

 - IRQ shutdown and workqueue initialization fixes for hid-cp2112 driver
   (Danny Kaehn)

 - #ifdef CONFIG_PM removal from HID code (Thomas Weißschuh)

 - other assorted device-ID additions and quirks

* tag 'for-linus-2023110101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (31 commits)
  HID: Add quirk for Dell Pro Wireless Keyboard and Mouse KM5221W
  HID: logitech-hidpp: Stop IO before calling hid_connect()
  HID: logitech-hidpp: Drop HIDPP_QUIRK_UNIFYING
  HID: logitech-hidpp: Drop delayed_work_cb()
  HID: logitech-hidpp: Fix connect event race
  HID: logitech-hidpp: Remove unused connected param from *_connect()
  HID: logitech-hidpp: Remove connected check for non-unifying devices
  HID: logitech-hidpp: Add hidpp_non_unifying_init() helper
  HID: logitech-hidpp: Move hidpp_overwrite_name() to before connect check
  HID: logitech-hidpp: Move g920_get_config() to just before hidpp_ff_init()
  HID: logitech-hidpp: Remove wtp_get_config() call from probe()
  HID: logitech-hidpp: Move get_wireless_feature_index() check to hidpp_connect_event()
  HID: logitech-hidpp: Revert "Don't restart communication if not necessary"
  HID: logitech-hidpp: Don't restart IO, instead defer hid_connect() only
  HID: rmi: remove #ifdef CONFIG_PM
  HID: multitouch: remove #ifdef CONFIG_PM
  HID: usbhid: remove #ifdef CONFIG_PM
  HID: core: remove #ifdef CONFIG_PM from hid_driver
  hid: lenovo: Resend all settings on reset_resume for compact keyboards
  HID: uclogic: Fix a work->entry not empty bug in __queue_work()
  ...
parents 27beb3ca 1372e73a
......@@ -1151,8 +1151,6 @@ static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct cp2112_device *dev = gpiochip_get_data(gc);
INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
if (!dev->gpio_poll) {
dev->gpio_poll = true;
schedule_delayed_work(&dev->gpio_poll_worker, 0);
......@@ -1168,7 +1166,11 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d)
struct cp2112_device *dev = gpiochip_get_data(gc);
cp2112_gpio_irq_mask(d);
cancel_delayed_work_sync(&dev->gpio_poll_worker);
if (!dev->irq_mask) {
dev->gpio_poll = false;
cancel_delayed_work_sync(&dev->gpio_poll_worker);
}
}
static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
......@@ -1307,6 +1309,8 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
girq->handler = handle_simple_irq;
girq->threaded = true;
INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);
ret = gpiochip_add_data(&dev->gc, dev);
if (ret < 0) {
hid_err(hdev, "error registering gpio chip\n");
......
......@@ -366,6 +366,7 @@
#define USB_VENDOR_ID_DELL 0x413c
#define USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE 0x301a
#define USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W 0x4503
#define USB_VENDOR_ID_DELORME 0x1163
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
......
......@@ -51,7 +51,12 @@ struct lenovo_drvdata {
int select_right;
int sensitivity;
int press_speed;
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
/* 0: Up
* 1: Down (undecided)
* 2: Scrolling
* 3: Patched firmware, disable workaround
*/
u8 middlebutton_state;
bool fn_lock;
};
......@@ -521,6 +526,19 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
int ret;
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
/*
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
* regular keys
*/
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
/* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
if (ret)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
if (ret)
hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
......@@ -668,31 +686,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
{
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
/* "wheel" scroll events */
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
usage->code == REL_HWHEEL)) {
/* Scroll events disable middle-click event */
cptkbd_data->middlebutton_state = 2;
return 0;
}
if (cptkbd_data->middlebutton_state != 3) {
/* REL_X and REL_Y events during middle button pressed
* are only possible on patched, bug-free firmware
* so set middlebutton_state to 3
* to never apply workaround anymore
*/
if (cptkbd_data->middlebutton_state == 1 &&
usage->type == EV_REL &&
(usage->code == REL_X || usage->code == REL_Y)) {
cptkbd_data->middlebutton_state = 3;
/* send middle button press which was hold before */
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 1);
input_sync(field->hidinput->input);
}
/* "wheel" scroll events */
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
usage->code == REL_HWHEEL)) {
/* Scroll events disable middle-click event */
cptkbd_data->middlebutton_state = 2;
return 0;
}
/* Middle click events */
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
if (value == 1) {
cptkbd_data->middlebutton_state = 1;
} else if (value == 0) {
if (cptkbd_data->middlebutton_state == 1) {
/* No scrolling inbetween, send middle-click */
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 1);
input_sync(field->hidinput->input);
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 0);
input_sync(field->hidinput->input);
/* Middle click events */
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
if (value == 1) {
cptkbd_data->middlebutton_state = 1;
} else if (value == 0) {
if (cptkbd_data->middlebutton_state == 1) {
/* No scrolling inbetween, send middle-click */
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 1);
input_sync(field->hidinput->input);
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 0);
input_sync(field->hidinput->input);
}
cptkbd_data->middlebutton_state = 0;
}
cptkbd_data->middlebutton_state = 0;
return 1;
}
return 1;
}
if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
......@@ -1126,22 +1161,6 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
}
hid_set_drvdata(hdev, cptkbd_data);
/*
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
* regular keys (Compact only)
*/
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
}
/* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
if (ret)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
/* Set keyboard settings to known state */
cptkbd_data->middlebutton_state = 0;
cptkbd_data->fn_lock = true;
......@@ -1264,6 +1283,24 @@ static int lenovo_probe(struct hid_device *hdev,
return ret;
}
#ifdef CONFIG_PM
static int lenovo_reset_resume(struct hid_device *hdev)
{
switch (hdev->product) {
case USB_DEVICE_ID_LENOVO_CUSBKBD:
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
if (hdev->type == HID_TYPE_USBMOUSE)
lenovo_features_set_cptkbd(hdev);
break;
default:
break;
}
return 0;
}
#endif
static void lenovo_remove_tpkbd(struct hid_device *hdev)
{
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
......@@ -1380,6 +1417,9 @@ static struct hid_driver lenovo_driver = {
.raw_event = lenovo_raw_event,
.event = lenovo_event,
.report_fixup = lenovo_report_fixup,
#ifdef CONFIG_PM
.reset_resume = lenovo_reset_resume,
#endif
};
module_hid_driver(lenovo_driver);
......
This diff is collapsed.
......@@ -1802,7 +1802,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
}
#ifdef CONFIG_PM
static int mt_suspend(struct hid_device *hdev, pm_message_t state)
{
struct mt_device *td = hid_get_drvdata(hdev);
......@@ -1836,7 +1835,6 @@ static int mt_resume(struct hid_device *hdev)
return 0;
}
#endif
static void mt_remove(struct hid_device *hdev)
{
......@@ -2259,10 +2257,8 @@ static struct hid_driver mt_driver = {
.usage_table = mt_grabbed_usages,
.event = mt_event,
.report = mt_report,
#ifdef CONFIG_PM
.suspend = mt_suspend,
.reset_resume = mt_reset_resume,
.resume = mt_resume,
#endif
.suspend = pm_ptr(mt_suspend),
.reset_resume = pm_ptr(mt_reset_resume),
.resume = pm_ptr(mt_resume),
};
module_hid_driver(mt_driver);
......@@ -410,6 +410,18 @@ static const char * const joycon_player_led_names[] = {
LED_FUNCTION_PLAYER4,
};
#define JC_NUM_LEDS ARRAY_SIZE(joycon_player_led_names)
#define JC_NUM_LED_PATTERNS 8
/* Taken from https://www.nintendo.com/my/support/qa/detail/33822 */
static const enum led_brightness joycon_player_led_patterns[JC_NUM_LED_PATTERNS][JC_NUM_LEDS] = {
{ 1, 0, 0, 0 },
{ 1, 1, 0, 0 },
{ 1, 1, 1, 0 },
{ 1, 1, 1, 1 },
{ 1, 0, 0, 1 },
{ 1, 0, 1, 0 },
{ 1, 0, 1, 1 },
{ 0, 1, 1, 0 },
};
/* Each physical controller is associated with a joycon_ctlr struct */
struct joycon_ctlr {
......@@ -699,6 +711,25 @@ static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on)
return joycon_send_subcmd(ctlr, req, 1, HZ/4);
}
static int joycon_set_home_led(struct joycon_ctlr *ctlr, enum led_brightness brightness)
{
struct joycon_subcmd_request *req;
u8 buffer[sizeof(*req) + 5] = { 0 };
u8 *data;
req = (struct joycon_subcmd_request *)buffer;
req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
data = req->data;
data[0] = 0x01;
data[1] = brightness << 4;
data[2] = brightness | (brightness << 4);
data[3] = 0x11;
data[4] = 0x11;
hid_dbg(ctlr->hdev, "setting home led brightness\n");
return joycon_send_subcmd(ctlr, req, 5, HZ/4);
}
static int joycon_request_spi_flash_read(struct joycon_ctlr *ctlr,
u32 start_addr, u8 size, u8 **reply)
{
......@@ -1840,6 +1871,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
return 0;
}
/* Because the subcommand sets all the leds at once, the brightness argument is ignored */
static int joycon_player_led_brightness_set(struct led_classdev *led,
enum led_brightness brightness)
{
......@@ -1849,7 +1881,6 @@ static int joycon_player_led_brightness_set(struct led_classdev *led,
int val = 0;
int i;
int ret;
int num;
ctlr = hid_get_drvdata(hdev);
if (!ctlr) {
......@@ -1857,21 +1888,10 @@ static int joycon_player_led_brightness_set(struct led_classdev *led,
return -ENODEV;
}
/* determine which player led this is */
for (num = 0; num < JC_NUM_LEDS; num++) {
if (&ctlr->leds[num] == led)
break;
}
if (num >= JC_NUM_LEDS)
return -EINVAL;
for (i = 0; i < JC_NUM_LEDS; i++)
val |= ctlr->leds[i].brightness << i;
mutex_lock(&ctlr->output_mutex);
for (i = 0; i < JC_NUM_LEDS; i++) {
if (i == num)
val |= brightness << i;
else
val |= ctlr->leds[i].brightness << i;
}
ret = joycon_set_player_leds(ctlr, 0, val);
mutex_unlock(&ctlr->output_mutex);
......@@ -1884,9 +1904,6 @@ static int joycon_home_led_brightness_set(struct led_classdev *led,
struct device *dev = led->dev->parent;
struct hid_device *hdev = to_hid_device(dev);
struct joycon_ctlr *ctlr;
struct joycon_subcmd_request *req;
u8 buffer[sizeof(*req) + 5] = { 0 };
u8 *data;
int ret;
ctlr = hid_get_drvdata(hdev);
......@@ -1894,43 +1911,35 @@ static int joycon_home_led_brightness_set(struct led_classdev *led,
hid_err(hdev, "No controller data\n");
return -ENODEV;
}
req = (struct joycon_subcmd_request *)buffer;
req->subcmd_id = JC_SUBCMD_SET_HOME_LIGHT;
data = req->data;
data[0] = 0x01;
data[1] = brightness << 4;
data[2] = brightness | (brightness << 4);
data[3] = 0x11;
data[4] = 0x11;
hid_dbg(hdev, "setting home led brightness\n");
mutex_lock(&ctlr->output_mutex);
ret = joycon_send_subcmd(ctlr, req, 5, HZ/4);
ret = joycon_set_home_led(ctlr, brightness);
mutex_unlock(&ctlr->output_mutex);
return ret;
}
static DEFINE_MUTEX(joycon_input_num_mutex);
static DEFINE_SPINLOCK(joycon_input_num_spinlock);
static int joycon_leds_create(struct joycon_ctlr *ctlr)
{
struct hid_device *hdev = ctlr->hdev;
struct device *dev = &hdev->dev;
const char *d_name = dev_name(dev);
struct led_classdev *led;
int led_val = 0;
char *name;
int ret = 0;
int ret;
int i;
static int input_num = 1;
unsigned long flags;
int player_led_pattern;
static int input_num;
/* Set the default controller player leds based on controller number */
mutex_lock(&joycon_input_num_mutex);
mutex_lock(&ctlr->output_mutex);
ret = joycon_set_player_leds(ctlr, 0, 0xF >> (4 - input_num));
if (ret)
hid_warn(ctlr->hdev, "Failed to set leds; ret=%d\n", ret);
mutex_unlock(&ctlr->output_mutex);
/*
* Set the player leds based on controller number
* Because there is no standard concept of "player number", the pattern
* number will simply increase by 1 every time a controller is connected.
*/
spin_lock_irqsave(&joycon_input_num_spinlock, flags);
player_led_pattern = input_num++ % JC_NUM_LED_PATTERNS;
spin_unlock_irqrestore(&joycon_input_num_spinlock, flags);
/* configure the player LEDs */
for (i = 0; i < JC_NUM_LEDS; i++) {
......@@ -1938,31 +1947,37 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
d_name,
"green",
joycon_player_led_names[i]);
if (!name) {
mutex_unlock(&joycon_input_num_mutex);
if (!name)
return -ENOMEM;
}
led = &ctlr->leds[i];
led->name = name;
led->brightness = ((i + 1) <= input_num) ? 1 : 0;
led->brightness = joycon_player_led_patterns[player_led_pattern][i];
led->max_brightness = 1;
led->brightness_set_blocking =
joycon_player_led_brightness_set;
led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
led_val |= joycon_player_led_patterns[player_led_pattern][i] << i;
}
mutex_lock(&ctlr->output_mutex);
ret = joycon_set_player_leds(ctlr, 0, led_val);
mutex_unlock(&ctlr->output_mutex);
if (ret) {
hid_warn(hdev, "Failed to set players LEDs, skipping registration; ret=%d\n", ret);
goto home_led;
}
for (i = 0; i < JC_NUM_LEDS; i++) {
led = &ctlr->leds[i];
ret = devm_led_classdev_register(&hdev->dev, led);
if (ret) {
hid_err(hdev, "Failed registering %s LED\n", led->name);
mutex_unlock(&joycon_input_num_mutex);
hid_err(hdev, "Failed to register player %d LED; ret=%d\n", i + 1, ret);
return ret;
}
}
if (++input_num > 4)
input_num = 1;
mutex_unlock(&joycon_input_num_mutex);
home_led:
/* configure the home LED */
if (jc_type_has_right(ctlr)) {
name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s:%s",
......@@ -1978,16 +1993,20 @@ static int joycon_leds_create(struct joycon_ctlr *ctlr)
led->max_brightness = 0xF;
led->brightness_set_blocking = joycon_home_led_brightness_set;
led->flags = LED_CORE_SUSPENDRESUME | LED_HW_PLUGGABLE;
ret = devm_led_classdev_register(&hdev->dev, led);
/* Set the home LED to 0 as default state */
mutex_lock(&ctlr->output_mutex);
ret = joycon_set_home_led(ctlr, 0);
mutex_unlock(&ctlr->output_mutex);
if (ret) {
hid_err(hdev, "Failed registering home led\n");
return ret;
hid_warn(hdev, "Failed to set home LED, skipping registration; ret=%d\n", ret);
return 0;
}
/* Set the home LED to 0 as default state */
ret = joycon_home_led_brightness_set(led, 0);
ret = devm_led_classdev_register(&hdev->dev, led);
if (ret) {
hid_warn(hdev, "Failed to set home LED default, unregistering home LED");
devm_led_classdev_unregister(&hdev->dev, led);
hid_err(hdev, "Failed to register home LED; ret=%d\n", ret);
return ret;
}
}
......
......@@ -915,6 +915,15 @@ static struct shield_device *thunderstrike_create(struct hid_device *hdev)
return ERR_PTR(ret);
}
static void thunderstrike_destroy(struct thunderstrike *ts)
{
led_classdev_unregister(&ts->led_dev);
power_supply_unregister(ts->base.battery_dev.psy);
if (ts->haptics_dev)
input_unregister_device(ts->haptics_dev);
ida_free(&thunderstrike_ida, ts->id);
}
static int android_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field,
struct hid_usage *usage, unsigned long **bit,
......@@ -1074,11 +1083,7 @@ static int shield_probe(struct hid_device *hdev, const struct hid_device_id *id)
err_stop:
hid_hw_stop(hdev);
err_ts_create:
power_supply_unregister(ts->base.battery_dev.psy);
if (ts->haptics_dev)
input_unregister_device(ts->haptics_dev);
led_classdev_unregister(&ts->led_dev);
ida_free(&thunderstrike_ida, ts->id);
thunderstrike_destroy(ts);
return ret;
}
......@@ -1090,11 +1095,7 @@ static void shield_remove(struct hid_device *hdev)
ts = container_of(dev, struct thunderstrike, base);
hid_hw_close(hdev);
power_supply_unregister(dev->battery_dev.psy);
if (ts->haptics_dev)
input_unregister_device(ts->haptics_dev);
led_classdev_unregister(&ts->led_dev);
ida_free(&thunderstrike_ida, ts->id);
thunderstrike_destroy(ts);
del_timer_sync(&ts->psy_stats_timer);
cancel_work_sync(&ts->hostcmd_req_work);
hid_hw_stop(hdev);
......
......@@ -66,6 +66,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PRO_WIRELESS_KM5221W), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
......
......@@ -436,7 +436,6 @@ static void rmi_report(struct hid_device *hid, struct hid_report *report)
input_sync(field->hidinput->input);
}
#ifdef CONFIG_PM
static int rmi_suspend(struct hid_device *hdev, pm_message_t message)
{
struct rmi_data *data = hid_get_drvdata(hdev);
......@@ -483,7 +482,6 @@ static int rmi_post_resume(struct hid_device *hdev)
hid_hw_close(hdev);
return ret;
}
#endif /* CONFIG_PM */
static int rmi_hid_reset(struct rmi_transport_dev *xport, u16 reset_addr)
{
......@@ -774,11 +772,9 @@ static struct hid_driver rmi_driver = {
.report = rmi_report,
.input_mapping = rmi_input_mapping,
.input_configured = rmi_input_configured,
#ifdef CONFIG_PM
.suspend = rmi_suspend,
.resume = rmi_post_resume,
.reset_resume = rmi_post_resume,
#endif
.suspend = pm_ptr(rmi_suspend),
.resume = pm_ptr(rmi_post_resume),
.reset_resume = pm_ptr(rmi_post_resume),
};
module_hid_driver(rmi_driver);
......
......@@ -56,6 +56,11 @@ static struct uclogic_raw_event_hook_test test_events[] = {
},
};
static void fake_work(struct work_struct *work)
{
}
static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
{
struct uclogic_params p = {0, };
......@@ -77,6 +82,8 @@ static void hid_test_uclogic_exec_event_hook_test(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filter->event);
memcpy(filter->event, &hook_events[n].event[0], filter->size);
INIT_WORK(&filter->work, fake_work);
list_add_tail(&filter->list, &p.event_hooks->list);
}
......
......@@ -174,12 +174,26 @@ static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test)
KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
}
struct fake_device {
unsigned long quirks;
};
static void hid_test_uclogic_params_cleanup_event_hooks(struct kunit *test)
{
int res, n;
struct hid_device *hdev;
struct fake_device *fake_dev;
struct uclogic_params p = {0, };
res = uclogic_params_ugee_v2_init_event_hooks(NULL, &p);
hdev = kunit_kzalloc(test, sizeof(struct hid_device), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hdev);
fake_dev = kunit_kzalloc(test, sizeof(struct fake_device), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_dev);
hid_set_drvdata(hdev, fake_dev);
res = uclogic_params_ugee_v2_init_event_hooks(hdev, &p);
KUNIT_ASSERT_EQ(test, res, 0);
/* Check that the function can be called repeatedly */
......
......@@ -1562,7 +1562,6 @@ static int hid_post_reset(struct usb_interface *intf)
return 0;
}
#ifdef CONFIG_PM
static int hid_resume_common(struct hid_device *hid, bool driver_suspended)
{
int status = 0;
......@@ -1654,8 +1653,6 @@ static int hid_reset_resume(struct usb_interface *intf)
return status;
}
#endif /* CONFIG_PM */
static const struct usb_device_id hid_usb_ids[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_INTERFACE_CLASS_HID },
......@@ -1668,11 +1665,9 @@ static struct usb_driver hid_driver = {
.name = "usbhid",
.probe = usbhid_probe,
.disconnect = usbhid_disconnect,
#ifdef CONFIG_PM
.suspend = hid_suspend,
.resume = hid_resume,
.reset_resume = hid_reset_resume,
#endif
.suspend = pm_ptr(hid_suspend),
.resume = pm_ptr(hid_resume),
.reset_resume = pm_ptr(hid_reset_resume),
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,
......
......@@ -833,11 +833,11 @@ struct hid_driver {
void (*feature_mapping)(struct hid_device *hdev,
struct hid_field *field,
struct hid_usage *usage);
#ifdef CONFIG_PM
int (*suspend)(struct hid_device *hdev, pm_message_t message);
int (*resume)(struct hid_device *hdev);
int (*reset_resume)(struct hid_device *hdev);
#endif
/* private: */
struct device_driver driver;
};
......
......@@ -21,7 +21,9 @@ CXX ?= $(CROSS_COMPILE)g++
HOSTPKG_CONFIG := pkg-config
CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(KHDR_INCLUDES) -I$(OUTPUT)
CFLAGS += -g -O0 -rdynamic -Wall -Werror -I$(OUTPUT)
CFLAGS += -I$(OUTPUT)/tools/include
LDLIBS += -lelf -lz -lrt -lpthread
# Silence some warnings when compiled with clang
......@@ -65,7 +67,6 @@ BPFTOOLDIR := $(TOOLSDIR)/bpf/bpftool
SCRATCH_DIR := $(OUTPUT)/tools
BUILD_DIR := $(SCRATCH_DIR)/build
INCLUDE_DIR := $(SCRATCH_DIR)/include
KHDR_INCLUDES := $(SCRATCH_DIR)/uapi/include
BPFOBJ := $(BUILD_DIR)/libbpf/libbpf.a
ifneq ($(CROSS_COMPILE),)
HOST_BUILD_DIR := $(BUILD_DIR)/host
......@@ -151,9 +152,6 @@ else
$(Q)cp "$(VMLINUX_H)" $@
endif
$(KHDR_INCLUDES)/linux/hid.h: $(top_srcdir)/include/uapi/linux/hid.h
$(MAKE) -C $(top_srcdir) INSTALL_HDR_PATH=$(SCRATCH_DIR)/uapi headers_install
$(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
$(TOOLSDIR)/bpf/resolve_btfids/main.c \
$(TOOLSDIR)/lib/rbtree.c \
......@@ -231,7 +229,7 @@ $(BPF_SKELS): %.skel.h: %.bpf.o $(BPFTOOL) | $(OUTPUT)
$(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $<
$(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@
$(OUTPUT)/%.o: %.c $(BPF_SKELS) $(KHDR_INCLUDES)/linux/hid.h
$(OUTPUT)/%.o: %.c $(BPF_SKELS)
$(call msg,CC,,$@)
$(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Red hat */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include "hid_bpf_helpers.h"
char _license[] SEC("license") = "GPL";
......
......@@ -5,6 +5,83 @@
#ifndef __HID_BPF_HELPERS_H
#define __HID_BPF_HELPERS_H
/* "undefine" structs and enums in vmlinux.h, because we "override" them below */
#define hid_bpf_ctx hid_bpf_ctx___not_used
#define hid_report_type hid_report_type___not_used
#define hid_class_request hid_class_request___not_used
#define hid_bpf_attach_flags hid_bpf_attach_flags___not_used
#define HID_INPUT_REPORT HID_INPUT_REPORT___not_used
#define HID_OUTPUT_REPORT HID_OUTPUT_REPORT___not_used
#define HID_FEATURE_REPORT HID_FEATURE_REPORT___not_used
#define HID_REPORT_TYPES HID_REPORT_TYPES___not_used
#define HID_REQ_GET_REPORT HID_REQ_GET_REPORT___not_used
#define HID_REQ_GET_IDLE HID_REQ_GET_IDLE___not_used
#define HID_REQ_GET_PROTOCOL HID_REQ_GET_PROTOCOL___not_used
#define HID_REQ_SET_REPORT HID_REQ_SET_REPORT___not_used
#define HID_REQ_SET_IDLE HID_REQ_SET_IDLE___not_used
#define HID_REQ_SET_PROTOCOL HID_REQ_SET_PROTOCOL___not_used
#define HID_BPF_FLAG_NONE HID_BPF_FLAG_NONE___not_used
#define HID_BPF_FLAG_INSERT_HEAD HID_BPF_FLAG_INSERT_HEAD___not_used
#define HID_BPF_FLAG_MAX HID_BPF_FLAG_MAX___not_used
#include "vmlinux.h"
#undef hid_bpf_ctx
#undef hid_report_type
#undef hid_class_request
#undef hid_bpf_attach_flags
#undef HID_INPUT_REPORT
#undef HID_OUTPUT_REPORT
#undef HID_FEATURE_REPORT
#undef HID_REPORT_TYPES
#undef HID_REQ_GET_REPORT
#undef HID_REQ_GET_IDLE
#undef HID_REQ_GET_PROTOCOL
#undef HID_REQ_SET_REPORT
#undef HID_REQ_SET_IDLE
#undef HID_REQ_SET_PROTOCOL
#undef HID_BPF_FLAG_NONE
#undef HID_BPF_FLAG_INSERT_HEAD
#undef HID_BPF_FLAG_MAX
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <linux/const.h>
enum hid_report_type {
HID_INPUT_REPORT = 0,
HID_OUTPUT_REPORT = 1,
HID_FEATURE_REPORT = 2,
HID_REPORT_TYPES,
};
struct hid_bpf_ctx {
__u32 index;
const struct hid_device *hid;
__u32 allocated_size;
enum hid_report_type report_type;
union {
__s32 retval;
__s32 size;
};
} __attribute__((preserve_access_index));
enum hid_class_request {
HID_REQ_GET_REPORT = 0x01,
HID_REQ_GET_IDLE = 0x02,
HID_REQ_GET_PROTOCOL = 0x03,
HID_REQ_SET_REPORT = 0x09,
HID_REQ_SET_IDLE = 0x0A,
HID_REQ_SET_PROTOCOL = 0x0B,
};
enum hid_bpf_attach_flags {
HID_BPF_FLAG_NONE = 0,
HID_BPF_FLAG_INSERT_HEAD = _BITUL(0),
HID_BPF_FLAG_MAX,
};
/* following are kfuncs exported by HID for HID-BPF */
extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
unsigned int offset,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment