* Re: [PATCH] Input: gpio_keys - wakeup_trigger
From: Doug Anderson @ 2013-09-13 23:56 UTC (permalink / raw)
To: Benson Leung
Cc: Dmitry Torokhov,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, david-/Q/L1SwJa3aEVqv0pETR8A
In-Reply-To: <1379109160-32437-1-git-send-email-bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Benson,
On Fri, Sep 13, 2013 at 2:52 PM, Benson Leung <bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
> Allow wakeup_trigger to be defined per gpio button. Currently, all
> gpio buttons are set up as IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING.
> It may be more appropriate to only wake the system on one edge, for example
> if the gpio is for a Lid Switch.
>
> Signed-off-by: Benson Leung <bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
As discussed out of band, I'd tend to put the masking/error checking
in gpio_keys_get_devtree_pdata() then just rely on non-DT users not to
pass in nonsense, but I don't feel that strongly about it, so:
Reviewed-by: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] Input: gpio_keys - wakeup_trigger
From: Benson Leung @ 2013-09-13 21:52 UTC (permalink / raw)
To: dmitry.torokhov, linux-kernel, linux-input, linux-gpio,
devicetree, david
Cc: bleung, dianders
Allow wakeup_trigger to be defined per gpio button. Currently, all
gpio buttons are set up as IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING.
It may be more appropriate to only wake the system on one edge, for example
if the gpio is for a Lid Switch.
Signed-off-by: Benson Leung <bleung@chromium.org>
---
.../devicetree/bindings/gpio/gpio_keys.txt | 7 +++++++
drivers/input/keyboard/gpio_keys.c | 23 ++++++++++++++++++++--
include/linux/gpio_keys.h | 3 +++
3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
index 5c2c021..243f569 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_keys.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -20,6 +20,13 @@ Optional subnode-properties:
- debounce-interval: Debouncing interval time in milliseconds.
If not specified defaults to 5.
- gpio-key,wakeup: Boolean, button can wake-up the system.
+ - gpio-key,wakeup-trigger : Specifies the type of wakeup behavior.
+ <1> == Rising Edge Trigger
+ <2> == Falling Edge Trigger
+ <3> == Both Rising and Falling Edge Trigger
+ <4> == Level High Trigger
+ <8> == Level Low Trigger
+ If not specified, defaults to <3> == Both Rising and Falling.
Example nodes:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 440ce32..28b6992 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -40,6 +40,7 @@ struct gpio_button_data {
spinlock_t lock;
bool disabled;
bool key_pressed;
+ unsigned long irqflags;
};
struct gpio_keys_drvdata {
@@ -493,6 +494,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
irqflags = 0;
}
+ bdata->irqflags = irqflags;
+
input_set_capability(input, button->type ?: EV_KEY, button->code);
/*
@@ -643,6 +646,9 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (of_property_read_u32(pp, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
+
+ of_property_read_u32(pp, "gpio-key,wakeup-trigger",
+ &button->wakeup_trigger);
}
if (pdata->nbuttons == 0) {
@@ -811,8 +817,14 @@ static int gpio_keys_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
- if (bdata->button->wakeup)
+ if (bdata->button->wakeup) {
+ unsigned int flags;
+ flags = bdata->button->wakeup_trigger &
+ IRQF_TRIGGER_MASK;
+ if (flags && flags != bdata->irqflags)
+ irq_set_irq_type(bdata->irq, flags);
enable_irq_wake(bdata->irq);
+ }
}
} else {
mutex_lock(&input->mutex);
@@ -834,8 +846,15 @@ static int gpio_keys_resume(struct device *dev)
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
- if (bdata->button->wakeup)
+ if (bdata->button->wakeup) {
+ unsigned int flags;
+ flags = bdata->button->wakeup_trigger &
+ IRQF_TRIGGER_MASK;
disable_irq_wake(bdata->irq);
+ if (flags && flags != bdata->irqflags)
+ irq_set_irq_type(bdata->irq,
+ bdata->irqflags);
+ }
}
} else {
mutex_lock(&input->mutex);
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index a7e977f..d8d5a4f 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -15,6 +15,9 @@ struct gpio_keys_button {
bool can_disable;
int value; /* axis value for EV_ABS */
unsigned int irq; /* Irq number in case of interrupt keys */
+
+ /* trigger value (IRQF_TRIGGER_*) while used as a wake-up source */
+ unsigned int wakeup_trigger;
};
struct gpio_keys_platform_data {
--
1.8.4
^ permalink raw reply related
* Re: [PATCH v3 00/10] HID: validate report details
From: Jiri Kosina @ 2013-09-13 13:15 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Benjamin Tissoires, Kees Cook, Henrik Rydberg, linux-input,
linux-kernel
In-Reply-To: <1378929419-6269-1-git-send-email-benjamin.tissoires@redhat.com>
On Wed, 11 Sep 2013, Benjamin Tissoires wrote:
> here is the v3 of the CVE fixes.
Now applied, will be pushing to Linus for 3.12. Thanks everybody,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re
From: Emirate @ 2013-09-13 10:01 UTC (permalink / raw)
--
Do you received our last notification?
^ permalink raw reply
* [PATCH v2 2/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
In-Reply-To: <1379045010-3347-1-git-send-email-yunkang.tang@cn.alps.com>
From: Yunkang Tang <yunkang.tang@cn.alps.com>
- Calculate the device's dimension in alps_identify().
- Change the logic of packet decoding.
- Add the new data process logic.
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
drivers/input/mouse/alps.c | 278 ++++++++++++++++++++++++++++++++++++++++++---
drivers/input/mouse/alps.h | 4 +
2 files changed, 264 insertions(+), 18 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7e8a4fb..86c956a 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -257,6 +257,75 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
}
/*
+ * Process bitmap data for V5 protocols. Return value is null.
+ *
+ * The bitmaps don't have enough data to track fingers, so this function
+ * only generates points representing a bounding box of at most two contacts.
+ * These two points are returned in x1, y1, x2, and y2.
+ */
+static void alps_process_bitmap_dolphin(struct alps_data *priv,
+ struct alps_fields *fields,
+ int *x1, int *y1, int *x2, int *y2)
+{
+ struct alps_palm_bitmap {
+ int start_bit;
+ int end_bit;
+ };
+
+ int i;
+ int box_middle_x, box_middle_y;
+ unsigned int x_map, y_map;
+ struct alps_palm_bitmap x_bitmap = {0}, y_bitmap = {0};
+
+ x_map = fields->x_map;
+ y_map = fields->y_map;
+
+ if (!x_map || !y_map)
+ return;
+
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ if (fields->fingers > 1) {
+ for (i = 0; i < 32; i++) {
+ if (x_map & (1 << i)) {
+ x_bitmap.end_bit = priv->x_bits - i;
+ break;
+ }
+ }
+
+ for (i = 31; i >= 0; i--) {
+ if (x_map & (1 << i)) {
+ x_bitmap.start_bit = priv->x_bits - i;
+ break;
+ }
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (y_map & (1 << i)) {
+ y_bitmap.start_bit = i;
+ break;
+ }
+ }
+
+ for (i = 31; i >= 0; i--) {
+ if (y_map & (1 << i)) {
+ y_bitmap.end_bit = i;
+ break;
+ }
+ }
+
+ box_middle_x = (priv->x_max * (x_bitmap.start_bit + x_bitmap.end_bit)) /
+ (2 * (priv->x_bits - 1));
+ box_middle_y = (priv->y_max * (y_bitmap.start_bit + y_bitmap.end_bit)) /
+ (2 * (priv->y_bits - 1));
+ *x1 = fields->x;
+ *y1 = fields->y;
+ *x2 = 2 * box_middle_x - *x1;
+ *y2 = 2 * box_middle_y - *y1;
+ }
+}
+
+/*
* Process bitmap data from v3 and v4 protocols. Returns the number of
* fingers detected. A return value of 0 means at least one of the
* bitmaps was empty.
@@ -495,25 +564,55 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
+ unsigned int palm_high = 0, palm_low = 0, palm_mask = 0;
+ int i, remain_xbits;
+ struct alps_data *priv = psmouse->private;
+
f->first_mp = !!(p[0] & 0x02);
f->is_mp = !!(p[0] & 0x20);
- f->fingers = ((p[0] & 0x6) >> 1 |
+ if (!f->is_mp) {
+ f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+ f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+ f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
+ alps_decode_buttons_v3(f, p);
+ } else {
+ f->fingers = ((p[0] & 0x6) >> 1 |
(p[0] & 0x10) >> 2);
- f->x_map = ((p[2] & 0x60) >> 5) |
- ((p[4] & 0x7f) << 2) |
- ((p[5] & 0x7f) << 9) |
- ((p[3] & 0x07) << 16) |
- ((p[3] & 0x70) << 15) |
- ((p[0] & 0x01) << 22);
- f->y_map = (p[1] & 0x7f) |
- ((p[2] & 0x1f) << 7);
-
- f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
- f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
- f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
+ palm_low = (p[1] & 0x7f) |
+ ((p[2] & 0x7f) << 7) |
+ ((p[4] & 0x7f) << 14) |
+ ((p[5] & 0x7f) << 21) |
+ ((p[3] & 0x07) << 28) | ((p[3] & 0x10) << 27);
+ palm_high = ((p[3] & 0x60) >> 5) | ((p[0] & 0x01) << 2);
+
+ for (i = 0; i < priv->y_bits; i++)
+ palm_mask |= 1 << i;
+
+ /* Y-profile is stored in P(0) to p(n), n = y_bits; */
+ f->y_map = palm_low & palm_mask;
+
+ /* X-profile is stored in p(n) to p(n+x_bits). */
+ palm_mask = 0;
+ for (i = priv->y_bits; i < 32 && i < priv->y_bits + priv->x_bits; i++)
+ palm_mask |= 1 << i;
+
+ f->x_map = ((palm_low & (palm_mask)) >> priv->y_bits);
+
+ /*
+ * In some cases, palm_low's 32bit is not enough to save
+ * all X&Y-profiles, we need to use palm_high.
+ */
+ remain_xbits = priv->x_bits + priv->y_bits - 32;
+ if (remain_xbits > 0) {
+ palm_mask = 0;
+ for (i = 0; i < remain_xbits; i++)
+ palm_mask |= 1 << i;
+
+ f->x_map |= ((palm_high & palm_mask) << (32 - priv->y_bits));
+ }
+ }
}
static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
@@ -745,6 +844,112 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
input_sync(dev);
}
+
+static void alps_process_touchpad_packet_v5(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ int fingers = 0;
+ struct alps_fields f;
+
+ priv->decode_fields(&f, packet, psmouse);
+
+ /*
+ * There's no single feature of touchpad position and bitmap packets
+ * that can be used to distinguish between them. We rely on the fact
+ * that a bitmap packet should always follow a position packet with
+ * bit 6 of packet[4] set.
+ */
+ if (priv->multi_packet) {
+ /*
+ * Sometimes a position packet will indicate a multi-packet
+ * sequence, but then what follows is another position
+ * packet. Check for this, and when it happens process the
+ * position packet as usual.
+ */
+ if (f.is_mp) {
+ fingers = f.fingers;
+ priv->decode_fields(&f, priv->multi_data, psmouse);
+ alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+ &x2, &y2);
+ } else {
+ priv->multi_packet = 0;
+ }
+ }
+
+ /*
+ * Bit 6 of byte 0 is not usually set in position packets. The only
+ * times it seems to be set is in situations where the data is
+ * suspect anyway, e.g. a palm resting flat on the touchpad. Given
+ * this combined with the fact that this bit is useful for filtering
+ * out misidentified bitmap packets, we reject anything with this
+ * bit set.
+ */
+ if (f.is_mp)
+ return;
+
+ if (!priv->multi_packet && f.first_mp) {
+ priv->multi_packet = 1;
+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+ return;
+ }
+
+ priv->multi_packet = 0;
+
+ /*
+ * Sometimes the hardware sends a single packet with z = 0
+ * in the middle of a stream. Real releases generate packets
+ * with x, y, and z all zero, so these seem to be flukes.
+ * Ignore them.
+ */
+ if (f.x && f.y && !f.z)
+ return;
+
+ /*
+ * If we don't have MT data or the bitmaps were empty, we have
+ * to rely on ST data.
+ */
+ if (!fingers) {
+ x1 = f.x;
+ y1 = f.y;
+ fingers = f.z > 0 ? 1 : 0;
+ }
+
+ if (f.z >= 64)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_mt_report_finger_count(dev, fingers);
+
+ input_report_key(dev, BTN_LEFT, f.left);
+ input_report_key(dev, BTN_RIGHT, f.right);
+ input_report_key(dev, BTN_MIDDLE, f.middle);
+
+ if (f.z > 0) {
+ input_report_abs(dev, ABS_X, f.x);
+ input_report_abs(dev, ABS_Y, f.y);
+ }
+ input_report_abs(dev, ABS_PRESSURE, f.z);
+
+ input_sync(dev);
+}
+
+static void alps_process_packet_v5(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+
+ /* Ignore stick point data */
+ if (packet[0] == 0xD8)
+ return;
+
+ alps_process_touchpad_packet_v5(psmouse);
+}
+
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -1522,6 +1727,41 @@ error:
return -1;
}
+static int alps_dolphin_get_device_area(struct psmouse *psmouse,
+ struct alps_data *priv)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4] = {0};
+ int num_x_electrode, num_y_electrode;
+
+ if (alps_enter_command_mode(psmouse))
+ return -1;
+
+ if (ps2_command(ps2dev, NULL, 0x00EC) ||
+ ps2_command(ps2dev, NULL, 0x00F0) ||
+ ps2_command(ps2dev, NULL, 0x00F0) ||
+ ps2_command(ps2dev, NULL, 0x00F3) ||
+ ps2_command(ps2dev, NULL, 0x000A) ||
+ ps2_command(ps2dev, NULL, 0x00F3) ||
+ ps2_command(ps2dev, NULL, 0x000A))
+ return -1;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
+ num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
+ priv->x_bits = num_x_electrode;
+ priv->y_bits = num_y_electrode;
+ priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+ priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
+
+ if (alps_exit_command_mode(psmouse))
+ return -1;
+
+ return 0;
+}
+
static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
@@ -1574,7 +1814,7 @@ static void alps_set_defaults(struct alps_data *priv)
break;
case ALPS_PROTO_V5:
priv->hw_init = alps_hw_init_dolphin_v1;
- priv->process_packet = alps_process_packet_v3;
+ priv->process_packet = alps_process_packet_v5;
priv->decode_fields = alps_decode_dolphin;
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
@@ -1648,11 +1888,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
if (alps_match_table(psmouse, priv, e7, ec) == 0) {
return 0;
} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
- ec[0] == 0x73 && ec[1] == 0x01) {
+ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
priv->proto_version = ALPS_PROTO_V5;
alps_set_defaults(priv);
-
- return 0;
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
+ else
+ return 0;
} else if (ec[0] == 0x88 && ec[1] == 0x08) {
priv->proto_version = ALPS_PROTO_V3;
alps_set_defaults(priv);
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index cdc10f3..43d89fc7 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -18,6 +18,10 @@
#define ALPS_PROTO_V4 4
#define ALPS_PROTO_V5 5
+#define DOLPHIN_COUNT_PER_ELECTRODE 64
+#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
+#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
+
/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
--
1.8.1.2
^ permalink raw reply related
* [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
* [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
* 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
* 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
* [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: [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
* [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
* [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 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 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 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
* 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
* 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 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 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 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
* [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
* [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 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 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
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