Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID fixes from Jiri Kosina: - fixes for a couple potential memory corruption problems (the HW would have to be manufactured to be deliberately evil to trigger those) found by Ben Hawkes - fix for potential infinite loop when using sysfs interface of logitech driver, from Simon Wood - a couple more simple driver fixes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: HID: fix a couple of off-by-ones HID: logitech: perform bounds checking on device_id early enough HID: logitech: fix bounds checking on LED report size HID: logitech: Prevent possibility of infinite loop when using /sys interface HID: rmi: print an error if F11 is not found instead of stopping the device HID: hid-sensor-hub: use devm_ functions consistently HID: huion: Use allocated buffer for DMA HID: huion: Fail on parameter retrieval errors
This commit is contained in:
commit
cee5aa1f81
11 changed files with 115 additions and 94 deletions
|
@ -28,7 +28,7 @@
|
|||
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
|
||||
if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
|
||||
hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
|
||||
rdesc[11] = rdesc[16] = 0xff;
|
||||
rdesc[12] = rdesc[17] = 0x03;
|
||||
|
|
|
@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
|
|||
0xC0 /* End Collection */
|
||||
};
|
||||
|
||||
/* Parameter indices */
|
||||
enum huion_prm {
|
||||
HUION_PRM_X_LM = 1,
|
||||
HUION_PRM_Y_LM = 2,
|
||||
HUION_PRM_PRESSURE_LM = 4,
|
||||
HUION_PRM_RESOLUTION = 5,
|
||||
HUION_PRM_NUM
|
||||
};
|
||||
|
||||
/* Driver data */
|
||||
struct huion_drvdata {
|
||||
__u8 *rdesc;
|
||||
|
@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
|
|||
int rc;
|
||||
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
|
||||
struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
|
||||
__le16 buf[6];
|
||||
__le16 *buf = NULL;
|
||||
size_t len;
|
||||
s32 params[HUION_PH_ID_NUM];
|
||||
s32 resolution;
|
||||
__u8 *p;
|
||||
s32 v;
|
||||
|
||||
/*
|
||||
* Read string descriptor containing tablet parameters. The specific
|
||||
|
@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
|
|||
* driver traffic.
|
||||
* NOTE: This enables fully-functional tablet mode.
|
||||
*/
|
||||
len = HUION_PRM_NUM * sizeof(*buf);
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
hid_err(hdev, "failed to allocate parameter buffer\n");
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
|
||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||
(USB_DT_STRING << 8) + 0x64,
|
||||
0x0409, buf, sizeof(buf),
|
||||
0x0409, buf, len,
|
||||
USB_CTRL_GET_TIMEOUT);
|
||||
if (rc == -EPIPE)
|
||||
hid_warn(hdev, "device parameters not found\n");
|
||||
else if (rc < 0)
|
||||
hid_warn(hdev, "failed to get device parameters: %d\n", rc);
|
||||
else if (rc != sizeof(buf))
|
||||
hid_warn(hdev, "invalid device parameters\n");
|
||||
else {
|
||||
s32 params[HUION_PH_ID_NUM];
|
||||
s32 resolution;
|
||||
__u8 *p;
|
||||
s32 v;
|
||||
if (rc == -EPIPE) {
|
||||
hid_err(hdev, "device parameters not found\n");
|
||||
rc = -ENODEV;
|
||||
goto cleanup;
|
||||
} else if (rc < 0) {
|
||||
hid_err(hdev, "failed to get device parameters: %d\n", rc);
|
||||
rc = -ENODEV;
|
||||
goto cleanup;
|
||||
} else if (rc != len) {
|
||||
hid_err(hdev, "invalid device parameters\n");
|
||||
rc = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extract device parameters */
|
||||
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
|
||||
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
|
||||
params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
|
||||
resolution = le16_to_cpu(buf[5]);
|
||||
if (resolution == 0) {
|
||||
params[HUION_PH_ID_X_PM] = 0;
|
||||
params[HUION_PH_ID_Y_PM] = 0;
|
||||
/* Extract device parameters */
|
||||
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
|
||||
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
|
||||
params[HUION_PH_ID_PRESSURE_LM] =
|
||||
le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
|
||||
resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
|
||||
if (resolution == 0) {
|
||||
params[HUION_PH_ID_X_PM] = 0;
|
||||
params[HUION_PH_ID_Y_PM] = 0;
|
||||
} else {
|
||||
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
|
||||
1000 / resolution;
|
||||
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
|
||||
1000 / resolution;
|
||||
}
|
||||
|
||||
/* Allocate fixed report descriptor */
|
||||
drvdata->rdesc = devm_kmalloc(&hdev->dev,
|
||||
sizeof(huion_tablet_rdesc_template),
|
||||
GFP_KERNEL);
|
||||
if (drvdata->rdesc == NULL) {
|
||||
hid_err(hdev, "failed to allocate fixed rdesc\n");
|
||||
rc = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
|
||||
|
||||
/* Format fixed report descriptor */
|
||||
memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
|
||||
drvdata->rsize);
|
||||
for (p = drvdata->rdesc;
|
||||
p <= drvdata->rdesc + drvdata->rsize - 4;) {
|
||||
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
|
||||
p[3] < sizeof(params)) {
|
||||
v = params[p[3]];
|
||||
put_unaligned(cpu_to_le32(v), (s32 *)p);
|
||||
p += 4;
|
||||
} else {
|
||||
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
|
||||
1000 / resolution;
|
||||
params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
|
||||
1000 / resolution;
|
||||
}
|
||||
|
||||
/* Allocate fixed report descriptor */
|
||||
drvdata->rdesc = devm_kmalloc(&hdev->dev,
|
||||
sizeof(huion_tablet_rdesc_template),
|
||||
GFP_KERNEL);
|
||||
if (drvdata->rdesc == NULL) {
|
||||
hid_err(hdev, "failed to allocate fixed rdesc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
drvdata->rsize = sizeof(huion_tablet_rdesc_template);
|
||||
|
||||
/* Format fixed report descriptor */
|
||||
memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
|
||||
drvdata->rsize);
|
||||
for (p = drvdata->rdesc;
|
||||
p <= drvdata->rdesc + drvdata->rsize - 4;) {
|
||||
if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
|
||||
p[3] < sizeof(params)) {
|
||||
v = params[p[3]];
|
||||
put_unaligned(cpu_to_le32(v), (s32 *)p);
|
||||
p += 4;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
|
|
@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
* - change the button usage range to 4-7 for the extra
|
||||
* buttons
|
||||
*/
|
||||
if (*rsize >= 74 &&
|
||||
if (*rsize >= 75 &&
|
||||
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
|
||||
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
|
||||
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
|
||||
|
|
|
@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
|||
struct usb_device_descriptor *udesc;
|
||||
__u16 bcdDevice, rev_maj, rev_min;
|
||||
|
||||
if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
|
||||
if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
|
||||
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
|
||||
hid_info(hdev,
|
||||
"fixing up Logitech keyboard report descriptor\n");
|
||||
rdesc[84] = rdesc[89] = 0x4d;
|
||||
rdesc[85] = rdesc[90] = 0x10;
|
||||
}
|
||||
if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
|
||||
if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
|
||||
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
|
||||
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
|
||||
hid_info(hdev,
|
||||
|
|
|
@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
|
|||
drv_data = hid_get_drvdata(hid);
|
||||
if (!drv_data) {
|
||||
hid_err(hid, "Private driver data not found!\n");
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry = drv_data->device_props;
|
||||
if (!entry) {
|
||||
hid_err(hid, "Device properties not found!\n");
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (range == 0)
|
||||
|
|
|
@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|||
return;
|
||||
}
|
||||
|
||||
if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
|
||||
(dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
|
||||
dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
|
||||
__func__, dj_report->device_index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
|
||||
/* The device is already known. No need to reallocate it. */
|
||||
dbg_hid("%s: device is already known\n", __func__);
|
||||
|
@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
|
|||
if (!out_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count < DJREPORT_SHORT_LENGTH - 2)
|
||||
if (count > DJREPORT_SHORT_LENGTH - 2)
|
||||
count = DJREPORT_SHORT_LENGTH - 2;
|
||||
|
||||
out_buf[0] = REPORT_ID_DJ_SHORT;
|
||||
|
@ -690,6 +683,12 @@ static int logi_dj_raw_event(struct hid_device *hdev,
|
|||
* device (via hid_input_report() ) and return 1 so hid-core does not do
|
||||
* anything else with it.
|
||||
*/
|
||||
if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
|
||||
(dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
|
||||
dev_err(&hdev->dev, "%s: invalid device index:%d\n",
|
||||
__func__, dj_report->device_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&djrcv_dev->lock, flags);
|
||||
if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
|
||||
if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
|
||||
hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
|
||||
rdesc[30] = 0x0c;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
|
||||
if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
|
||||
rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
|
||||
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
|
||||
hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
|
||||
|
|
|
@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (!test_bit(RMI_STARTED, &data->flags)) {
|
||||
hid_hw_stop(hdev);
|
||||
return -EIO;
|
||||
}
|
||||
if (!test_bit(RMI_STARTED, &data->flags))
|
||||
/*
|
||||
* The device maybe in the bootloader if rmi_input_configured
|
||||
* failed to find F11 in the PDT. Print an error, but don't
|
||||
* return an error from rmi_probe so that hidraw will be
|
||||
* accessible from userspace. That way a userspace tool
|
||||
* can be used to reload working firmware on the touchpad.
|
||||
*/
|
||||
hid_err(hdev, "Device failed to be properly configured\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
ret = -EINVAL;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
|
||||
sizeof(struct mfd_cell),
|
||||
GFP_KERNEL);
|
||||
sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
|
||||
sizeof(struct mfd_cell),
|
||||
GFP_KERNEL);
|
||||
if (sd->hid_sensor_hub_client_devs == NULL) {
|
||||
hid_err(hdev, "Failed to allocate memory for mfd cells\n");
|
||||
ret = -ENOMEM;
|
||||
|
@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL) {
|
||||
|
||||
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
|
||||
hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
|
||||
GFP_KERNEL);
|
||||
if (!hsdev) {
|
||||
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_mem;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
hsdev->hdev = hdev;
|
||||
hsdev->vendor_id = hdev->vendor;
|
||||
|
@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
last_hsdev = hsdev;
|
||||
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
|
||||
collection->usage);
|
||||
name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
|
||||
"HID-SENSOR-%x",
|
||||
collection->usage);
|
||||
if (name == NULL) {
|
||||
hid_err(hdev, "Failed MFD device name\n");
|
||||
ret = -ENOMEM;
|
||||
kfree(hsdev);
|
||||
goto err_no_mem;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].id =
|
||||
|
@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
|||
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
|
||||
sd->hid_sensor_client_cnt, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
goto err_no_mem;
|
||||
goto err_stop_hw;
|
||||
|
||||
return ret;
|
||||
|
||||
err_no_mem:
|
||||
for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
|
||||
kfree(sd->hid_sensor_hub_client_devs[i].name);
|
||||
kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
|
||||
}
|
||||
kfree(sd->hid_sensor_hub_client_devs);
|
||||
err_stop_hw:
|
||||
hid_hw_stop(hdev);
|
||||
|
||||
|
@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
|||
{
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
hid_dbg(hdev, " hardware removed\n");
|
||||
hid_hw_close(hdev);
|
||||
|
@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
|||
complete(&data->pending.ready);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
mfd_remove_devices(&hdev->dev);
|
||||
for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
|
||||
kfree(data->hid_sensor_hub_client_devs[i].name);
|
||||
kfree(data->hid_sensor_hub_client_devs[i].platform_data);
|
||||
}
|
||||
kfree(data->hid_sensor_hub_client_devs);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
mutex_destroy(&data->mutex);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||
unsigned int *rsize)
|
||||
{
|
||||
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
||||
if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
||||
rdesc[106] == 0x03) {
|
||||
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
|
||||
rdesc[105] = rdesc[110] = 0x03;
|
||||
|
|
Loading…
Reference in a new issue