Merge tag 'hid-for-linus-2025062701' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID fixes from Jiri Kosina: - fix for stalls during suspend/resume cycles with hid-nintendo (Daniel J. Ogorchock) - memory leak and reference count fixes in hid-wacom and in-appletb-kdb (Qasim Ijaz) - race condition (leading to kernel crash) fix during device removal in hid-wacom (Thomas Zeitlhofer) - fix for missed interrupt in intel-thc-hid (Intel-thc-hid:) - support for a bunch of new device IDs * tag 'hid-for-linus-2025062701' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: HID: lenovo: Add support for ThinkPad X1 Tablet Thin Keyboard Gen2 HID: appletb-kbd: fix "appletb_backlight" backlight device reference counting HID: wacom: fix crash in wacom_aes_battery_handler() HID: intel-ish-hid: ipc: Add Wildcat Lake PCI device ID hid: intel-ish-hid: Use PCI_DEVICE_DATA() macro for ISH device table HID: lenovo: Restrict F7/9/11 mode to compact keyboards only HID: Add IGNORE quirk for SMARTLINKTECHNOLOGY HID: input: lower message severity of 'No inputs registered, leaving' to debug HID: quirks: Add quirk for 2 Chicony Electronics HP 5MP Cameras HID: Intel-thc-hid: Intel-quicki2c: Enhance QuickI2C reset flow HID: nintendo: avoid bluetooth suspend/resume stalls HID: wacom: fix kobject reference count leak HID: wacom: fix memory leak on sysfs attribute creation failure HID: wacom: fix memory leak on kobject creation failure
This commit is contained in:
@@ -438,6 +438,8 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
|
||||
return 0;
|
||||
|
||||
close_hw:
|
||||
if (kbd->backlight_dev)
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
hid_hw_close(hdev);
|
||||
stop_hw:
|
||||
hid_hw_stop(hdev);
|
||||
@@ -453,6 +455,9 @@ static void appletb_kbd_remove(struct hid_device *hdev)
|
||||
input_unregister_handler(&kbd->inp_handler);
|
||||
timer_delete_sync(&kbd->inactivity_timer);
|
||||
|
||||
if (kbd->backlight_dev)
|
||||
put_device(&kbd->backlight_dev->dev);
|
||||
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
@@ -312,6 +312,8 @@
|
||||
#define USB_DEVICE_ID_ASUS_AK1D 0x1125
|
||||
#define USB_DEVICE_ID_CHICONY_TOSHIBA_WT10A 0x1408
|
||||
#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421
|
||||
#define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA 0xb824
|
||||
#define USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2 0xb82c
|
||||
|
||||
#define USB_VENDOR_ID_CHUNGHWAT 0x2247
|
||||
#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001
|
||||
@@ -819,6 +821,7 @@
|
||||
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
|
||||
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
|
||||
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
|
||||
#define USB_DEVICE_ID_LENOVO_X1_TAB2 0x60a4
|
||||
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
|
||||
#define USB_DEVICE_ID_LENOVO_X12_TAB 0x60fe
|
||||
#define USB_DEVICE_ID_LENOVO_X12_TAB2 0x61ae
|
||||
@@ -1525,4 +1528,7 @@
|
||||
#define USB_VENDOR_ID_SIGNOTEC 0x2133
|
||||
#define USB_DEVICE_ID_SIGNOTEC_VIEWSONIC_PD1011 0x0018
|
||||
|
||||
#define USB_VENDOR_ID_SMARTLINKTECHNOLOGY 0x4c4a
|
||||
#define USB_DEVICE_ID_SMARTLINKTECHNOLOGY_4155 0x4155
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2343,7 +2343,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
|
||||
}
|
||||
|
||||
if (list_empty(&hid->inputs)) {
|
||||
hid_err(hid, "No inputs registered, leaving\n");
|
||||
hid_dbg(hid, "No inputs registered, leaving\n");
|
||||
goto out_unwind;
|
||||
}
|
||||
|
||||
|
||||
@@ -492,6 +492,7 @@ static int lenovo_input_mapping(struct hid_device *hdev,
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
return lenovo_input_mapping_x1_tab_kbd(hdev, hi, field, usage, bit, max);
|
||||
default:
|
||||
@@ -548,11 +549,14 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
|
||||
|
||||
/*
|
||||
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
|
||||
* regular keys
|
||||
* regular keys (Compact only)
|
||||
*/
|
||||
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
|
||||
if (ret)
|
||||
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
|
||||
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);
|
||||
@@ -605,6 +609,7 @@ static ssize_t attr_fn_lock_store(struct device *dev,
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, TP10UBKBD_FN_LOCK_LED, value);
|
||||
if (ret)
|
||||
@@ -861,6 +866,7 @@ static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
return lenovo_event_tp10ubkbd(hdev, field, usage, value);
|
||||
default:
|
||||
@@ -1144,6 +1150,7 @@ static int lenovo_led_brightness_set(struct led_classdev *led_cdev,
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
|
||||
break;
|
||||
@@ -1384,6 +1391,7 @@ static int lenovo_probe(struct hid_device *hdev,
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
ret = lenovo_probe_tp10ubkbd(hdev);
|
||||
break;
|
||||
@@ -1473,6 +1481,7 @@ static void lenovo_remove(struct hid_device *hdev)
|
||||
case USB_DEVICE_ID_LENOVO_X12_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_TP10UBKBD:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB2:
|
||||
case USB_DEVICE_ID_LENOVO_X1_TAB3:
|
||||
lenovo_remove_tp10ubkbd(hdev);
|
||||
break;
|
||||
@@ -1523,6 +1532,8 @@ static const struct hid_device_id lenovo_devices[] = {
|
||||
*/
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB2) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_TAB3) },
|
||||
{ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
|
||||
|
||||
@@ -2132,12 +2132,18 @@ static const struct hid_device_id mt_devices[] = {
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_GENERIC,
|
||||
USB_VENDOR_ID_LG, I2C_DEVICE_ID_LG_7010) },
|
||||
|
||||
/* Lenovo X1 TAB Gen 2 */
|
||||
/* Lenovo X1 TAB Gen 1 */
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_LENOVO,
|
||||
USB_DEVICE_ID_LENOVO_X1_TAB) },
|
||||
|
||||
/* Lenovo X1 TAB Gen 2 */
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_LENOVO,
|
||||
USB_DEVICE_ID_LENOVO_X1_TAB2) },
|
||||
|
||||
/* Lenovo X1 TAB Gen 3 */
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
|
||||
@@ -308,6 +308,7 @@ enum joycon_ctlr_state {
|
||||
JOYCON_CTLR_STATE_INIT,
|
||||
JOYCON_CTLR_STATE_READ,
|
||||
JOYCON_CTLR_STATE_REMOVED,
|
||||
JOYCON_CTLR_STATE_SUSPENDED,
|
||||
};
|
||||
|
||||
/* Controller type received as part of device info */
|
||||
@@ -2750,14 +2751,46 @@ static void nintendo_hid_remove(struct hid_device *hdev)
|
||||
|
||||
static int nintendo_hid_resume(struct hid_device *hdev)
|
||||
{
|
||||
int ret = joycon_init(hdev);
|
||||
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
|
||||
int ret;
|
||||
|
||||
hid_dbg(hdev, "resume\n");
|
||||
if (!joycon_using_usb(ctlr)) {
|
||||
hid_dbg(hdev, "no-op resume for bt ctlr\n");
|
||||
ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = joycon_init(hdev);
|
||||
if (ret)
|
||||
hid_err(hdev, "Failed to restore controller after resume");
|
||||
hid_err(hdev,
|
||||
"Failed to restore controller after resume: %d\n",
|
||||
ret);
|
||||
else
|
||||
ctlr->ctlr_state = JOYCON_CTLR_STATE_READ;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nintendo_hid_suspend(struct hid_device *hdev, pm_message_t message)
|
||||
{
|
||||
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
|
||||
|
||||
hid_dbg(hdev, "suspend: %d\n", message.event);
|
||||
/*
|
||||
* Avoid any blocking loops in suspend/resume transitions.
|
||||
*
|
||||
* joycon_enforce_subcmd_rate() can result in repeated retries if for
|
||||
* whatever reason the controller stops providing input reports.
|
||||
*
|
||||
* This has been observed with bluetooth controllers which lose
|
||||
* connectivity prior to suspend (but not long enough to result in
|
||||
* complete disconnection).
|
||||
*/
|
||||
ctlr->ctlr_state = JOYCON_CTLR_STATE_SUSPENDED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct hid_device_id nintendo_hid_devices[] = {
|
||||
@@ -2796,6 +2829,7 @@ static struct hid_driver nintendo_hid_driver = {
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
.resume = nintendo_hid_resume,
|
||||
.suspend = nintendo_hid_suspend,
|
||||
#endif
|
||||
};
|
||||
static int __init nintendo_init(void)
|
||||
|
||||
@@ -757,6 +757,8 @@ static const struct hid_device_id hid_ignore_list[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_HP_5MP_CAMERA2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },
|
||||
@@ -904,6 +906,7 @@ static const struct hid_device_id hid_ignore_list[] = {
|
||||
#endif
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_HP_5MP_CAMERA_5473) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SMARTLINKTECHNOLOGY, USB_DEVICE_ID_SMARTLINKTECHNOLOGY_4155) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_ISH_LNL_M 0xA845
|
||||
#define PCI_DEVICE_ID_INTEL_ISH_PTL_H 0xE345
|
||||
#define PCI_DEVICE_ID_INTEL_ISH_PTL_P 0xE445
|
||||
#define PCI_DEVICE_ID_INTEL_ISH_WCL 0x4D45
|
||||
|
||||
#define REVISION_ID_CHT_A0 0x6
|
||||
#define REVISION_ID_CHT_Ax_SI 0x0
|
||||
|
||||
@@ -27,10 +27,12 @@ enum ishtp_driver_data_index {
|
||||
ISHTP_DRIVER_DATA_NONE,
|
||||
ISHTP_DRIVER_DATA_LNL_M,
|
||||
ISHTP_DRIVER_DATA_PTL,
|
||||
ISHTP_DRIVER_DATA_WCL,
|
||||
};
|
||||
|
||||
#define ISH_FW_GEN_LNL_M "lnlm"
|
||||
#define ISH_FW_GEN_PTL "ptl"
|
||||
#define ISH_FW_GEN_WCL "wcl"
|
||||
|
||||
#define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
|
||||
#define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
|
||||
@@ -42,6 +44,9 @@ static struct ishtp_driver_data ishtp_driver_data[] = {
|
||||
[ISHTP_DRIVER_DATA_PTL] = {
|
||||
.fw_generation = ISH_FW_GEN_PTL,
|
||||
},
|
||||
[ISHTP_DRIVER_DATA_WCL] = {
|
||||
.fw_generation = ISH_FW_GEN_WCL,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pci_device_id ish_pci_tbl[] = {
|
||||
@@ -67,9 +72,10 @@ static const struct pci_device_id ish_pci_tbl[] = {
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_MTL_P)},
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_H)},
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_ARL_S)},
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_LNL_M), .driver_data = ISHTP_DRIVER_DATA_LNL_M},
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_PTL_H), .driver_data = ISHTP_DRIVER_DATA_PTL},
|
||||
{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ISH_PTL_P), .driver_data = ISHTP_DRIVER_DATA_PTL},
|
||||
{PCI_DEVICE_DATA(INTEL, ISH_LNL_M, ISHTP_DRIVER_DATA_LNL_M)},
|
||||
{PCI_DEVICE_DATA(INTEL, ISH_PTL_H, ISHTP_DRIVER_DATA_PTL)},
|
||||
{PCI_DEVICE_DATA(INTEL, ISH_PTL_P, ISHTP_DRIVER_DATA_PTL)},
|
||||
{PCI_DEVICE_DATA(INTEL, ISH_WCL, ISHTP_DRIVER_DATA_WCL)},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hid-over-i2c.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include "intel-thc-dev.h"
|
||||
#include "intel-thc-dma.h"
|
||||
@@ -200,6 +201,9 @@ int quicki2c_set_report(struct quicki2c_device *qcdev, u8 report_type,
|
||||
|
||||
int quicki2c_reset(struct quicki2c_device *qcdev)
|
||||
{
|
||||
u16 input_reg = le16_to_cpu(qcdev->dev_desc.input_reg);
|
||||
size_t read_len = HIDI2C_LENGTH_LEN;
|
||||
u32 prd_len = read_len;
|
||||
int ret;
|
||||
|
||||
qcdev->reset_ack = false;
|
||||
@@ -213,12 +217,32 @@ int quicki2c_reset(struct quicki2c_device *qcdev)
|
||||
|
||||
ret = wait_event_interruptible_timeout(qcdev->reset_ack_wq, qcdev->reset_ack,
|
||||
HIDI2C_RESET_TIMEOUT * HZ);
|
||||
if (ret <= 0 || !qcdev->reset_ack) {
|
||||
if (qcdev->reset_ack)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Manually read reset response if it wasn't received, in case reset interrupt
|
||||
* was missed by touch device or THC hardware.
|
||||
*/
|
||||
ret = thc_tic_pio_read(qcdev->thc_hw, input_reg, read_len, &prd_len,
|
||||
(u32 *)qcdev->input_buf);
|
||||
if (ret) {
|
||||
dev_err_once(qcdev->dev, "Read Reset Response failed, ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check response packet length, it's first 16 bits of packet.
|
||||
* If response packet length is zero, it's reset response, otherwise not.
|
||||
*/
|
||||
if (get_unaligned_le16(qcdev->input_buf)) {
|
||||
dev_err_once(qcdev->dev,
|
||||
"Wait reset response timed out ret:%d timeout:%ds\n",
|
||||
ret, HIDI2C_RESET_TIMEOUT);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
qcdev->reset_ack = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2048,14 +2048,18 @@ static int wacom_initialize_remotes(struct wacom *wacom)
|
||||
|
||||
remote->remote_dir = kobject_create_and_add("wacom_remote",
|
||||
&wacom->hdev->dev.kobj);
|
||||
if (!remote->remote_dir)
|
||||
if (!remote->remote_dir) {
|
||||
kfifo_free(&remote->remote_fifo);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
error = sysfs_create_files(remote->remote_dir, remote_unpair_attrs);
|
||||
|
||||
if (error) {
|
||||
hid_err(wacom->hdev,
|
||||
"cannot create sysfs group err: %d\n", error);
|
||||
kfifo_free(&remote->remote_fifo);
|
||||
kobject_put(remote->remote_dir);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2901,6 +2905,7 @@ static void wacom_remove(struct hid_device *hdev)
|
||||
hid_hw_stop(hdev);
|
||||
|
||||
cancel_delayed_work_sync(&wacom->init_work);
|
||||
cancel_delayed_work_sync(&wacom->aes_battery_work);
|
||||
cancel_work_sync(&wacom->wireless_work);
|
||||
cancel_work_sync(&wacom->battery_work);
|
||||
cancel_work_sync(&wacom->remote_work);
|
||||
|
||||
Reference in New Issue
Block a user