1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

hid-for-linus-2025030501

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEL65usyKPHcrRDEicpmLzj2vtYEkFAmfIU/YACgkQpmLzj2vt
 YElabBAApth4hmsxhJSlClPw5py3rK2vFnPBj4wtxbClar8vzV6c/DUqdGIZe1+I
 FvNvS+G3fyA5XvwU8cTwObjtj0nIiYhFxpcpJ6taIZtzoru/UqkLjbNTE9gX2QAL
 yPrHQv6KIM5u99hMVYabZkjI4NoI0pQXcdTJrb1hInwcV6WTjzGIGnZ31NKda3nw
 PwKebdqK4wEUG6Ctp9f4TN2qpiNlJJHAsrbQjusRG4eaNTRHFUxqfg2xek8DCT3w
 ABV/oI/XmR1Fptx8KbGo5RW2Ird9CpnfA1VAPu1SYq7foztpnxGzoOdolh1bqxGl
 30U8+r2y9cQSg1B00EbBcXh4+Ncg8KeoX0skES8mBI+js5uskvhq7n07h06MnTRA
 2skf9BUsF3+zG+OtxhS8dqvN/MupW89hTmpfT7yOi2JSgoDLyNZXHaeBXhjil2Im
 KFgYdYxv9oM95nsuQtqJTHQfHjay3UPFchG3HcCmzwiQLq+wKPb/25Mh0FvNT65z
 yIB3jqpPgckhylCsUitrZHgXhtX9v1roa9360nbkn0NShDJRXnMP2pWnjd6WKUBz
 fFwTdtDMLHIv6EMADmLuefIp/LT11EAgOMIDzOfZqdXPmvgfkWPoq1W8xV/85ug2
 fbdNbs5fGxsW9/PxZkbC4e/iEOswWiDKFl7yHVlEsN3KDd6wWjs=
 =B3rd
 -----END PGP SIGNATURE-----

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

Pull HID fixes from Jiri Kosina:

 - power management fix in intel-thc-hid (Even Xu)

 - nintendo gencon mapping fix (Ryan McClelland)

 - fix for UAF on device diconnect path in hid-steam (Vicki Pfau)

 - two fixes for UAF on device disconnect path in intel-ish-hid (Zhang
   Lixu)

 - fix for potential NULL dereference in hid-appleir (Daniil Dulov)

 - few other small cosmetic fixes (e.g. typos)

* tag 'hid-for-linus-2025030501' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: Intel-thc-hid: Intel-quickspi: Correct device state after S4
  HID: intel-thc-hid: Fix spelling mistake "intput" -> "input"
  HID: hid-steam: Fix use-after-free when detaching device
  HID: debug: Fix spelling mistake "Messanger" -> "Messenger"
  HID: appleir: Fix potential NULL dereference at raw event handle
  HID: apple: disable Fn key handling on the Omoton KB066
  HID: i2c-hid: improve i2c_hid_get_report error message
  HID: intel-ish-hid: Fix use-after-free issue in ishtp_hid_remove()
  HID: intel-ish-hid: Fix use-after-free issue in hid_ishtp_cl_remove()
  HID: google: fix unused variable warning under !CONFIG_ACPI
  HID: nintendo: fix gencon button events map
  HID: corsair-void: Update power supply values with a unified work handler
This commit is contained in:
Linus Torvalds 2025-03-05 07:46:59 -10:00
commit 848e076317
12 changed files with 70 additions and 58 deletions

View file

@ -378,6 +378,12 @@ static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
return false; return false;
} }
static bool apple_is_omoton_kb066(struct hid_device *hdev)
{
return hdev->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI &&
strcmp(hdev->name, "Bluetooth Keyboard") == 0;
}
static inline void apple_setup_key_translation(struct input_dev *input, static inline void apple_setup_key_translation(struct input_dev *input,
const struct apple_key_translation *table) const struct apple_key_translation *table)
{ {
@ -546,9 +552,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
} }
} }
if (usage->hid == 0xc0301) /* Omoton KB066 quirk */
code = KEY_F6;
if (usage->code != code) { if (usage->code != code) {
input_event_with_scancode(input, usage->type, code, usage->hid, value); input_event_with_scancode(input, usage->type, code, usage->hid, value);
@ -728,7 +731,7 @@ static int apple_input_configured(struct hid_device *hdev,
{ {
struct apple_sc *asc = hid_get_drvdata(hdev); struct apple_sc *asc = hid_get_drvdata(hdev);
if ((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) { if (((asc->quirks & APPLE_HAS_FN) && !asc->fn_found) || apple_is_omoton_kb066(hdev)) {
hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n"); hid_info(hdev, "Fn key not found (Apple Wireless Keyboard clone?), disabling Fn key handling\n");
asc->quirks &= ~APPLE_HAS_FN; asc->quirks &= ~APPLE_HAS_FN;
} }

View file

@ -188,7 +188,7 @@ static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 }; static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
unsigned long flags; unsigned long flags;
if (len != 5) if (len != 5 || !(hid->claimed & HID_CLAIMED_INPUT))
goto out; goto out;
if (!memcmp(data, keydown, sizeof(keydown))) { if (!memcmp(data, keydown, sizeof(keydown))) {

View file

@ -71,11 +71,9 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
@ -120,6 +118,12 @@ enum {
CORSAIR_VOID_BATTERY_CHARGING = 5, CORSAIR_VOID_BATTERY_CHARGING = 5,
}; };
enum {
CORSAIR_VOID_ADD_BATTERY = 0,
CORSAIR_VOID_REMOVE_BATTERY = 1,
CORSAIR_VOID_UPDATE_BATTERY = 2,
};
static enum power_supply_property corsair_void_battery_props[] = { static enum power_supply_property corsair_void_battery_props[] = {
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_PRESENT,
@ -155,12 +159,12 @@ struct corsair_void_drvdata {
struct power_supply *battery; struct power_supply *battery;
struct power_supply_desc battery_desc; struct power_supply_desc battery_desc;
struct mutex battery_mutex;
struct delayed_work delayed_status_work; struct delayed_work delayed_status_work;
struct delayed_work delayed_firmware_work; struct delayed_work delayed_firmware_work;
struct work_struct battery_remove_work;
struct work_struct battery_add_work; unsigned long battery_work_flags;
struct work_struct battery_work;
}; };
/* /*
@ -260,11 +264,9 @@ success:
/* Inform power supply if battery values changed */ /* Inform power supply if battery values changed */
if (memcmp(&orig_battery_data, battery_data, sizeof(*battery_data))) { if (memcmp(&orig_battery_data, battery_data, sizeof(*battery_data))) {
scoped_guard(mutex, &drvdata->battery_mutex) { set_bit(CORSAIR_VOID_UPDATE_BATTERY,
if (drvdata->battery) { &drvdata->battery_work_flags);
power_supply_changed(drvdata->battery); schedule_work(&drvdata->battery_work);
}
}
} }
} }
@ -536,29 +538,11 @@ static void corsair_void_firmware_work_handler(struct work_struct *work)
} }
static void corsair_void_battery_remove_work_handler(struct work_struct *work) static void corsair_void_add_battery(struct corsair_void_drvdata *drvdata)
{ {
struct corsair_void_drvdata *drvdata;
drvdata = container_of(work, struct corsair_void_drvdata,
battery_remove_work);
scoped_guard(mutex, &drvdata->battery_mutex) {
if (drvdata->battery) {
power_supply_unregister(drvdata->battery);
drvdata->battery = NULL;
}
}
}
static void corsair_void_battery_add_work_handler(struct work_struct *work)
{
struct corsair_void_drvdata *drvdata;
struct power_supply_config psy_cfg = {}; struct power_supply_config psy_cfg = {};
struct power_supply *new_supply; struct power_supply *new_supply;
drvdata = container_of(work, struct corsair_void_drvdata,
battery_add_work);
guard(mutex)(&drvdata->battery_mutex);
if (drvdata->battery) if (drvdata->battery)
return; return;
@ -583,16 +567,42 @@ static void corsair_void_battery_add_work_handler(struct work_struct *work)
drvdata->battery = new_supply; drvdata->battery = new_supply;
} }
static void corsair_void_battery_work_handler(struct work_struct *work)
{
struct corsair_void_drvdata *drvdata = container_of(work,
struct corsair_void_drvdata, battery_work);
bool add_battery = test_and_clear_bit(CORSAIR_VOID_ADD_BATTERY,
&drvdata->battery_work_flags);
bool remove_battery = test_and_clear_bit(CORSAIR_VOID_REMOVE_BATTERY,
&drvdata->battery_work_flags);
bool update_battery = test_and_clear_bit(CORSAIR_VOID_UPDATE_BATTERY,
&drvdata->battery_work_flags);
if (add_battery && !remove_battery) {
corsair_void_add_battery(drvdata);
} else if (remove_battery && !add_battery && drvdata->battery) {
power_supply_unregister(drvdata->battery);
drvdata->battery = NULL;
}
if (update_battery && drvdata->battery)
power_supply_changed(drvdata->battery);
}
static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata) static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata)
{ {
schedule_work(&drvdata->battery_add_work); set_bit(CORSAIR_VOID_ADD_BATTERY, &drvdata->battery_work_flags);
schedule_work(&drvdata->battery_work);
schedule_delayed_work(&drvdata->delayed_firmware_work, schedule_delayed_work(&drvdata->delayed_firmware_work,
msecs_to_jiffies(100)); msecs_to_jiffies(100));
} }
static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata) static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata)
{ {
schedule_work(&drvdata->battery_remove_work); set_bit(CORSAIR_VOID_REMOVE_BATTERY, &drvdata->battery_work_flags);
schedule_work(&drvdata->battery_work);
corsair_void_set_unknown_wireless_data(drvdata); corsair_void_set_unknown_wireless_data(drvdata);
corsair_void_set_unknown_batt(drvdata); corsair_void_set_unknown_batt(drvdata);
@ -678,13 +688,7 @@ static int corsair_void_probe(struct hid_device *hid_dev,
drvdata->battery_desc.get_property = corsair_void_battery_get_property; drvdata->battery_desc.get_property = corsair_void_battery_get_property;
drvdata->battery = NULL; drvdata->battery = NULL;
INIT_WORK(&drvdata->battery_remove_work, INIT_WORK(&drvdata->battery_work, corsair_void_battery_work_handler);
corsair_void_battery_remove_work_handler);
INIT_WORK(&drvdata->battery_add_work,
corsair_void_battery_add_work_handler);
ret = devm_mutex_init(drvdata->dev, &drvdata->battery_mutex);
if (ret)
return ret;
ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group); ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group);
if (ret) if (ret)
@ -721,8 +725,7 @@ static void corsair_void_remove(struct hid_device *hid_dev)
struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev);
hid_hw_stop(hid_dev); hid_hw_stop(hid_dev);
cancel_work_sync(&drvdata->battery_remove_work); cancel_work_sync(&drvdata->battery_work);
cancel_work_sync(&drvdata->battery_add_work);
if (drvdata->battery) if (drvdata->battery)
power_supply_unregister(drvdata->battery); power_supply_unregister(drvdata->battery);

View file

@ -3450,7 +3450,7 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_MACRO_RECORD_START] = "MacroRecordStart", [KEY_MACRO_RECORD_START] = "MacroRecordStart",
[KEY_MACRO_RECORD_STOP] = "MacroRecordStop", [KEY_MACRO_RECORD_STOP] = "MacroRecordStop",
[KEY_MARK_WAYPOINT] = "MarkWayPoint", [KEY_MEDIA_REPEAT] = "MediaRepeat", [KEY_MARK_WAYPOINT] = "MarkWayPoint", [KEY_MEDIA_REPEAT] = "MediaRepeat",
[KEY_MEDIA_TOP_MENU] = "MediaTopMenu", [KEY_MESSENGER] = "Messanger", [KEY_MEDIA_TOP_MENU] = "MediaTopMenu", [KEY_MESSENGER] = "Messenger",
[KEY_NAV_CHART] = "NavChar", [KEY_NAV_INFO] = "NavInfo", [KEY_NAV_CHART] = "NavChar", [KEY_NAV_INFO] = "NavInfo",
[KEY_NEWS] = "News", [KEY_NEXT_ELEMENT] = "NextElement", [KEY_NEWS] = "News", [KEY_NEXT_ELEMENT] = "NextElement",
[KEY_NEXT_FAVORITE] = "NextFavorite", [KEY_NOTIFICATION_CENTER] = "NotificationCenter", [KEY_NEXT_FAVORITE] = "NextFavorite", [KEY_NOTIFICATION_CENTER] = "NotificationCenter",

View file

@ -268,11 +268,13 @@ static void cbas_ec_remove(struct platform_device *pdev)
mutex_unlock(&cbas_ec_reglock); mutex_unlock(&cbas_ec_reglock);
} }
#ifdef CONFIG_ACPI
static const struct acpi_device_id cbas_ec_acpi_ids[] = { static const struct acpi_device_id cbas_ec_acpi_ids[] = {
{ "GOOG000B", 0 }, { "GOOG000B", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids); MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids);
#endif
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id cbas_ec_of_match[] = { static const struct of_device_id cbas_ec_of_match[] = {

View file

@ -457,13 +457,13 @@ static const struct joycon_ctlr_button_mapping snescon_button_mappings[] = {
}; };
static const struct joycon_ctlr_button_mapping gencon_button_mappings[] = { static const struct joycon_ctlr_button_mapping gencon_button_mappings[] = {
{ BTN_A, JC_BTN_A, }, { BTN_WEST, JC_BTN_A, }, /* A */
{ BTN_B, JC_BTN_B, }, { BTN_SOUTH, JC_BTN_B, }, /* B */
{ BTN_C, JC_BTN_R, }, { BTN_EAST, JC_BTN_R, }, /* C */
{ BTN_X, JC_BTN_X, }, /* MD/GEN 6B Only */ { BTN_TL, JC_BTN_X, }, /* X MD/GEN 6B Only */
{ BTN_Y, JC_BTN_Y, }, /* MD/GEN 6B Only */ { BTN_NORTH, JC_BTN_Y, }, /* Y MD/GEN 6B Only */
{ BTN_Z, JC_BTN_L, }, /* MD/GEN 6B Only */ { BTN_TR, JC_BTN_L, }, /* Z MD/GEN 6B Only */
{ BTN_SELECT, JC_BTN_ZR, }, { BTN_SELECT, JC_BTN_ZR, }, /* Mode */
{ BTN_START, JC_BTN_PLUS, }, { BTN_START, JC_BTN_PLUS, },
{ BTN_MODE, JC_BTN_HOME, }, { BTN_MODE, JC_BTN_HOME, },
{ BTN_Z, JC_BTN_CAP, }, { BTN_Z, JC_BTN_CAP, },

View file

@ -1327,11 +1327,11 @@ static void steam_remove(struct hid_device *hdev)
return; return;
} }
hid_destroy_device(steam->client_hdev);
cancel_delayed_work_sync(&steam->mode_switch); cancel_delayed_work_sync(&steam->mode_switch);
cancel_work_sync(&steam->work_connect); cancel_work_sync(&steam->work_connect);
cancel_work_sync(&steam->rumble_work); cancel_work_sync(&steam->rumble_work);
cancel_work_sync(&steam->unregister_work); cancel_work_sync(&steam->unregister_work);
hid_destroy_device(steam->client_hdev);
steam->client_hdev = NULL; steam->client_hdev = NULL;
steam->client_opened = 0; steam->client_opened = 0;
if (steam->quirks & STEAM_QUIRK_WIRELESS) { if (steam->quirks & STEAM_QUIRK_WIRELESS) {

View file

@ -290,7 +290,7 @@ static int i2c_hid_get_report(struct i2c_hid *ihid,
ihid->rawbuf, recv_len + sizeof(__le16)); ihid->rawbuf, recv_len + sizeof(__le16));
if (error) { if (error) {
dev_err(&ihid->client->dev, dev_err(&ihid->client->dev,
"failed to set a report to device: %d\n", error); "failed to get a report from device: %d\n", error);
return error; return error;
} }

View file

@ -832,9 +832,9 @@ static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
hid_ishtp_cl); hid_ishtp_cl);
dev_dbg(ishtp_device(cl_device), "%s\n", __func__); dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
hid_ishtp_cl_deinit(hid_ishtp_cl);
ishtp_put_device(cl_device); ishtp_put_device(cl_device);
ishtp_hid_remove(client_data); ishtp_hid_remove(client_data);
hid_ishtp_cl_deinit(hid_ishtp_cl);
hid_ishtp_cl = NULL; hid_ishtp_cl = NULL;

View file

@ -261,12 +261,14 @@ err_hid_data:
*/ */
void ishtp_hid_remove(struct ishtp_cl_data *client_data) void ishtp_hid_remove(struct ishtp_cl_data *client_data)
{ {
void *data;
int i; int i;
for (i = 0; i < client_data->num_hid_devices; ++i) { for (i = 0; i < client_data->num_hid_devices; ++i) {
if (client_data->hid_sensor_hubs[i]) { if (client_data->hid_sensor_hubs[i]) {
kfree(client_data->hid_sensor_hubs[i]->driver_data); data = client_data->hid_sensor_hubs[i]->driver_data;
hid_destroy_device(client_data->hid_sensor_hubs[i]); hid_destroy_device(client_data->hid_sensor_hubs[i]);
kfree(data);
client_data->hid_sensor_hubs[i] = NULL; client_data->hid_sensor_hubs[i] = NULL;
} }
} }

View file

@ -909,6 +909,8 @@ static int quickspi_restore(struct device *device)
thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE); thc_change_ltr_mode(qsdev->thc_hw, THC_LTR_MODE_ACTIVE);
qsdev->state = QUICKSPI_ENABLED;
return 0; return 0;
} }

View file

@ -107,7 +107,7 @@ static int quickspi_get_device_descriptor(struct quickspi_device *qsdev)
return 0; return 0;
} }
dev_err_once(qsdev->dev, "Unexpected intput report type: %d\n", input_rep_type); dev_err_once(qsdev->dev, "Unexpected input report type: %d\n", input_rep_type);
return -EINVAL; return -EINVAL;
} }