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
|
@ -28,7 +28,7 @@
|
||||||
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
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");
|
hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
|
||||||
rdesc[11] = rdesc[16] = 0xff;
|
rdesc[11] = rdesc[16] = 0xff;
|
||||||
rdesc[12] = rdesc[17] = 0x03;
|
rdesc[12] = rdesc[17] = 0x03;
|
||||||
|
|
|
@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
|
||||||
0xC0 /* End Collection */
|
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 */
|
/* Driver data */
|
||||||
struct huion_drvdata {
|
struct huion_drvdata {
|
||||||
__u8 *rdesc;
|
__u8 *rdesc;
|
||||||
|
@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
|
||||||
int rc;
|
int rc;
|
||||||
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
|
struct usb_device *usb_dev = hid_to_usb_dev(hdev);
|
||||||
struct huion_drvdata *drvdata = hid_get_drvdata(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
|
* Read string descriptor containing tablet parameters. The specific
|
||||||
|
@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
|
||||||
* driver traffic.
|
* driver traffic.
|
||||||
* NOTE: This enables fully-functional tablet mode.
|
* 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),
|
rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
|
||||||
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
|
||||||
(USB_DT_STRING << 8) + 0x64,
|
(USB_DT_STRING << 8) + 0x64,
|
||||||
0x0409, buf, sizeof(buf),
|
0x0409, buf, len,
|
||||||
USB_CTRL_GET_TIMEOUT);
|
USB_CTRL_GET_TIMEOUT);
|
||||||
if (rc == -EPIPE)
|
if (rc == -EPIPE) {
|
||||||
hid_warn(hdev, "device parameters not found\n");
|
hid_err(hdev, "device parameters not found\n");
|
||||||
else if (rc < 0)
|
rc = -ENODEV;
|
||||||
hid_warn(hdev, "failed to get device parameters: %d\n", rc);
|
goto cleanup;
|
||||||
else if (rc != sizeof(buf))
|
} else if (rc < 0) {
|
||||||
hid_warn(hdev, "invalid device parameters\n");
|
hid_err(hdev, "failed to get device parameters: %d\n", rc);
|
||||||
else {
|
rc = -ENODEV;
|
||||||
s32 params[HUION_PH_ID_NUM];
|
goto cleanup;
|
||||||
s32 resolution;
|
} else if (rc != len) {
|
||||||
__u8 *p;
|
hid_err(hdev, "invalid device parameters\n");
|
||||||
s32 v;
|
rc = -ENODEV;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extract device parameters */
|
/* Extract device parameters */
|
||||||
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
|
params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
|
||||||
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
|
params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
|
||||||
params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
|
params[HUION_PH_ID_PRESSURE_LM] =
|
||||||
resolution = le16_to_cpu(buf[5]);
|
le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
|
||||||
if (resolution == 0) {
|
resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
|
||||||
params[HUION_PH_ID_X_PM] = 0;
|
if (resolution == 0) {
|
||||||
params[HUION_PH_ID_Y_PM] = 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 {
|
} else {
|
||||||
params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
|
p++;
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
rc = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
kfree(buf);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
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
|
* - change the button usage range to 4-7 for the extra
|
||||||
* buttons
|
* buttons
|
||||||
*/
|
*/
|
||||||
if (*rsize >= 74 &&
|
if (*rsize >= 75 &&
|
||||||
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
|
rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
|
||||||
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
|
rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
|
||||||
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
|
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;
|
struct usb_device_descriptor *udesc;
|
||||||
__u16 bcdDevice, rev_maj, rev_min;
|
__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) {
|
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
|
||||||
hid_info(hdev,
|
hid_info(hdev,
|
||||||
"fixing up Logitech keyboard report descriptor\n");
|
"fixing up Logitech keyboard report descriptor\n");
|
||||||
rdesc[84] = rdesc[89] = 0x4d;
|
rdesc[84] = rdesc[89] = 0x4d;
|
||||||
rdesc[85] = rdesc[90] = 0x10;
|
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[32] == 0x81 && rdesc[33] == 0x06 &&
|
||||||
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
|
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
|
||||||
hid_info(hdev,
|
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);
|
drv_data = hid_get_drvdata(hid);
|
||||||
if (!drv_data) {
|
if (!drv_data) {
|
||||||
hid_err(hid, "Private driver data not found!\n");
|
hid_err(hid, "Private driver data not found!\n");
|
||||||
return 0;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = drv_data->device_props;
|
entry = drv_data->device_props;
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
hid_err(hid, "Device properties not found!\n");
|
hid_err(hid, "Device properties not found!\n");
|
||||||
return 0;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range == 0)
|
if (range == 0)
|
||||||
|
|
|
@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||||
return;
|
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]) {
|
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
|
||||||
/* The device is already known. No need to reallocate it. */
|
/* The device is already known. No need to reallocate it. */
|
||||||
dbg_hid("%s: device is already known\n", __func__);
|
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)
|
if (!out_buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (count < DJREPORT_SHORT_LENGTH - 2)
|
if (count > DJREPORT_SHORT_LENGTH - 2)
|
||||||
count = DJREPORT_SHORT_LENGTH - 2;
|
count = DJREPORT_SHORT_LENGTH - 2;
|
||||||
|
|
||||||
out_buf[0] = REPORT_ID_DJ_SHORT;
|
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
|
* device (via hid_input_report() ) and return 1 so hid-core does not do
|
||||||
* anything else with it.
|
* 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);
|
spin_lock_irqsave(&djrcv_dev->lock, flags);
|
||||||
if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
|
if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
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");
|
hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
|
||||||
rdesc[30] = 0x0c;
|
rdesc[30] = 0x0c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
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[41] == 0x00 && rdesc[59] == 0x26 &&
|
||||||
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
|
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
|
||||||
hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_bit(RMI_STARTED, &data->flags)) {
|
if (!test_bit(RMI_STARTED, &data->flags))
|
||||||
hid_hw_stop(hdev);
|
/*
|
||||||
return -EIO;
|
* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_stop_hw;
|
goto err_stop_hw;
|
||||||
}
|
}
|
||||||
sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
|
sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
|
||||||
sizeof(struct mfd_cell),
|
sizeof(struct mfd_cell),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (sd->hid_sensor_hub_client_devs == NULL) {
|
if (sd->hid_sensor_hub_client_devs == NULL) {
|
||||||
hid_err(hdev, "Failed to allocate memory for mfd cells\n");
|
hid_err(hdev, "Failed to allocate memory for mfd cells\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||||
|
|
||||||
if (collection->type == HID_COLLECTION_PHYSICAL) {
|
if (collection->type == HID_COLLECTION_PHYSICAL) {
|
||||||
|
|
||||||
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
|
hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!hsdev) {
|
if (!hsdev) {
|
||||||
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
|
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_no_mem;
|
goto err_stop_hw;
|
||||||
}
|
}
|
||||||
hsdev->hdev = hdev;
|
hsdev->hdev = hdev;
|
||||||
hsdev->vendor_id = hdev->vendor;
|
hsdev->vendor_id = hdev->vendor;
|
||||||
|
@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||||
if (last_hsdev)
|
if (last_hsdev)
|
||||||
last_hsdev->end_collection_index = i;
|
last_hsdev->end_collection_index = i;
|
||||||
last_hsdev = hsdev;
|
last_hsdev = hsdev;
|
||||||
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
|
name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
|
||||||
collection->usage);
|
"HID-SENSOR-%x",
|
||||||
|
collection->usage);
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
hid_err(hdev, "Failed MFD device name\n");
|
hid_err(hdev, "Failed MFD device name\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
kfree(hsdev);
|
goto err_stop_hw;
|
||||||
goto err_no_mem;
|
|
||||||
}
|
}
|
||||||
sd->hid_sensor_hub_client_devs[
|
sd->hid_sensor_hub_client_devs[
|
||||||
sd->hid_sensor_client_cnt].id =
|
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,
|
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
|
||||||
sd->hid_sensor_client_cnt, NULL, 0, NULL);
|
sd->hid_sensor_client_cnt, NULL, 0, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_no_mem;
|
goto err_stop_hw;
|
||||||
|
|
||||||
return ret;
|
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:
|
err_stop_hw:
|
||||||
hid_hw_stop(hdev);
|
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);
|
struct sensor_hub_data *data = hid_get_drvdata(hdev);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
|
||||||
|
|
||||||
hid_dbg(hdev, " hardware removed\n");
|
hid_dbg(hdev, " hardware removed\n");
|
||||||
hid_hw_close(hdev);
|
hid_hw_close(hdev);
|
||||||
|
@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
||||||
complete(&data->pending.ready);
|
complete(&data->pending.ready);
|
||||||
spin_unlock_irqrestore(&data->lock, flags);
|
spin_unlock_irqrestore(&data->lock, flags);
|
||||||
mfd_remove_devices(&hdev->dev);
|
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);
|
hid_set_drvdata(hdev, NULL);
|
||||||
mutex_destroy(&data->mutex);
|
mutex_destroy(&data->mutex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
|
||||||
unsigned int *rsize)
|
unsigned int *rsize)
|
||||||
{
|
{
|
||||||
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
|
||||||
rdesc[106] == 0x03) {
|
rdesc[106] == 0x03) {
|
||||||
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
|
hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
|
||||||
rdesc[105] = rdesc[110] = 0x03;
|
rdesc[105] = rdesc[110] = 0x03;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user