* [PATCH v3 04/10] HID: steelseries: validate output report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
From: Kees Cook <keescook@chromium.org>
A HID device could send a malicious output report that would cause the
steelseries HID driver to write beyond the output report allocation
during initialization, causing a heap overflow:
[ 167.981534] usb 1-1: New USB device found, idVendor=1038, idProduct=1410
...
[ 182.050547] BUG kmalloc-256 (Tainted: G W ): Redzone overwritten
CVE-2013-2891
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- no changes
drivers/hid/hid-steelseries.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index d164911..29f328f 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
goto err_free;
}
+ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
+ ret = -ENODEV;
+ goto err_free;
+ }
+
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 05/10] HID: LG: validate HID output report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
From: Kees Cook <keescook@chromium.org>
A HID device could send a malicious output report that would cause the
lg, lg3, and lg4 HID drivers to write beyond the output report allocation
during an event, causing a heap overflow:
[ 325.245240] usb 1-1: New USB device found, idVendor=046d, idProduct=c287
...
[ 414.518960] BUG kmalloc-4096 (Not tainted): Redzone overwritten
Additionally, while lg2 did correctly validate the report details, it was
cleaned up and shortened.
CVE-2013-2893
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- no changes
drivers/hid/hid-lg2ff.c | 19 +++----------------
drivers/hid/hid-lg3ff.c | 29 ++++++-----------------------
drivers/hid/hid-lg4ff.c | 20 +-------------------
drivers/hid/hid-lgff.c | 17 ++---------------
4 files changed, 12 insertions(+), 73 deletions(-)
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index b3cd150..1a42eaa 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid)
struct hid_report *report;
struct hid_input *hidinput = list_entry(hid->inputs.next,
struct hid_input, list);
- struct list_head *report_list =
- &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
int error;
- if (list_empty(report_list)) {
- hid_err(hid, "no output report found\n");
+ /* Check that the report looks ok */
+ report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
+ if (!report)
return -ENODEV;
- }
-
- report = list_entry(report_list->next, struct hid_report, list);
-
- if (report->maxfield < 1) {
- hid_err(hid, "output report is empty\n");
- return -ENODEV;
- }
- if (report->field[0]->report_count < 7) {
- hid_err(hid, "not enough values in the field\n");
- return -ENODEV;
- }
lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
if (!lg2ff)
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index e52f181..8c2da18 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
int x, y;
/*
- * Maxusage should always be 63 (maximum fields)
- * likely a better way to ensure this data is clean
+ * Available values in the field should always be 63, but we only use up to
+ * 35. Instead, clear the entire area, however big it is.
*/
- memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
+ memset(report->field[0]->value, 0,
+ sizeof(__s32) * report->field[0]->report_count);
switch (effect->type) {
case FF_CONSTANT:
@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = {
int lg3ff_init(struct hid_device *hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
- struct hid_report *report;
- struct hid_field *field;
const signed short *ff_bits = ff3_joystick_ac;
int error;
int i;
- /* Find the report to use */
- if (list_empty(report_list)) {
- hid_err(hid, "No output report found\n");
- return -1;
- }
-
/* Check that the report looks ok */
- report = list_entry(report_list->next, struct hid_report, list);
- if (!report) {
- hid_err(hid, "NULL output report\n");
- return -1;
- }
-
- field = report->field[0];
- if (!field) {
- hid_err(hid, "NULL field\n");
- return -1;
- }
+ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
+ return -ENODEV;
/* Assume single fixed device G940 */
for (i = 0; ff_bits[i] >= 0; i++)
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 0ddae2a..8782fe1 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
int lg4ff_init(struct hid_device *hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
- struct hid_report *report;
- struct hid_field *field;
struct lg4ff_device_entry *entry;
struct lg_drv_data *drv_data;
struct usb_device_descriptor *udesc;
int error, i, j;
__u16 bcdDevice, rev_maj, rev_min;
- /* Find the report to use */
- if (list_empty(report_list)) {
- hid_err(hid, "No output report found\n");
- return -1;
- }
-
/* Check that the report looks ok */
- report = list_entry(report_list->next, struct hid_report, list);
- if (!report) {
- hid_err(hid, "NULL output report\n");
+ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
return -1;
- }
-
- field = report->field[0];
- if (!field) {
- hid_err(hid, "NULL field\n");
- return -1;
- }
/* Check what wheel has been connected */
for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index d7ea8c8..e1394af 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
int lgff_init(struct hid_device* hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
- struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct input_dev *dev = hidinput->input;
- struct hid_report *report;
- struct hid_field *field;
const signed short *ff_bits = ff_joystick;
int error;
int i;
- /* Find the report to use */
- if (list_empty(report_list)) {
- hid_err(hid, "No output report found\n");
- return -1;
- }
-
/* Check that the report looks ok */
- report = list_entry(report_list->next, struct hid_report, list);
- field = report->field[0];
- if (!field) {
- hid_err(hid, "NULL field\n");
- return -1;
- }
+ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
+ return -ENODEV;
for (i = 0; i < ARRAY_SIZE(devices); i++) {
if (dev->id.vendor == devices[i].idVendor &&
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 06/10] HID: lenovo-tpkbd: validate output report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
From: Kees Cook <keescook@chromium.org>
From: Kees Cook <keescook@chromium.org>
A HID device could send a malicious output report that would cause the
lenovo-tpkbd HID driver to write just beyond the output report allocation
during initialization, causing a heap overflow:
[ 76.109807] usb 1-1: New USB device found, idVendor=17ef, idProduct=6009
...
[ 80.462540] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
CVE-2013-2894
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- fix feature report check for report ID 4
drivers/hid/hid-lenovo-tpkbd.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 07837f5..762d988 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
struct tpkbd_data_pointer *data_pointer;
size_t name_sz = strlen(dev_name(dev)) + 16;
char *name_mute, *name_micmute;
- int ret;
+ int i, ret;
+
+ /* Validate required reports. */
+ for (i = 0; i < 4; i++) {
+ if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
+ return -ENODEV;
+ }
+ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
+ return -ENODEV;
if (sysfs_create_group(&hdev->dev.kobj,
&tpkbd_attr_group_pointer)) {
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 07/10] HID: logitech-dj: validate output report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
From: Kees Cook <keescook@chromium.org>
A HID device could send a malicious output report that would cause the
logitech-dj HID driver to leak kernel memory contents to the device, or
trigger a NULL dereference during initialization:
[ 304.424553] usb 1-1: New USB device found, idVendor=046d, idProduct=c52b
...
[ 304.780467] BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
[ 304.781409] IP: [<ffffffff815d50aa>] logi_dj_recv_send_report.isra.11+0x1a/0x90
CVE-2013-2895
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
---
v3:
- check for the whole size of the DJ report, as per the spec
drivers/hid/hid-logitech-dj.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 7800b14..2e53024 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
struct hid_report *report;
struct hid_report_enum *output_report_enum;
u8 *data = (u8 *)(&dj_report->device_index);
- int i;
+ unsigned int i;
output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
@@ -471,7 +471,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
return -ENODEV;
}
- for (i = 0; i < report->field[0]->report_count; i++)
+ for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
report->field[0]->value[i] = data[i];
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev,
goto hid_parse_fail;
}
+ if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT,
+ 0, DJREPORT_SHORT_LENGTH - 1)) {
+ retval = -ENODEV;
+ goto hid_parse_fail;
+ }
+
/* Starts the usb device and connects to upper interfaces hiddev and
* hidraw */
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 09/10] HID: multitouch: validate indexes details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
When working on report indexes, always validate that they are in bounds.
Without this, a HID device could report a malicious feature report that
could trick the driver into a heap overflow:
[ 634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
...
[ 676.469629] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
Note that we need to change the indexes from s8 to s16 as they can
be between -1 and 255.
CVE-2013-2897
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- extract from hid-multitouch the generic checks so that every hid drivers will
benefit from them
- change __s8 index declarations into __s16
- use usage_index for the input_mode index instead of a half working code
- check the indexes validities only once
drivers/hid/hid-multitouch.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index ac28f08..5e5fe1b 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -101,9 +101,9 @@ struct mt_device {
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned pen_report_id; /* the report ID of the pen device */
- __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
- __s8 inputmode_index; /* InputMode HID feature index in the report */
- __s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
+ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
+ __s16 inputmode_index; /* InputMode HID feature index in the report */
+ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
-1 if non-existent */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
@@ -312,20 +312,18 @@ static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage)
{
struct mt_device *td = hid_get_drvdata(hdev);
- int i;
switch (usage->hid) {
case HID_DG_INPUTMODE:
- td->inputmode = field->report->id;
- td->inputmode_index = 0; /* has to be updated below */
-
- for (i=0; i < field->maxusage; i++) {
- if (field->usage[i].hid == usage->hid) {
- td->inputmode_index = i;
- break;
- }
+ /* Ignore if value index is out of bounds. */
+ if (usage->usage_index >= field->report_count) {
+ dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
+ break;
}
+ td->inputmode = field->report->id;
+ td->inputmode_index = usage->usage_index;
+
break;
case HID_DG_CONTACTMAX:
td->maxcontact_report_id = field->report->id;
@@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
mt_store_field(usage, td, hi);
return 1;
case HID_DG_CONTACTCOUNT:
+ /* Ignore if indexes are out of bounds. */
+ if (field->index >= field->report->maxfield ||
+ usage->usage_index >= field->report_count)
+ return 1;
td->cc_index = field->index;
td->cc_value_index = usage->usage_index;
return 1;
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 10/10] HID: lenovo-tpkbd: fix leak if tpkbd_probe_tp fails
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
If tpkbd_probe_tp() bails out, the probe() function return an error,
but hid_hw_stop() is never called.
fixes:
https://bugzilla.redhat.com/show_bug.cgi?id=1003998
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- new patch
drivers/hid/hid-lenovo-tpkbd.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 762d988..31cf29a 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -414,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "hid_parse failed\n");
- goto err_free;
+ goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hid_hw_start failed\n");
- goto err_free;
+ goto err;
}
uhdev = (struct usbhid_device *) hdev->driver_data;
- if (uhdev->ifnum == 1)
- return tpkbd_probe_tp(hdev);
+ if (uhdev->ifnum == 1) {
+ ret = tpkbd_probe_tp(hdev);
+ if (ret)
+ goto err_hid;
+ }
return 0;
-err_free:
+err_hid:
+ hid_hw_stop(hdev);
+err:
return ret;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 00/10] HID: validate report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
Hi guys,
here is the v3 of the CVE fixes.
I have tested the multitouch and logitech-dj part, and the lenovo-tpkbd has been
tested in the bug referenced in patch 10.
Cheers,
Benjamin
Changes since v2:
- fix lenovo-tpkbd report validation
- fix lenovo-tpkbd not releasing the device when the report was not valid
- use generic tests found in previous hid-multitouch patches, so that this will
not happen again
- fix input_report index retrieving in hid-multitouch
Original message from Kees (v2):
These patches introduce a validation function for HID devices that do
direct report value accesses, solving a number of heap smashing flaws.
This version changes to using an field-index-based checker for the new
"hid_validate_values()" which requires callers to loop across fields if
they use more than one field.
Benjamin Tissoires (3):
HID: validate feature and input report details
HID: multitouch: validate indexes details
HID: lenovo-tpkbd: fix leak if tpkbd_probe_tp fails
Kees Cook (7):
HID: provide a helper for validating hid reports
HID: zeroplus: validate output report details
HID: sony: validate HID output report details
HID: steelseries: validate output report details
HID: LG: validate HID output report details
HID: lenovo-tpkbd: validate output report details
HID: logitech-dj: validate output report details
drivers/hid/hid-core.c | 74 +++++++++++++++++++++++++++++++++++++-----
drivers/hid/hid-input.c | 11 ++++++-
drivers/hid/hid-lenovo-tpkbd.c | 25 ++++++++++----
drivers/hid/hid-lg2ff.c | 19 ++---------
drivers/hid/hid-lg3ff.c | 29 ++++-------------
drivers/hid/hid-lg4ff.c | 20 +-----------
drivers/hid/hid-lgff.c | 17 ++--------
drivers/hid/hid-logitech-dj.c | 10 ++++--
drivers/hid/hid-multitouch.c | 26 ++++++++-------
drivers/hid/hid-sony.c | 4 +++
drivers/hid/hid-steelseries.c | 5 +++
drivers/hid/hid-zpff.c | 18 +++-------
include/linux/hid.h | 4 +++
13 files changed, 146 insertions(+), 116 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [PATCH v3 01/10] HID: provide a helper for validating hid reports
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
From: Kees Cook <keescook@chromium.org>
Many drivers need to validate the characteristics of their HID report
during initialization to avoid misusing the reports. This adds a common
helper to perform validation of the report exisitng, the field existing,
and the expected number of values within the field.
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- no changes
v2:
- suggestions from Benjamin Tissoires:
- check id too, just to be double-safe.
- updated to check a specific field, moving the for loop to callers.
drivers/hid/hid-core.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/hid.h | 4 ++++
2 files changed, 62 insertions(+)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 2c77854..44b6c68 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -801,6 +801,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
}
EXPORT_SYMBOL_GPL(hid_parse_report);
+static const char * const hid_report_names[] = {
+ "HID_INPUT_REPORT",
+ "HID_OUTPUT_REPORT",
+ "HID_FEATURE_REPORT",
+};
+/**
+ * hid_validate_values - validate existing device report's value indexes
+ *
+ * @device: hid device
+ * @type: which report type to examine
+ * @id: which report ID to examine (0 for first)
+ * @field_index: which report field to examine
+ * @report_counts: expected number of values
+ *
+ * Validate the number of values in a given field of a given report, after
+ * parsing.
+ */
+struct hid_report *hid_validate_values(struct hid_device *hid,
+ unsigned int type, unsigned int id,
+ unsigned int field_index,
+ unsigned int report_counts)
+{
+ struct hid_report *report;
+
+ if (type > HID_FEATURE_REPORT) {
+ hid_err(hid, "invalid HID report type %u\n", type);
+ return NULL;
+ }
+
+ if (id >= HID_MAX_IDS) {
+ hid_err(hid, "invalid HID report id %u\n", id);
+ return NULL;
+ }
+
+ /*
+ * Explicitly not using hid_get_report() here since it depends on
+ * ->numbered being checked, which may not always be the case when
+ * drivers go to access report values.
+ */
+ report = hid->report_enum[type].report_id_hash[id];
+ if (!report) {
+ hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
+ return NULL;
+ }
+ if (report->maxfield <= field_index) {
+ hid_err(hid, "not enough fields in %s %u\n",
+ hid_report_names[type], id);
+ return NULL;
+ }
+ if (report->field[field_index]->report_count < report_counts) {
+ hid_err(hid, "not enough values in %s %u field %u\n",
+ hid_report_names[type], id, field_index);
+ return NULL;
+ }
+ return report;
+}
+EXPORT_SYMBOL_GPL(hid_validate_values);
+
/**
* hid_open_report - open a driver-specific device report
*
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ee1ffc5..31b9d29 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+struct hid_report *hid_validate_values(struct hid_device *hid,
+ unsigned int type, unsigned int id,
+ unsigned int field_index,
+ unsigned int report_counts);
int hid_open_report(struct hid_device *device);
int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
--
1.8.3.1
^ permalink raw reply related
* [PATCH v3 08/10] HID: validate feature and input report details
From: Benjamin Tissoires @ 2013-09-11 19:56 UTC (permalink / raw)
To: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
When dealing with usage_index, be sure to properly use unsigned instead of
int to avoid overflows.
When working on report fields, always validate that their report_counts are
in bounds.
Without this, a HID device could report a malicious feature report that
could trick the driver into a heap overflow:
[ 634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
...
[ 676.469629] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
CVE-2013-2897
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
v3:
- new patch: extract from the hid-multitouch patch, the generic checks so that
every hid drivers will benefit from them
drivers/hid/hid-core.c | 16 +++++++---------
drivers/hid/hid-input.c | 11 ++++++++++-
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 44b6c68..329e24e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
{
struct hid_field *field;
- int i;
if (report->maxfield == HID_MAX_FIELDS) {
hid_err(report->device, "too many fields in report\n");
@@ -113,9 +112,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
field->value = (s32 *)(field->usage + usages);
field->report = report;
- for (i = 0; i < usages; i++)
- field->usage[i].usage_index = i;
-
return field;
}
@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
{
struct hid_report *report;
struct hid_field *field;
- int usages;
+ unsigned usages;
unsigned offset;
- int i;
+ unsigned i;
report = hid_register_report(parser->device, report_type, parser->global.report_id);
if (!report) {
@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
if (!parser->local.usage_index) /* Ignore padding fields */
return 0;
- usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+ usages = max_t(unsigned, parser->local.usage_index,
+ parser->global.report_count);
field = hid_register_field(report, usages, parser->global.report_count);
if (!field)
@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
for (i = 0; i < usages; i++) {
- int j = i;
+ unsigned j = i;
/* Duplicate the last usage we parsed if we have excess values */
if (i >= parser->local.usage_index)
j = parser->local.usage_index - 1;
field->usage[i].hid = parser->local.usage[j];
field->usage[i].collection_index =
parser->local.collection_index[j];
+ field->usage[i].usage_index = i;
}
field->maxusage = usages;
@@ -1354,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
goto out;
}
- if (hid->claimed != HID_CLAIMED_HIDRAW) {
+ if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
hdrv = hid->driver;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index b420f4a..8741d95 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore;
+ /* Ignore if report count is out of bounds. */
+ if (field->report_count < 1)
+ goto ignore;
+
/* only LED usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT &&
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid)
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list)
- for (i = 0; i < rep->maxfield; i++)
+ for (i = 0; i < rep->maxfield; i++) {
+ /* Ignore if report count is out of bounds. */
+ if (rep->field[i]->report_count < 1)
+ continue;
+
for (j = 0; j < rep->field[i]->maxusage; j++) {
/* Verify if Battery Strength feature is available */
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid)
drv->feature_mapping(hid, rep->field[i],
rep->field[i]->usage + j);
}
+ }
}
static struct hid_input *hidinput_allocate(struct hid_device *hid)
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH v3 06/10] HID: lenovo-tpkbd: validate output report details
From: Kees Cook @ 2013-09-11 20:06 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Henrik Rydberg, Jiri Kosina, linux-input,
LKML
In-Reply-To: <1378929419-6269-7-git-send-email-benjamin.tissoires@redhat.com>
On Wed, Sep 11, 2013 at 12:56 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> From: Kees Cook <keescook@chromium.org>
>
> From: Kees Cook <keescook@chromium.org>
>
Not sure if "git am" will eat the second one, but the "From:" is
duplicated above...
-Kees
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* Re: [PATCH v3 06/10] HID: lenovo-tpkbd: validate output report details
From: Benjamin Tissoires @ 2013-09-11 20:08 UTC (permalink / raw)
To: Kees Cook
Cc: Benjamin Tissoires, Henrik Rydberg, Jiri Kosina, linux-input,
LKML
In-Reply-To: <CAGXu5j+9hDd388ynuppu9jiQJgMKnSfPJ-FbmMztioFwntta0Q@mail.gmail.com>
On Wed, Sep 11, 2013 at 10:06 PM, Kees Cook <keescook@chromium.org> wrote:
> On Wed, Sep 11, 2013 at 12:56 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
>> From: Kees Cook <keescook@chromium.org>
>>
>> From: Kees Cook <keescook@chromium.org>
>>
>
> Not sure if "git am" will eat the second one, but the "From:" is
> duplicated above...
>
Yep, I saw that I duplicated it. Sorry :(
Anyway, feel free to add/remove any Signed-off-by if you wish (I think
I kept your original ones when it mattered).
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH v3 08/10] HID: validate feature and input report details
From: Kees Cook @ 2013-09-11 20:08 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Henrik Rydberg, Jiri Kosina, linux-input,
LKML
In-Reply-To: <1378929419-6269-9-git-send-email-benjamin.tissoires@redhat.com>
On Wed, Sep 11, 2013 at 12:56 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> When dealing with usage_index, be sure to properly use unsigned instead of
> int to avoid overflows.
>
> When working on report fields, always validate that their report_counts are
> in bounds.
> Without this, a HID device could report a malicious feature report that
> could trick the driver into a heap overflow:
>
> [ 634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
> ...
> [ 676.469629] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
>
> CVE-2013-2897
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
> ---
> v3:
> - new patch: extract from the hid-multitouch patch, the generic checks so that
> every hid drivers will benefit from them
>
> drivers/hid/hid-core.c | 16 +++++++---------
> drivers/hid/hid-input.c | 11 ++++++++++-
> 2 files changed, 17 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 44b6c68..329e24e 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
> static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
> {
> struct hid_field *field;
> - int i;
>
> if (report->maxfield == HID_MAX_FIELDS) {
> hid_err(report->device, "too many fields in report\n");
> @@ -113,9 +112,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
> field->value = (s32 *)(field->usage + usages);
> field->report = report;
>
> - for (i = 0; i < usages; i++)
> - field->usage[i].usage_index = i;
> -
> return field;
> }
>
> @@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
> {
> struct hid_report *report;
> struct hid_field *field;
> - int usages;
> + unsigned usages;
> unsigned offset;
> - int i;
> + unsigned i;
>
> report = hid_register_report(parser->device, report_type, parser->global.report_id);
> if (!report) {
> @@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
> if (!parser->local.usage_index) /* Ignore padding fields */
> return 0;
>
> - usages = max_t(int, parser->local.usage_index, parser->global.report_count);
> + usages = max_t(unsigned, parser->local.usage_index,
> + parser->global.report_count);
>
> field = hid_register_field(report, usages, parser->global.report_count);
> if (!field)
> @@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
> field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
>
> for (i = 0; i < usages; i++) {
> - int j = i;
> + unsigned j = i;
> /* Duplicate the last usage we parsed if we have excess values */
> if (i >= parser->local.usage_index)
> j = parser->local.usage_index - 1;
> field->usage[i].hid = parser->local.usage[j];
> field->usage[i].collection_index =
> parser->local.collection_index[j];
> + field->usage[i].usage_index = i;
> }
>
> field->maxusage = usages;
> @@ -1354,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
> goto out;
> }
>
> - if (hid->claimed != HID_CLAIMED_HIDRAW) {
> + if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
> for (a = 0; a < report->maxfield; a++)
> hid_input_field(hid, report->field[a], cdata, interrupt);
> hdrv = hid->driver;
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index b420f4a..8741d95 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
> if (field->flags & HID_MAIN_ITEM_CONSTANT)
> goto ignore;
>
> + /* Ignore if report count is out of bounds. */
> + if (field->report_count < 1)
> + goto ignore;
> +
> /* only LED usages are supported in output fields */
> if (field->report_type == HID_OUTPUT_REPORT &&
> (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
> @@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid)
>
> rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
> list_for_each_entry(rep, &rep_enum->report_list, list)
> - for (i = 0; i < rep->maxfield; i++)
> + for (i = 0; i < rep->maxfield; i++) {
> + /* Ignore if report count is out of bounds. */
> + if (rep->field[i]->report_count < 1)
> + continue;
> +
> for (j = 0; j < rep->field[i]->maxusage; j++) {
> /* Verify if Battery Strength feature is available */
> hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
> @@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid)
> drv->feature_mapping(hid, rep->field[i],
> rep->field[i]->usage + j);
> }
> + }
> }
>
> static struct hid_input *hidinput_allocate(struct hid_device *hid)
> --
> 1.8.3.1
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* Re: [PATCH v3 09/10] HID: multitouch: validate indexes details
From: Kees Cook @ 2013-09-11 20:09 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Henrik Rydberg, Jiri Kosina, linux-input,
LKML
In-Reply-To: <1378929419-6269-10-git-send-email-benjamin.tissoires@redhat.com>
On Wed, Sep 11, 2013 at 12:56 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> When working on report indexes, always validate that they are in bounds.
> Without this, a HID device could report a malicious feature report that
> could trick the driver into a heap overflow:
>
> [ 634.885003] usb 1-1: New USB device found, idVendor=0596, idProduct=0500
> ...
> [ 676.469629] BUG kmalloc-192 (Tainted: G W ): Redzone overwritten
>
> Note that we need to change the indexes from s8 to s16 as they can
> be between -1 and 255.
>
> CVE-2013-2897
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
> ---
> v3:
> - extract from hid-multitouch the generic checks so that every hid drivers will
> benefit from them
> - change __s8 index declarations into __s16
> - use usage_index for the input_mode index instead of a half working code
> - check the indexes validities only once
>
> drivers/hid/hid-multitouch.c | 26 ++++++++++++++------------
> 1 file changed, 14 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
> index ac28f08..5e5fe1b 100644
> --- a/drivers/hid/hid-multitouch.c
> +++ b/drivers/hid/hid-multitouch.c
> @@ -101,9 +101,9 @@ struct mt_device {
> unsigned last_slot_field; /* the last field of a slot */
> unsigned mt_report_id; /* the report ID of the multitouch device */
> unsigned pen_report_id; /* the report ID of the pen device */
> - __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
> - __s8 inputmode_index; /* InputMode HID feature index in the report */
> - __s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
> + __s16 inputmode; /* InputMode HID feature, -1 if non-existent */
> + __s16 inputmode_index; /* InputMode HID feature index in the report */
> + __s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
> -1 if non-existent */
> __u8 num_received; /* how many contacts we received */
> __u8 num_expected; /* expected last contact index */
> @@ -312,20 +312,18 @@ static void mt_feature_mapping(struct hid_device *hdev,
> struct hid_field *field, struct hid_usage *usage)
> {
> struct mt_device *td = hid_get_drvdata(hdev);
> - int i;
>
> switch (usage->hid) {
> case HID_DG_INPUTMODE:
> - td->inputmode = field->report->id;
> - td->inputmode_index = 0; /* has to be updated below */
> -
> - for (i=0; i < field->maxusage; i++) {
> - if (field->usage[i].hid == usage->hid) {
> - td->inputmode_index = i;
> - break;
> - }
> + /* Ignore if value index is out of bounds. */
> + if (usage->usage_index >= field->report_count) {
> + dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
> + break;
> }
>
> + td->inputmode = field->report->id;
> + td->inputmode_index = usage->usage_index;
> +
> break;
> case HID_DG_CONTACTMAX:
> td->maxcontact_report_id = field->report->id;
> @@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
> mt_store_field(usage, td, hi);
> return 1;
> case HID_DG_CONTACTCOUNT:
> + /* Ignore if indexes are out of bounds. */
> + if (field->index >= field->report->maxfield ||
> + usage->usage_index >= field->report_count)
> + return 1;
> td->cc_index = field->index;
> td->cc_value_index = usage->usage_index;
> return 1;
> --
> 1.8.3.1
>
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* Re: [PATCH v3 00/10] HID: validate report details
From: Kees Cook @ 2013-09-11 20:11 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Henrik Rydberg, Jiri Kosina, linux-input,
LKML
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
On Wed, Sep 11, 2013 at 12:56 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> Hi guys,
>
> here is the v3 of the CVE fixes.
>
> I have tested the multitouch and logitech-dj part, and the lenovo-tpkbd has been
> tested in the bug referenced in patch 10.
>
> Cheers,
> Benjamin
>
> Changes since v2:
> - fix lenovo-tpkbd report validation
> - fix lenovo-tpkbd not releasing the device when the report was not valid
> - use generic tests found in previous hid-multitouch patches, so that this will
> not happen again
> - fix input_report index retrieving in hid-multitouch
Awesome! Thanks very much for fixing these up. I replied with Acks
where appropriate. :)
-Kees
--
Kees Cook
Chrome OS Security
^ permalink raw reply
* [PATCH 1/3] HID: lenovo-tpkbd: devm conversion
From: Benjamin Tissoires @ 2013-09-11 20:12 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <1378930345-6670-1-git-send-email-benjamin.tissoires@redhat.com>
We can use the devres API in hid modules, so use it to avoid some kfree
and potential leaks.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-lenovo-tpkbd.c | 30 ++++++++----------------------
1 file changed, 8 insertions(+), 22 deletions(-)
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 31cf29a..0d9a276 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -339,7 +339,7 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
struct tpkbd_data_pointer *data_pointer;
size_t name_sz = strlen(dev_name(dev)) + 16;
char *name_mute, *name_micmute;
- int i, ret;
+ int i;
/* Validate required reports. */
for (i = 0; i < 4; i++) {
@@ -354,7 +354,9 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
hid_warn(hdev, "Could not create sysfs group\n");
}
- data_pointer = kzalloc(sizeof(struct tpkbd_data_pointer), GFP_KERNEL);
+ data_pointer = devm_kzalloc(&hdev->dev,
+ sizeof(struct tpkbd_data_pointer),
+ GFP_KERNEL);
if (data_pointer == NULL) {
hid_err(hdev, "Could not allocate memory for driver data\n");
return -ENOMEM;
@@ -364,20 +366,13 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
data_pointer->sensitivity = 0xa0;
data_pointer->press_speed = 0x38;
- name_mute = kzalloc(name_sz, GFP_KERNEL);
- if (name_mute == NULL) {
+ name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
+ name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
+ if (name_mute == NULL || name_micmute == NULL) {
hid_err(hdev, "Could not allocate memory for led data\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
-
- name_micmute = kzalloc(name_sz, GFP_KERNEL);
- if (name_micmute == NULL) {
- hid_err(hdev, "Could not allocate memory for led data\n");
- ret = -ENOMEM;
- goto err2;
- }
snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));
hid_set_drvdata(hdev, data_pointer);
@@ -397,12 +392,6 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
tpkbd_features_set(hdev);
return 0;
-
-err2:
- kfree(name_mute);
-err:
- kfree(data_pointer);
- return ret;
}
static int tpkbd_probe(struct hid_device *hdev,
@@ -449,9 +438,6 @@ static void tpkbd_remove_tp(struct hid_device *hdev)
led_classdev_unregister(&data_pointer->led_mute);
hid_set_drvdata(hdev, NULL);
- kfree(data_pointer->led_micmute.name);
- kfree(data_pointer->led_mute.name);
- kfree(data_pointer);
}
static void tpkbd_remove(struct hid_device *hdev)
--
1.8.3.1
^ permalink raw reply related
* [PATCH 2/3] HID: lenovo-tpkbd: remove usb dependency
From: Benjamin Tissoires @ 2013-09-11 20:12 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <1378930345-6670-1-git-send-email-benjamin.tissoires@redhat.com>
lenovo tpkbd currently relies on the usb interface number to detect
if it is dealing with the touchpad interface or not.
As the report descriptors of the interface 0 does not contain the
button 3, we can use this to remove the need to check for usb.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
I am not 100% happy with the trick required to differenciate the 2 interfaces.
It is working, but I don't really like setting "hid_set_drvdata(hdev, (void *)1);"
to avoid a kzalloc (and some more indirections later in the led part).
Any comments welcome :)
Cheers,
Benjamin
drivers/hid/Kconfig | 2 +-
drivers/hid/hid-lenovo-tpkbd.c | 20 ++++++--------------
2 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3d7c9f6..4b70800 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -322,7 +322,7 @@ config HID_LCPOWER
config HID_LENOVO_TPKBD
tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
- depends on USB_HID
+ depends on HID
select NEW_LEDS
select LEDS_CLASS
---help---
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 0d9a276..2d25b6c 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -14,11 +14,9 @@
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/device.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/leds.h>
-#include "usbhid/usbhid.h"
#include "hid-ids.h"
@@ -41,10 +39,9 @@ static int tpkbd_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
- struct usbhid_device *uhdev;
-
- uhdev = (struct usbhid_device *) hdev->driver_data;
- if (uhdev->ifnum == 1 && usage->hid == (HID_UP_BUTTON | 0x0010)) {
+ if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
+ /* mark the device as pointer */
+ hid_set_drvdata(hdev, (void *)1);
map_key_clear(KEY_MICMUTE);
return 1;
}
@@ -398,7 +395,6 @@ static int tpkbd_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
- struct usbhid_device *uhdev;
ret = hid_parse(hdev);
if (ret) {
@@ -412,9 +408,8 @@ static int tpkbd_probe(struct hid_device *hdev,
goto err;
}
- uhdev = (struct usbhid_device *) hdev->driver_data;
-
- if (uhdev->ifnum == 1) {
+ if (hid_get_drvdata(hdev)) {
+ hid_set_drvdata(hdev, NULL);
ret = tpkbd_probe_tp(hdev);
if (ret)
goto err_hid;
@@ -442,10 +437,7 @@ static void tpkbd_remove_tp(struct hid_device *hdev)
static void tpkbd_remove(struct hid_device *hdev)
{
- struct usbhid_device *uhdev;
-
- uhdev = (struct usbhid_device *) hdev->driver_data;
- if (uhdev->ifnum == 1)
+ if (hid_get_drvdata(hdev))
tpkbd_remove_tp(hdev);
hid_hw_stop(hdev);
--
1.8.3.1
^ permalink raw reply related
* [PATCH 0/3] Few cleanups
From: Benjamin Tissoires @ 2013-09-11 20:12 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, linux-input, linux-kernel
Hi Jiri,
Well, while debugging hid-lenovo-tpkbd, I also cleaned it up a little (so this
goes on top of the CVE series):
- use devres API
- remove usb references (so that the regressions tests through uhid are working)
This has also been tested by https://bugzilla.redhat.com/show_bug.cgi?id=1003998
And I also had a patch for sony that I wanted to send, but I was waiting for a
complete drop of usb, which I still did not managed to do.
Cheers,
Benjamin
Benjamin Tissoires (3):
HID: lenovo-tpkbd: devm conversion
HID: lenovo-tpkbd: remove usb dependency
HID: sony: use hid_get_raw_report() instead of a direct call to usb
drivers/hid/Kconfig | 2 +-
drivers/hid/hid-lenovo-tpkbd.c | 50 ++++++++++++------------------------------
drivers/hid/hid-sony.c | 11 ++--------
3 files changed, 17 insertions(+), 46 deletions(-)
--
1.8.3.1
^ permalink raw reply
* [PATCH 3/3] HID: sony: use hid_get_raw_report() instead of a direct call to usb
From: Benjamin Tissoires @ 2013-09-11 20:12 UTC (permalink / raw)
To: Benjamin Tissoires, Jiri Kosina, linux-input, linux-kernel
In-Reply-To: <1378930345-6670-1-git-send-email-benjamin.tissoires@redhat.com>
The usb packets are exactly the same, but it makes it a little bit more
independent of the transport layer.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-sony.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index b18320d..bc37a18 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -419,21 +419,14 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
*/
static int sixaxis_set_operational_usb(struct hid_device *hdev)
{
- struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
- struct usb_device *dev = interface_to_usbdev(intf);
- __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
int ret;
char *buf = kmalloc(18, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- HID_REQ_GET_REPORT,
- USB_DIR_IN | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE,
- (3 << 8) | 0xf2, ifnum, buf, 17,
- USB_CTRL_GET_TIMEOUT);
+ ret = hdev->hid_get_raw_report(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT);
+
if (ret < 0)
hid_err(hdev, "can't set operational mode\n");
--
1.8.3.1
^ permalink raw reply related
* [PATCH] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Florian Echtler @ 2013-09-11 21:26 UTC (permalink / raw)
To: linux-input
Cc: benjamin.tissoires, rydberg, dmitry.torokhov, dh.herrmann,
Florian Echtler
From: "Florian Echtler" <floe@butterbrot.org>
This patch adds support for the built-in multitouch sensor in the Samsung
SUR40 touchscreen device, also known as Microsoft Surface 2.0 or Microsoft
Pixelsense. Support for raw video output from the sensor as well as the
accelerometer will be added in a later patch.
Signed-off-by: Florian Echtler <floe@butterbrot.org>
---
drivers/input/touchscreen/Kconfig | 10 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/sur40.c | 444 ++++++++++++++++++++++++++++++++++++
3 files changed, 455 insertions(+)
create mode 100644 drivers/input/touchscreen/sur40.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 515cfe7..99aaf10 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -876,6 +876,16 @@ config TOUCHSCREEN_STMPE
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
+config TOUCHSCREEN_SUR40
+ tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
+ depends on USB
+ help
+ Say Y here if you want support for the Samsung SUR40 touchscreen
+ (also known as Microsoft Surface 2.0 or Microsoft PixelSense).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sur40.
+
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6bfbeab..b63a25d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
new file mode 100644
index 0000000..45f6cf4
--- /dev/null
+++ b/drivers/input/touchscreen/sur40.c
@@ -0,0 +1,444 @@
+/*
+ Surface2.0/SUR40/PixelSense input driver v0.0.1
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org>
+
+ Derived from the USB Skeleton driver 1.1,
+ Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com)
+
+ and from the Apple USB BCM5974 multitouch driver,
+ Copyright (c) 2008 Henrik Rydberg (rydberg@euromail.se)
+
+ and from the generic hid-multitouch driver,
+ Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/printk.h>
+#include <linux/input-polldev.h>
+#include <linux/input/mt.h>
+#include <linux/usb/input.h>
+
+/* read 512 bytes from endpoint 0x86 -> get header + blobs */
+struct sur40_header {
+
+ uint16_t type; /* always 0x0001 */
+ uint16_t count; /* count of blobs (if 0: continue prev. packet) */
+
+ uint32_t packet_id;
+
+ uint32_t timestamp; /* milliseconds (inc. by 16 or 17 each frame) */
+ uint32_t unknown; /* "epoch?" always 02/03 00 00 00 */
+};
+
+struct sur40_blob {
+
+ uint16_t blob_id;
+
+ uint8_t action; /* 0x02 = enter/exit, 0x03 = update (?) */
+ uint8_t unknown; /* always 0x01 or 0x02 (no idea what this is?) */
+
+ uint16_t bb_pos_x; /* upper left corner of bounding box */
+ uint16_t bb_pos_y;
+
+ uint16_t bb_size_x; /* size of bounding box */
+ uint16_t bb_size_y;
+
+ uint16_t pos_x; /* finger tip position */
+ uint16_t pos_y;
+
+ uint16_t ctr_x; /* centroid position */
+ uint16_t ctr_y;
+
+ uint16_t axis_x; /* somehow related to major/minor axis, mostly: */
+ uint16_t axis_y; /* axis_x == bb_size_y && axis_y == bb_size_x */
+
+ float angle; /* orientation in radians relative to x axis */
+ uint32_t area; /* size in pixels/pressure (?) */
+
+ uint8_t padding[32];
+};
+
+/* read 8 bytes using control message 0xc0,0xb1,0x00,0x00 */
+struct sur40_sensors {
+ uint16_t temp;
+ uint16_t acc_x;
+ uint16_t acc_y;
+ uint16_t acc_z;
+};
+
+/* version information */
+#define DRIVER_VERSION "0.0.1"
+#define DRIVER_SHORT "sur40"
+#define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>"
+#define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver"
+
+/* vendor and device IDs */
+#define ID_MICROSOFT 0x045e
+#define ID_SUR40 0x0775
+
+/* sensor resolution */
+#define SENSOR_RES_X 1920
+#define SENSOR_RES_Y 1080
+
+/* touch data endpoint */
+#define TOUCH_ENDPOINT 0x86
+
+/* polling interval (ms) */
+#define POLL_INTERVAL 10
+
+/* maximum number of contacts FIXME: this is a guess? */
+#define MAX_CONTACTS 64
+
+/* device ID table */
+static const struct usb_device_id sur40_table[] = {
+ {USB_DEVICE(ID_MICROSOFT, ID_SUR40)}, /* Samsung SUR40 */
+ {} /* terminating null entry */
+};
+
+/* control commands */
+#define SUR40_GET_VERSION 0xb0 /* 12 bytes string */
+#define SUR40_UNKNOWN1 0xb3 /* 5 bytes */
+#define SUR40_UNKNOWN2 0xc1 /* 24 bytes */
+
+#define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */
+#define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */
+
+/*
+ * Note: a earlier, non-public version of this driver used USB_RECIP_ENDPOINT
+ * here by mistake which is very likely to have corrupted the firmware EEPROM
+ * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug.
+ * Should you ever run into a similar problem, the background story to this
+ * incident and instructions on how to fix the corrupted EEPROM are available
+ * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html
+*/
+#define sur40_command(dev, command, index, buffer, size) \
+ usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0), \
+ command, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x00, \
+ index, buffer, size, 1000)
+
+MODULE_DEVICE_TABLE(usb, sur40_table);
+
+/* structure to hold all of our device specific stuff */
+struct sur40_state {
+
+ struct usb_device *usbdev; /* save the usb device pointer */
+ struct input_polled_dev *input; /* struct for polled input device */
+
+ unsigned char *bulk_in_buffer; /* the buffer to receive data */
+ size_t bulk_in_size; /* the maximum bulk packet size */
+ __u8 bulk_in_epaddr; /* address of the bulk in endpoint */
+
+ char phys[64]; /* buffer for phys name */
+};
+
+/* debug helper macro */
+#define get_dev(x) (&(x->usbdev->dev))
+
+/* initialization routine, called from sur40_open */
+static int sur40_init(struct sur40_state *dev)
+{
+ int result;
+ __u8 buffer[24];
+
+ /* stupidly replay the original MS driver init sequence */
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x00, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x01, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x02, buffer, 12);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_UNKNOWN2, 0x00, buffer, 24);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_UNKNOWN1, 0x00, buffer, 5);
+ if (result < 0)
+ return result;
+
+ result = sur40_command(dev, SUR40_GET_VERSION, 0x03, buffer, 12);
+
+ /* discard the result buffer - no known data inside except
+ some version strings, maybe extract these sometime.. */
+
+ return result;
+}
+
+/*
+ * callback routines from input_polled_dev
+*/
+
+/* enable the device, polling will now start */
+void sur40_open(struct input_polled_dev *polldev)
+{
+ struct sur40_state *sur40 = polldev->private;
+ dev_dbg(get_dev(sur40), "open\n");
+ sur40_init(sur40);
+}
+
+/* disable device, polling has stopped */
+void sur40_close(struct input_polled_dev *polldev)
+{
+ /* no known way to stop the device, except to stop polling */
+ struct sur40_state *sur40 = polldev->private;
+ dev_dbg(get_dev(sur40), "close\n");
+}
+
+/*
+ * this function is called when a whole contact has been processed,
+ * so that it can assign it to a slot and store the data there
+ */
+static void report_blob(struct sur40_blob *blob, struct input_dev *input)
+{
+ int wide, major, minor;
+
+ int slotnum = input_mt_get_slot_by_key(input, blob->blob_id);
+ if (slotnum < 0 || slotnum >= MAX_CONTACTS)
+ return;
+
+ input_mt_slot(input, slotnum);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
+ wide = (blob->bb_size_x > blob->bb_size_y);
+ major = max(blob->bb_size_x, blob->bb_size_y);
+ minor = min(blob->bb_size_x, blob->bb_size_y);
+
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, blob->pos_x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, blob->pos_y);
+ input_event(input, EV_ABS, ABS_MT_TOOL_X, blob->ctr_x);
+ input_event(input, EV_ABS, ABS_MT_TOOL_Y, blob->ctr_y);
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+}
+
+/* core function: poll for new input data */
+void sur40_poll(struct input_polled_dev *polldev)
+{
+
+ struct sur40_state *sur40 = polldev->private;
+ struct input_dev *input = polldev->input;
+ int result, bulk_read, need_blobs, packet_blobs, i;
+ uint32_t packet_id;
+
+ struct sur40_header *header =
+ (struct sur40_header *)(sur40->bulk_in_buffer);
+ struct sur40_blob *inblob =
+ (struct sur40_blob *)(sur40->bulk_in_buffer +
+ sizeof(struct sur40_header));
+
+ need_blobs = -1;
+
+ dev_dbg(get_dev(sur40), "poll\n");
+
+ do {
+
+ /* perform a blocking bulk read to get data from the device */
+ result = usb_bulk_msg(sur40->usbdev,
+ usb_rcvbulkpipe(sur40->usbdev, sur40->bulk_in_epaddr),
+ sur40->bulk_in_buffer, 512, &bulk_read, 1000);
+
+ dev_dbg(get_dev(sur40), "received %d bytes\n", bulk_read);
+
+ if (result < 0) {
+ dev_err(get_dev(sur40), "error in usb_bulk_read\n");
+ return;
+ }
+
+ result = bulk_read - sizeof(struct sur40_header);
+
+ if (result % sizeof(struct sur40_blob) != 0) {
+ dev_err(get_dev(sur40), "transfer size mismatch\n");
+ return;
+ }
+
+ /* first packet? */
+ if (need_blobs == -1) {
+ need_blobs = header->count;
+ dev_dbg(get_dev(sur40), "need %d blobs\n", need_blobs);
+ packet_id = header->packet_id;
+ }
+
+ /* sanity check. when video data is also being retrieved, the
+ * packet ID will usually increase in the middle of a series
+ * instead of at the end. */
+ if (packet_id != header->packet_id)
+ dev_warn(get_dev(sur40), "packet ID mismatch\n");
+
+ packet_blobs = result / sizeof(struct sur40_blob);
+ dev_dbg(get_dev(sur40), "received %d blobs\n", packet_blobs);
+
+ /* packets always contain at least 4 blobs, even if empty */
+ if (packet_blobs > need_blobs)
+ packet_blobs = need_blobs;
+
+ for (i = 0; i < packet_blobs; i++) {
+ need_blobs--;
+ dev_dbg(get_dev(sur40), "processing blob\n");
+ report_blob(&(inblob[i]), input);
+ }
+
+ } while (need_blobs > 0);
+
+ input_mt_sync_frame(input);
+ input_sync(input);
+}
+
+/*
+ * housekeeping routines
+*/
+
+/* initialize input device parameters */
+static void sur40_input_setup(struct input_dev *input_dev)
+{
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(EV_SYN, input_dev->evbit);
+ set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_MT_TOOL_X,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOOL_Y,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ /* max value unknown, but major/minor axis
+ * can never be larger than screen */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, SENSOR_RES_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
+ 0, SENSOR_RES_Y, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+
+ input_mt_init_slots(input_dev, MAX_CONTACTS,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+}
+
+/* clean up all allocated buffers/structs */
+static inline void sur40_delete(struct sur40_state *sur40)
+{
+ input_free_polled_device(sur40->input);
+ kfree(sur40->bulk_in_buffer);
+ kfree(sur40);
+}
+
+/* check candidate USB interface */
+static int sur40_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+ struct sur40_state *sur40;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct input_polled_dev *poll_dev;
+ int result;
+
+ /* check if we really have the right interface */
+ iface_desc = &interface->altsetting[0];
+ if (iface_desc->desc.bInterfaceClass != 0xFF)
+ return -ENODEV;
+
+ /* use endpoint #4 (0x86) */
+ endpoint = &iface_desc->endpoint[4].desc;
+ if (endpoint->bEndpointAddress != TOUCH_ENDPOINT)
+ return -ENODEV;
+
+ /* allocate memory for our device state and initialize it */
+ sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL);
+ poll_dev = input_allocate_polled_device();
+ if (!sur40 || !poll_dev)
+ return -ENOMEM;
+
+ /* setup polled input device control struct */
+ poll_dev->private = sur40;
+ poll_dev->poll_interval = POLL_INTERVAL;
+ poll_dev->open = sur40_open;
+ poll_dev->poll = sur40_poll;
+ poll_dev->close = sur40_close;
+
+ /* setup regular input device struct */
+ sur40_input_setup(poll_dev->input);
+
+ poll_dev->input->name = "Samsung SUR40";
+ usb_to_input_id(usbdev, &(poll_dev->input->id));
+ usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys));
+ strlcat(sur40->phys, "/input0", sizeof(sur40->phys));
+ poll_dev->input->phys = sur40->phys;
+
+ sur40->usbdev = usbdev;
+ sur40->input = poll_dev;
+
+ /* use the bulk-in endpoint tested above */
+ sur40->bulk_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ sur40->bulk_in_epaddr = endpoint->bEndpointAddress;
+ sur40->bulk_in_buffer = kmalloc(2 * sur40->bulk_in_size, GFP_KERNEL);
+ if (!sur40->bulk_in_buffer) {
+ dev_err(&interface->dev, "Unable to allocate input buffer.");
+ sur40_delete(sur40);
+ return -ENOMEM;
+ }
+
+ result = input_register_polled_device(poll_dev);
+ if (result) {
+ dev_err(&interface->dev,
+ "Unable to register polled input device.");
+ sur40_delete(sur40);
+ return result;
+ }
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, sur40);
+ dev_info(&interface->dev, "%s now attached\n", DRIVER_DESC);
+
+ return 0;
+}
+
+/* unregister device & clean up */
+static void sur40_disconnect(struct usb_interface *interface)
+{
+ struct sur40_state *sur40 = usb_get_intfdata(interface);
+
+ input_unregister_polled_device(sur40->input);
+
+ usb_set_intfdata(interface, NULL);
+
+ sur40_delete(sur40);
+
+ dev_info(&interface->dev, "%s now disconnected\n", DRIVER_DESC);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver sur40_driver = {
+ .name = DRIVER_SHORT,
+ .probe = sur40_probe,
+ .disconnect = sur40_disconnect,
+ .id_table = sur40_table,
+};
+
+module_usb_driver(sur40_driver);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
* Re: [RFC PATCH] amba: Ensure drvdata is NULL
From: Michal Simek @ 2013-09-12 5:57 UTC (permalink / raw)
To: Michal Simek, Russell King
Cc: linux-kernel, Vinod Koul, Dan Williams, Dmitry Torokhov,
Chris Ball, Alessandro Zummo, Linus Walleij, Mark Brown,
Greg Kroah-Hartman, Jiri Slaby, Jean-Christophe Plagniol-Villard,
Tomi Valkeinen, Wim Van Sebroeck, Andrew Morton, zhangwei(Jovi),
Randy Dunlap, linux-arm-kernel, linux-input, linux-mmc, rtc-linux,
linux-spi, linux-serial, linux-fbdev, linux-watchdog
In-Reply-To: <346db238d6c8c418bddb1e8a166e9818b5074c06.1378305864.git.michal.simek@xilinx.com>
[-- Attachment #1: Type: text/plain, Size: 8371 bytes --]
Hi Russell,
any comment on this one?
Thanks,
Michal
On 09/04/2013 04:44 PM, Michal Simek wrote:
> This patch is inpired by the patch for drvdata
> "device-core: Ensure drvdata = NULL when no driver is bound"
> (sha1: 0998d0631001288a5974afc0b2a5f568bcdecb4d)
>
> Also it fixes all occurences in drivers.
>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> arch/arm/kernel/etm.c | 6 ------
> drivers/amba/bus.c | 2 ++
> drivers/dma/pl330.c | 3 ---
> drivers/input/serio/ambakmi.c | 2 --
> drivers/mmc/host/mmci.c | 2 --
> drivers/rtc/rtc-pl030.c | 2 --
> drivers/rtc/rtc-pl031.c | 2 --
> drivers/spi/spi-pl022.c | 1 -
> drivers/tty/serial/amba-pl010.c | 3 ---
> drivers/tty/serial/amba-pl011.c | 3 ---
> drivers/video/amba-clcd.c | 2 --
> drivers/watchdog/sp805_wdt.c | 1 -
> 12 files changed, 2 insertions(+), 27 deletions(-)
>
> diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
> index 8ff0ecd..131a6ab 100644
> --- a/arch/arm/kernel/etm.c
> +++ b/arch/arm/kernel/etm.c
> @@ -385,7 +385,6 @@ out:
> return ret;
>
> out_unmap:
> - amba_set_drvdata(dev, NULL);
> iounmap(t->etb_regs);
>
> out_release:
> @@ -398,8 +397,6 @@ static int etb_remove(struct amba_device *dev)
> {
> struct tracectx *t = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> iounmap(t->etb_regs);
> t->etb_regs = NULL;
>
> @@ -588,7 +585,6 @@ out:
> return ret;
>
> out_unmap:
> - amba_set_drvdata(dev, NULL);
> iounmap(t->etm_regs);
>
> out_release:
> @@ -601,8 +597,6 @@ static int etm_remove(struct amba_device *dev)
> {
> struct tracectx *t = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> iounmap(t->etm_regs);
> t->etm_regs = NULL;
>
> diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
> index c670727..9762090 100644
> --- a/drivers/amba/bus.c
> +++ b/drivers/amba/bus.c
> @@ -373,6 +373,7 @@ static int amba_probe(struct device *dev)
> if (ret == 0)
> break;
>
> + amba_set_drvdata(pcdev, NULL);
> pm_runtime_disable(dev);
> pm_runtime_set_suspended(dev);
> pm_runtime_put_noidle(dev);
> @@ -391,6 +392,7 @@ static int amba_remove(struct device *dev)
>
> pm_runtime_get_sync(dev);
> ret = drv->remove(pcdev);
> + amba_set_drvdata(pcdev, NULL);
> pm_runtime_put_noidle(dev);
>
> /* Undo the runtime PM settings in amba_probe() */
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index fa645d8..626f99e 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -3026,8 +3026,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
>
> return 0;
> probe_err3:
> - amba_set_drvdata(adev, NULL);
> -
> /* Idle the DMAC */
> list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
> chan.device_node) {
> @@ -3061,7 +3059,6 @@ static int pl330_remove(struct amba_device *adev)
> of_dma_controller_free(adev->dev.of_node);
>
> dma_async_device_unregister(&pdmac->ddma);
> - amba_set_drvdata(adev, NULL);
>
> /* Idle the DMAC */
> list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
> diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
> index 4e2fd44..b7c206d 100644
> --- a/drivers/input/serio/ambakmi.c
> +++ b/drivers/input/serio/ambakmi.c
> @@ -167,8 +167,6 @@ static int amba_kmi_remove(struct amba_device *dev)
> {
> struct amba_kmi_port *kmi = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> serio_unregister_port(kmi->io);
> clk_put(kmi->clk);
> iounmap(kmi->base);
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index c3785ed..07e17f1 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -1678,8 +1678,6 @@ static int mmci_remove(struct amba_device *dev)
> {
> struct mmc_host *mmc = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> if (mmc) {
> struct mmci_host *host = mmc_priv(mmc);
>
> diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
> index 22bacdb..a804f75 100644
> --- a/drivers/rtc/rtc-pl030.c
> +++ b/drivers/rtc/rtc-pl030.c
> @@ -153,8 +153,6 @@ static int pl030_remove(struct amba_device *dev)
> {
> struct pl030_rtc *rtc = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> writel(0, rtc->base + RTC_CR);
>
> free_irq(dev->irq[0], rtc);
> diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
> index 0f0609b..c9ca86e 100644
> --- a/drivers/rtc/rtc-pl031.c
> +++ b/drivers/rtc/rtc-pl031.c
> @@ -305,7 +305,6 @@ static int pl031_remove(struct amba_device *adev)
> {
> struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
>
> - amba_set_drvdata(adev, NULL);
> free_irq(adev->irq[0], ldata);
> rtc_device_unregister(ldata->rtc);
> iounmap(ldata->base);
> @@ -392,7 +391,6 @@ out_no_irq:
> rtc_device_unregister(ldata->rtc);
> out_no_rtc:
> iounmap(ldata->base);
> - amba_set_drvdata(adev, NULL);
> out_no_remap:
> kfree(ldata);
> out:
> diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
> index abef061..e12813e 100644
> --- a/drivers/spi/spi-pl022.c
> +++ b/drivers/spi/spi-pl022.c
> @@ -2306,7 +2306,6 @@ pl022_remove(struct amba_device *adev)
> amba_release_regions(adev);
> tasklet_disable(&pl022->pump_transfers);
> spi_unregister_master(pl022->master);
> - amba_set_drvdata(adev, NULL);
> return 0;
> }
>
> diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
> index c368405..f630b78 100644
> --- a/drivers/tty/serial/amba-pl010.c
> +++ b/drivers/tty/serial/amba-pl010.c
> @@ -728,7 +728,6 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
> amba_set_drvdata(dev, uap);
> ret = uart_add_one_port(&amba_reg, &uap->port);
> if (ret) {
> - amba_set_drvdata(dev, NULL);
> amba_ports[i] = NULL;
> clk_put(uap->clk);
> unmap:
> @@ -745,8 +744,6 @@ static int pl010_remove(struct amba_device *dev)
> struct uart_amba_port *uap = amba_get_drvdata(dev);
> int i;
>
> - amba_set_drvdata(dev, NULL);
> -
> uart_remove_one_port(&amba_reg, &uap->port);
>
> for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
> diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
> index 28b35ad..2a1efe0 100644
> --- a/drivers/tty/serial/amba-pl011.c
> +++ b/drivers/tty/serial/amba-pl011.c
> @@ -2143,7 +2143,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
> amba_set_drvdata(dev, uap);
> ret = uart_add_one_port(&amba_reg, &uap->port);
> if (ret) {
> - amba_set_drvdata(dev, NULL);
> amba_ports[i] = NULL;
> pl011_dma_remove(uap);
> }
> @@ -2156,8 +2155,6 @@ static int pl011_remove(struct amba_device *dev)
> struct uart_amba_port *uap = amba_get_drvdata(dev);
> int i;
>
> - amba_set_drvdata(dev, NULL);
> -
> uart_remove_one_port(&amba_reg, &uap->port);
>
> for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
> diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
> index 0a2cce7..0bab6ab 100644
> --- a/drivers/video/amba-clcd.c
> +++ b/drivers/video/amba-clcd.c
> @@ -594,8 +594,6 @@ static int clcdfb_remove(struct amba_device *dev)
> {
> struct clcd_fb *fb = amba_get_drvdata(dev);
>
> - amba_set_drvdata(dev, NULL);
> -
> clcdfb_disable(fb);
> unregister_framebuffer(&fb->fb);
> if (fb->fb.cmap.len)
> diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
> index 58df98a..3f786ce 100644
> --- a/drivers/watchdog/sp805_wdt.c
> +++ b/drivers/watchdog/sp805_wdt.c
> @@ -268,7 +268,6 @@ static int sp805_wdt_remove(struct amba_device *adev)
> struct sp805_wdt *wdt = amba_get_drvdata(adev);
>
> watchdog_unregister_device(&wdt->wdd);
> - amba_set_drvdata(adev, NULL);
> watchdog_set_drvdata(&wdt->wdd, NULL);
>
> return 0;
> --
> 1.8.2.3
>
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
^ permalink raw reply
* [HELP] mediabuttons/buttons_backlight on MSI G-series laptops
From: Vadim A. Misbakh-Soloviov @ 2013-09-12 8:49 UTC (permalink / raw)
To: linux-input
[-- Attachment #1: Type: text/plain, Size: 1218 bytes --]
Hi, list!
I wat to try to write a kernel driver for some mediabuttons (and their
backlight) on my laptop, that don't want to work otherwise.
First of all, can you suggest me some ways for reverse-engineering if I
have no MS Windows OS (and don't want to buy it and even to install it)?
Actually, exactly that buttons requires additional software to work even
on windows (two different programms for Win7 and Win8, both on .NET).
Unfortunately, kernel totally ignores two of that buttons, DisplayOff
(with it's backlight) and FlightMode (without backlight): neither evbug
nor acpid can't see any events on it. And it is also some buttons, that
requires "setkeycodes", including "Eject" one, that works fine at
BIOS/GRUB2 stage, for example. Also, it is virtual buttons on plugging
in/out AC cord, CoolerBooster and Turbo one.
So, there is may things, that requires to be rewritten, but I don't
know, if it is okay to redefine such behaviour in module.
P.S. I talking about MSI GE60 0NC (problem is the same for all of
G-series laptops), so if anyone already working on this issue — I'd glad
to participate.
P.P.S. I already tried platform-dependent code for MSI, but without any
luck.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]
^ permalink raw reply
* Re: [PATCH v3 03/10] HID: sony: validate HID output report details
From: Josh Boyer @ 2013-09-12 12:39 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, Linux-Kernel@Vger. Kernel. Org
In-Reply-To: <1378929419-6269-4-git-send-email-benjamin.tissoires@redhat.com>
On Wed, Sep 11, 2013 at 3:56 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> From: Kees Cook <keescook@chromium.org>
>
> This driver must validate the availability of the HID output report and
> its size before it can write LED states via buzz_set_leds(). This stops
> a heap overflow that is possible if a device provides a malicious HID
> output report:
>
> [ 108.171280] usb 1-1: New USB device found, idVendor=054c, idProduct=0002
> ...
> [ 117.507877] BUG kmalloc-192 (Not tainted): Redzone overwritten
>
> CVE-2013-2890
>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Cc: stable@vger.kernel.org
> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
As far as I know, this should be Cc: stable@vger.kernel.org #3.11, correct?
josh
> ---
> v3:
> - no changes
>
> drivers/hid/hid-sony.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
> index 30dbb6b..b18320d 100644
> --- a/drivers/hid/hid-sony.c
> +++ b/drivers/hid/hid-sony.c
> @@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev)
> drv_data = hid_get_drvdata(hdev);
> BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
>
> + /* Validate expected report characteristics. */
> + if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
> + return -ENODEV;
> +
> buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
> if (!buzz) {
> hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
> --
> 1.8.3.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v3 03/10] HID: sony: validate HID output report details
From: Benjamin Tissoires @ 2013-09-12 14:11 UTC (permalink / raw)
To: Josh Boyer
Cc: Benjamin Tissoires, Kees Cook, Henrik Rydberg, Jiri Kosina,
linux-input, Linux-Kernel@Vger. Kernel. Org
In-Reply-To: <CA+5PVA5LAzseeqv_OGPX57tnq+16smZRv72fZ=H_GN9BegDXcQ@mail.gmail.com>
On 12/09/13 14:39, Josh Boyer wrote:
> On Wed, Sep 11, 2013 at 3:56 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
>> From: Kees Cook <keescook@chromium.org>
>>
>> This driver must validate the availability of the HID output report and
>> its size before it can write LED states via buzz_set_leds(). This stops
>> a heap overflow that is possible if a device provides a malicious HID
>> output report:
>>
>> [ 108.171280] usb 1-1: New USB device found, idVendor=054c, idProduct=0002
>> ...
>> [ 117.507877] BUG kmalloc-192 (Not tainted): Redzone overwritten
>>
>> CVE-2013-2890
>>
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> Cc: stable@vger.kernel.org
>> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>
> As far as I know, this should be Cc: stable@vger.kernel.org #3.11, correct?
>
Yep, for this one, only 3.11 is impacted.
Thanks Josh. And sorry for being to lazy to have added the proper tags :(
Cheers,
Benjamin
^ permalink raw reply
* [PATCH v2 0/2] Improve the performance of alps v5-protocol's touchpad
From: Yunkang Tang @ 2013-09-13 4:03 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: yunkang.tang, linux-input
Hi all,
Here is the v2 of improving ALPS v5 protocol device.
Change since v1:
- fix the issue that previous patches were broken by mail system.
- split the modification to 2 patches.
- Change dev2's name to "ALPS PS/2 Device"
Best Regards,
Tommy
^ permalink raw reply
* [PATCH v2 1/2] Add an additional argument for decode routine, change secondary device name
From: Yunkang Tang @ 2013-09-13 4:03 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: yunkang.tang, linux-input
In-Reply-To: <1379045010-3347-1-git-send-email-yunkang.tang@cn.alps.com>
From: Yunkang Tang <yunkang.tang@cn.alps.com>
- Add an addition argument for decode routine, new devices need this info.
- Change the dev2's name from "PS/2 Mouse" to "ALPS PS/2 Device".
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
drivers/input/mouse/alps.c | 17 ++++++++++-------
drivers/input/mouse/alps.h | 5 +++--
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7c5d72a..7e8a4fb 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -461,7 +461,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
f->ts_middle = !!(p[3] & 0x40);
}
-static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
f->first_mp = !!(p[4] & 0x40);
f->is_mp = !!(p[0] & 0x40);
@@ -482,15 +483,17 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
alps_decode_buttons_v3(f, p);
}
-static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
- alps_decode_pinnacle(f, p);
+ alps_decode_pinnacle(f, p, psmouse);
f->x_map |= (p[5] & 0x10) << 11;
f->y_map |= (p[5] & 0x20) << 6;
}
-static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse)
{
f->first_mp = !!(p[0] & 0x02);
f->is_mp = !!(p[0] & 0x20);
@@ -523,7 +526,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
int fingers = 0, bmap_fingers;
struct alps_fields f;
- priv->decode_fields(&f, packet);
+ priv->decode_fields(&f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -552,7 +555,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
fingers = bmap_fingers;
/* Now process position packet */
- priv->decode_fields(&f, priv->multi_data);
+ priv->decode_fields(&f, priv->multi_data, psmouse);
} else {
priv->multi_packet = 0;
}
@@ -1792,7 +1795,7 @@ int alps_init(struct psmouse *psmouse)
snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = (priv->flags & ALPS_DUALPOINT) ?
- "DualPoint Stick" : "PS/2 Mouse";
+ "DualPoint Stick" : "ALPS PS/2 Device";
dev2->id.bustype = BUS_I8042;
dev2->id.vendor = 0x0002;
dev2->id.product = PSMOUSE_ALPS;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index eee5985..cdc10f3 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -69,7 +69,7 @@ struct alps_nibble_commands {
* @y: Y position for ST.
* @z: Z position for ST.
* @first_mp: Packet is the first of a multi-packet report.
- * @is_mp: Packet is part of a multi-packet report.
+ * @is_mp: Packet is the last of a multi-packet report.
* @left: Left touchpad button is active.
* @right: Right touchpad button is active.
* @middle: Middle touchpad button is active.
@@ -145,7 +145,8 @@ struct alps_data {
int (*hw_init)(struct psmouse *psmouse);
void (*process_packet)(struct psmouse *psmouse);
- void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+ void (*decode_fields)(struct alps_fields *f, unsigned char *p,
+ struct psmouse *psmouse);
void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
int prev_fin;
--
1.8.1.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox