From bdb5c57f209c3b78b3511476b233562496acd997 Mon Sep 17 00:00:00 2001 From: Florian Echtler Date: Fri, 8 Nov 2013 10:01:13 -0800 Subject: Input: add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense) 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 Reviewed-by: David Herrmann Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/sur40.c | 466 +++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/input/touchscreen/sur40.c (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 00d1e547b211..961d58d32647 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -906,6 +906,17 @@ 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 + select INPUT_POLLDEV + 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 7587883b8d38..62801f213346 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -54,6 +54,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 000000000000..cfd1b7e8c001 --- /dev/null +++ b/drivers/input/touchscreen/sur40.c @@ -0,0 +1,466 @@ +/* + * Surface2.0/SUR40/PixelSense input driver + * + * Copyright (c) 2013 by Florian 'floe' Echtler + * + * 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 + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* read 512 bytes from endpoint 0x86 -> get header + blobs */ +struct sur40_header { + + __le16 type; /* always 0x0001 */ + __le16 count; /* count of blobs (if 0: continue prev. packet) */ + + __le32 packet_id; /* unique ID for all packets in one frame */ + + __le32 timestamp; /* milliseconds (inc. by 16 or 17 each frame) */ + __le32 unknown; /* "epoch?" always 02/03 00 00 00 */ + +} __packed; + +struct sur40_blob { + + __le16 blob_id; + + u8 action; /* 0x02 = enter/exit, 0x03 = update (?) */ + u8 unknown; /* always 0x01 or 0x02 (no idea what this is?) */ + + __le16 bb_pos_x; /* upper left corner of bounding box */ + __le16 bb_pos_y; + + __le16 bb_size_x; /* size of bounding box */ + __le16 bb_size_y; + + __le16 pos_x; /* finger tip position */ + __le16 pos_y; + + __le16 ctr_x; /* centroid position */ + __le16 ctr_y; + + __le16 axis_x; /* somehow related to major/minor axis, mostly: */ + __le16 axis_y; /* axis_x == bb_size_y && axis_y == bb_size_x */ + + __le32 angle; /* orientation in radians relative to x axis - + actually an IEEE754 float, don't use in kernel */ + + __le32 area; /* size in pixels/pressure (?) */ + + u8 padding[32]; + +} __packed; + +/* combined header/blob data */ +struct sur40_data { + struct sur40_header header; + struct sur40_blob blobs[]; +} __packed; + + +/* version information */ +#define DRIVER_SHORT "sur40" +#define DRIVER_AUTHOR "Florian 'floe' Echtler " +#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 + +/* 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: an 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 +*/ + +struct sur40_state { + + struct usb_device *usbdev; + struct device *dev; + struct input_polled_dev *input; + + struct sur40_data *bulk_in_buffer; + size_t bulk_in_size; + u8 bulk_in_epaddr; + + char phys[64]; +}; + +static int sur40_command(struct sur40_state *dev, + u8 command, u16 index, void *buffer, u16 size) +{ + return 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); +} + +/* 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. */ +static void sur40_open(struct input_polled_dev *polldev) +{ + struct sur40_state *sur40 = polldev->private; + + dev_dbg(sur40->dev, "open\n"); + sur40_init(sur40); +} + +/* Disable device, polling has stopped. */ +static void sur40_close(struct input_polled_dev *polldev) +{ + struct sur40_state *sur40 = polldev->private; + + dev_dbg(sur40->dev, "close\n"); + /* + * There is no known way to stop the device, so we simply + * stop polling. + */ +} + +/* + * 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 sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) +{ + int wide, major, minor; + + int bb_size_x = le16_to_cpu(blob->bb_size_x); + int bb_size_y = le16_to_cpu(blob->bb_size_y); + + int pos_x = le16_to_cpu(blob->pos_x); + int pos_y = le16_to_cpu(blob->pos_y); + + int ctr_x = le16_to_cpu(blob->ctr_x); + int ctr_y = le16_to_cpu(blob->ctr_y); + + 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 = (bb_size_x > bb_size_y); + major = max(bb_size_x, bb_size_y); + minor = min(bb_size_x, bb_size_y); + + input_report_abs(input, ABS_MT_POSITION_X, pos_x); + input_report_abs(input, ABS_MT_POSITION_Y, pos_y); + input_report_abs(input, ABS_MT_TOOL_X, ctr_x); + input_report_abs(input, ABS_MT_TOOL_Y, ctr_y); + + /* TODO: use a better orientation measure */ + input_report_abs(input, ABS_MT_ORIENTATION, wide); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); + input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); +} + +/* core function: poll for new input data */ +static 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; + u32 packet_id; + + struct sur40_header *header = &sur40->bulk_in_buffer->header; + struct sur40_blob *inblob = &sur40->bulk_in_buffer->blobs[0]; + + dev_dbg(sur40->dev, "poll\n"); + + need_blobs = -1; + + 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, sur40->bulk_in_size, + &bulk_read, 1000); + + dev_dbg(sur40->dev, "received %d bytes\n", bulk_read); + + if (result < 0) { + dev_err(sur40->dev, "error in usb_bulk_read\n"); + return; + } + + result = bulk_read - sizeof(struct sur40_header); + + if (result % sizeof(struct sur40_blob) != 0) { + dev_err(sur40->dev, "transfer size mismatch\n"); + return; + } + + /* first packet? */ + if (need_blobs == -1) { + need_blobs = le16_to_cpu(header->count); + dev_dbg(sur40->dev, "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(sur40->dev, "packet ID mismatch\n"); + + packet_blobs = result / sizeof(struct sur40_blob); + dev_dbg(sur40->dev, "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(sur40->dev, "processing blob\n"); + sur40_report_blob(&(inblob[i]), input); + } + + } while (need_blobs > 0); + + input_mt_sync_frame(input); + input_sync(input); +} + +/* Initialize input device parameters. */ +static void sur40_input_setup(struct input_dev *input_dev) +{ + __set_bit(EV_KEY, 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); +} + +/* 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 error; + + /* 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); + if (!sur40) + return -ENOMEM; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + error = -ENOMEM; + goto err_free_dev; + } + + /* Set up polled input device control structure */ + 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; + + /* Set up regular input device structure */ + 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; + poll_dev->input->dev.parent = &interface->dev; + + sur40->usbdev = usbdev; + sur40->dev = &interface->dev; + sur40->input = poll_dev; + + /* use the bulk-in endpoint tested above */ + sur40->bulk_in_size = usb_endpoint_maxp(endpoint); + sur40->bulk_in_epaddr = endpoint->bEndpointAddress; + sur40->bulk_in_buffer = kmalloc(sur40->bulk_in_size, GFP_KERNEL); + if (!sur40->bulk_in_buffer) { + dev_err(&interface->dev, "Unable to allocate input buffer."); + error = -ENOMEM; + goto err_free_polldev; + } + + error = input_register_polled_device(poll_dev); + if (error) { + dev_err(&interface->dev, + "Unable to register polled input device."); + goto err_free_buffer; + } + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, sur40); + dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); + + return 0; + +err_free_buffer: + kfree(sur40->bulk_in_buffer); +err_free_polldev: + input_free_polled_device(sur40->input); +err_free_dev: + kfree(sur40); + + return error; +} + +/* 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); + input_free_polled_device(sur40->input); + kfree(sur40->bulk_in_buffer); + kfree(sur40); + + usb_set_intfdata(interface, NULL); + dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); +} + +static const struct usb_device_id sur40_table[] = { + { USB_DEVICE(ID_MICROSOFT, ID_SUR40) }, /* Samsung SUR40 */ + { } /* terminating null entry */ +}; +MODULE_DEVICE_TABLE(usb, sur40_table); + +/* 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"); -- cgit From 0221e670cd25bb41062031eaa653f6447707abc6 Mon Sep 17 00:00:00 2001 From: Xie XiuQi Date: Tue, 19 Nov 2013 13:15:43 -0800 Subject: Input: cyttsp4 - remove unnecessary work pending test Remove unnecessary work pending test before calling schedule_work(). It has been tested in queue_work_on() already. Signed-off-by: Xie XiuQi Reviewed-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cyttsp4_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 42d830efa316..a035a390f8e2 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1246,8 +1246,7 @@ static void cyttsp4_watchdog_timer(unsigned long handle) dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__); - if (!work_pending(&cd->watchdog_work)) - schedule_work(&cd->watchdog_work); + schedule_work(&cd->watchdog_work); return; } -- cgit From b64da05fb746c6ff5bcb9abeaa52684d1b08a2b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Nov 2013 13:28:06 -0800 Subject: Input: hp_sdc_rtc - unlock on error in hp_sdc_rtc_read_i8042timer() The transaction task here is hp_sdc_tasklet() and it releases the lock. The problem is if we aren't able to queue the transaction then we need to release the lock ourselves. Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/misc/hp_sdc_rtc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 86b822806e95..45e0e3e55de2 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -180,7 +180,10 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) if (WARN_ON(down_interruptible(&i8042tregs))) return -1; - if (hp_sdc_enqueue_transaction(&t)) return -1; + if (hp_sdc_enqueue_transaction(&t)) { + up(&i8042tregs); + return -1; + } /* Sleep until results come back. */ if (WARN_ON(down_interruptible(&i8042tregs))) -- cgit From 2d4bba146e1975fc277a4509304d98761016b8b7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 19 Nov 2013 14:01:47 -0800 Subject: Input: atmel-wm97xx - fix compile error Reported-by: Fengguang Wu Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel-wm97xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c index 268a35e55d7f..279c0e42b8a7 100644 --- a/drivers/input/touchscreen/atmel-wm97xx.c +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -391,7 +391,7 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static int atmel_wm97xx_suspend(struct *dev) +static int atmel_wm97xx_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); -- cgit From e4cfb034e89a1c7148f617735d92a3655d27773f Mon Sep 17 00:00:00 2001 From: Andrew Liu Date: Sat, 23 Nov 2013 10:06:36 -0800 Subject: Input: keyboard - "keycode & KEY_MAX" changes some keycode values For exmaple, keycode: KEY_OK(0x160) is changed by "and" operation with KEY_MAX(0x2ff) to KEY_KPENTER(96). Signed-off-by: Andrew Liu Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5588-keys.c | 3 ++- drivers/input/keyboard/adp5589-keys.c | 3 ++- drivers/input/keyboard/bf54x-keys.c | 3 ++- drivers/input/misc/pcf8574_keypad.c | 7 +++++-- 4 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index dbd2047f1641..3ed23513d881 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -536,7 +536,8 @@ static int adp5588_probe(struct i2c_client *client, __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); + if (kpad->keycode[i] <= KEY_MAX) + __set_bit(kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); if (kpad->gpimapsize) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 67d12b3427c9..60dafd4fa692 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -992,7 +992,8 @@ static int adp5589_probe(struct i2c_client *client, __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); + if (kpad->keycode[i] <= KEY_MAX) + __set_bit(kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); if (kpad->gpimapsize) diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index fc88fb48d70d..09b91d093087 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -289,7 +289,8 @@ static int bfin_kpad_probe(struct platform_device *pdev) __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit); + if (bf54x_kpad->keycode[i] <= KEY_MAX) + __set_bit(bf54x_kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); error = input_register_device(input); diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index e37392976fdd..0deca5a3c87f 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -113,9 +113,12 @@ static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_i idev->keycodemax = ARRAY_SIZE(lp->btncode); for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { - lp->btncode[i] = pcf8574_kp_btncode[i]; - __set_bit(lp->btncode[i] & KEY_MAX, idev->keybit); + if (lp->btncode[i] <= KEY_MAX) { + lp->btncode[i] = pcf8574_kp_btncode[i]; + __set_bit(lp->btncode[i], idev->keybit); + } } + __clear_bit(KEY_RESERVED, idev->keybit); sprintf(lp->name, DRV_NAME); sprintf(lp->phys, "kp_data/input0"); -- cgit From b884eb8c8502ca1fea497a02433c2b41de851f62 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Nov 2013 11:03:57 -0800 Subject: Input: sur40 - suppress false uninitialized variable warning We will never use packet_id before initializing it as we start with "need_blobs == -1" and will set packet_id there. Also use le32_to_cpu when fetching header->packet_id. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sur40.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index cfd1b7e8c001..f1cb05148b46 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -251,7 +251,7 @@ static 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; - u32 packet_id; + u32 uninitialized_var(packet_id); struct sur40_header *header = &sur40->bulk_in_buffer->header; struct sur40_blob *inblob = &sur40->bulk_in_buffer->blobs[0]; @@ -286,7 +286,7 @@ static void sur40_poll(struct input_polled_dev *polldev) if (need_blobs == -1) { need_blobs = le16_to_cpu(header->count); dev_dbg(sur40->dev, "need %d blobs\n", need_blobs); - packet_id = header->packet_id; + packet_id = le32_to_cpu(header->packet_id); } /* -- cgit From 4ef38351d770cc421f4a0c7a849fd13207fc5741 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Tue, 26 Nov 2013 18:16:17 -0800 Subject: Input: usbtouchscreen - separate report and transmit buffer size handling This patch supports the separate handling of the USB transfer buffer length and the length of the buffer used for multi packet support. For devices supporting multiple report or diagnostic packets, the USB transfer size is now limited to the USB endpoints wMaxPacketSize - otherwise it defaults to the configured report packet size as before. This fixes an issue where event reporting can be delayed for an arbitrary time for multi packet devices. For instance the report size for eGalax devices is defined to the 16 byte maximum diagnostic packet size as opposed to the 5 byte report packet size. In case the driver requests 16 byte from the USB interrupt endpoint, the USB host controller driver needs to split up the request into 2 accesses according to the endpoints wMaxPacketSize of 8 byte. When the first transfer is answered by the eGalax device with not less than the full 8 byte requested, the host controller has got no way of knowing whether the touch controller has got additional data queued and will issue the second transfer. If per example a liftoff event finishes at such a wMaxPacketSize boundary, the data will not be available to the usbtouch driver until a further event is triggered and transfered to the host. From user perspective the BTN_TOUCH release event in this case is stuck until the next touch down event. Signed-off-by: Christian Engelmayer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/usbtouchscreen.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 721fdb3597ca..819fb21ae58d 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -106,6 +106,7 @@ struct usbtouch_device_info { struct usbtouch_usb { unsigned char *data; dma_addr_t data_dma; + int data_size; unsigned char *buffer; int buf_len; struct urb *irq; @@ -1523,7 +1524,7 @@ static int usbtouch_reset_resume(struct usb_interface *intf) static void usbtouch_free_buffers(struct usb_device *udev, struct usbtouch_usb *usbtouch) { - usb_free_coherent(udev, usbtouch->type->rept_size, + usb_free_coherent(udev, usbtouch->data_size, usbtouch->data, usbtouch->data_dma); kfree(usbtouch->buffer); } @@ -1568,7 +1569,20 @@ static int usbtouch_probe(struct usb_interface *intf, if (!type->process_pkt) type->process_pkt = usbtouch_process_pkt; - usbtouch->data = usb_alloc_coherent(udev, type->rept_size, + usbtouch->data_size = type->rept_size; + if (type->get_pkt_len) { + /* + * When dealing with variable-length packets we should + * not request more than wMaxPacketSize bytes at once + * as we do not know if there is more data coming or + * we filled exactly wMaxPacketSize bytes and there is + * nothing else. + */ + usbtouch->data_size = min(usbtouch->data_size, + usb_endpoint_maxp(endpoint)); + } + + usbtouch->data = usb_alloc_coherent(udev, usbtouch->data_size, GFP_KERNEL, &usbtouch->data_dma); if (!usbtouch->data) goto out_free; @@ -1628,12 +1642,12 @@ static int usbtouch_probe(struct usb_interface *intf, if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT) usb_fill_int_urb(usbtouch->irq, udev, usb_rcvintpipe(udev, endpoint->bEndpointAddress), - usbtouch->data, type->rept_size, + usbtouch->data, usbtouch->data_size, usbtouch_irq, usbtouch, endpoint->bInterval); else usb_fill_bulk_urb(usbtouch->irq, udev, usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), - usbtouch->data, type->rept_size, + usbtouch->data, usbtouch->data_size, usbtouch_irq, usbtouch); usbtouch->irq->dev = udev; -- cgit From 9cb80b965eaf7af1369f6e16f48a05fbaaccc021 Mon Sep 17 00:00:00 2001 From: Matt Walker Date: Thu, 5 Dec 2013 12:39:02 -0800 Subject: Input: elantech - add support for newer (August 2013) devices Added detection for newer Elantech touchpads, so that kernel doesn't fall-back to default PS/2 driver. Supports touchpads released after ~August 2013. Fixes bug: https://lists.launchpad.net/kernel-packages/msg18481.html Tested on an Acer Aspire S7-392-6302. Signed-off by: Matt Walker Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 8551dcaf24db..597e9b8fc18d 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1313,6 +1313,7 @@ static int elantech_set_properties(struct elantech_data *etd) break; case 6: case 7: + case 8: etd->hw_version = 4; break; default: -- cgit From 95f75e91588afecfb0090988393653d21f5d1f91 Mon Sep 17 00:00:00 2001 From: Yunkang Tang Date: Sun, 1 Dec 2013 22:33:52 -0800 Subject: Input: ALPS - add support for DualPoint device on Dell XT2 model The device uses special MPU controller that necessitates the new initialization sequence for the device. We also define a new protocol for the trackpad that allows reporting better resolution than older V2 protocol. Signed-off-by: Yunkang Tang Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 206 ++++++++++++++++++++++++++++++++++++++++++++- drivers/input/mouse/alps.h | 1 + 2 files changed, 204 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index ca7a26f1dce8..5cf62e315218 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = { { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ }; +static const struct alps_nibble_commands alps_v6_nibble_commands[] = { + { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ + { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */ + { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */ + { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */ + { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */ + { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */ + { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */ + { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */ + { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */ + { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */ + { PSMOUSE_CMD_SETRES, 0x00 }, /* a */ + { PSMOUSE_CMD_SETRES, 0x01 }, /* b */ + { PSMOUSE_CMD_SETRES, 0x02 }, /* c */ + { PSMOUSE_CMD_SETRES, 0x03 }, /* d */ + { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */ + { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ +}; + #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ #define ALPS_PASS 0x04 /* device has a pass-through port */ @@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = { /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, + { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */ { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ @@ -645,6 +665,76 @@ static void alps_process_packet_v3(struct psmouse *psmouse) alps_process_touchpad_packet_v3(psmouse); } +static void alps_process_packet_v6(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + unsigned char *packet = psmouse->packet; + struct input_dev *dev = psmouse->dev; + struct input_dev *dev2 = priv->dev2; + int x, y, z, left, right, middle; + + /* + * We can use Byte5 to distinguish if the packet is from Touchpad + * or Trackpoint. + * Touchpad: 0 - 0x7E + * Trackpoint: 0x7F + */ + if (packet[5] == 0x7F) { + /* It should be a DualPoint when received Trackpoint packet */ + if (!(priv->flags & ALPS_DUALPOINT)) + return; + + /* Trackpoint packet */ + x = packet[1] | ((packet[3] & 0x20) << 2); + y = packet[2] | ((packet[3] & 0x40) << 1); + z = packet[4]; + left = packet[3] & 0x01; + right = packet[3] & 0x02; + middle = packet[3] & 0x04; + + /* To prevent the cursor jump when finger lifted */ + if (x == 0x7F && y == 0x7F && z == 0x7F) + x = y = z = 0; + + /* Divide 4 since trackpoint's speed is too fast */ + input_report_rel(dev2, REL_X, (char)x / 4); + input_report_rel(dev2, REL_Y, -((char)y / 4)); + + input_report_key(dev2, BTN_LEFT, left); + input_report_key(dev2, BTN_RIGHT, right); + input_report_key(dev2, BTN_MIDDLE, middle); + + input_sync(dev2); + return; + } + + /* Touchpad packet */ + x = packet[1] | ((packet[3] & 0x78) << 4); + y = packet[2] | ((packet[4] & 0x78) << 4); + z = packet[5]; + left = packet[3] & 0x01; + right = packet[3] & 0x02; + + if (z > 30) + input_report_key(dev, BTN_TOUCH, 1); + if (z < 25) + input_report_key(dev, BTN_TOUCH, 0); + + if (z > 0) { + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + } + + input_report_abs(dev, ABS_PRESSURE, z); + input_report_key(dev, BTN_TOOL_FINGER, z > 0); + + /* v6 touchpad does not have middle button */ + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_RIGHT, right); + + input_sync(dev); +} + static void alps_process_packet_v4(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -897,7 +987,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) } /* Bytes 2 - pktsize should have 0 in the highest bit */ - if (priv->proto_version != ALPS_PROTO_V5 && + if ((priv->proto_version < ALPS_PROTO_V5) && psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", @@ -1085,6 +1175,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); } +static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) +{ + int i, nibble; + + /* + * b0-b11 are valid bits, send sequence is inverse. + * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 + */ + for (i = 0; i <= 8; i += 4) { + nibble = (word >> i) & 0xf; + if (alps_command_mode_send_nibble(psmouse, nibble)) + return -1; + } + + return 0; +} + +static int alps_monitor_mode_write_reg(struct psmouse *psmouse, + u16 addr, u16 value) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + + /* 0x0A0 is the command to write the word */ + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || + alps_monitor_mode_send_word(psmouse, 0x0A0) || + alps_monitor_mode_send_word(psmouse, addr) || + alps_monitor_mode_send_word(psmouse, value) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) + return -1; + + return 0; +} + +static int alps_monitor_mode(struct psmouse *psmouse, bool enable) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + + if (enable) { + /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || + ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) + return -1; + } else { + /* EC to exit monitor mode */ + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) + return -1; + } + + return 0; +} + +static int alps_absolute_mode_v6(struct psmouse *psmouse) +{ + u16 reg_val = 0x181; + int ret = -1; + + /* enter monitor mode, to write the register */ + if (alps_monitor_mode(psmouse, true)) + return -1; + + ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); + + if (alps_monitor_mode(psmouse, false)) + ret = -1; + + return ret; +} + static int alps_get_status(struct psmouse *psmouse, char *param) { /* Get status: 0xF5 0xF5 0xF5 0xE9 */ @@ -1189,6 +1353,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse) return 0; } +static int alps_hw_init_v6(struct psmouse *psmouse) +{ + unsigned char param[2] = {0xC8, 0x14}; + + /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ + if (alps_passthrough_mode_v2(psmouse, true)) + return -1; + + if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || + ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || + ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) + return -1; + + if (alps_passthrough_mode_v2(psmouse, false)) + return -1; + + if (alps_absolute_mode_v6(psmouse)) { + psmouse_err(psmouse, "Failed to enable absolute mode\n"); + return -1; + } + + return 0; +} + /* * Enable or disable passthrough mode to the trackstick. */ @@ -1553,6 +1743,8 @@ static void alps_set_defaults(struct alps_data *priv) priv->hw_init = alps_hw_init_v1_v2; priv->process_packet = alps_process_packet_v1_v2; priv->set_abs_params = alps_set_abs_params_st; + priv->x_max = 1023; + priv->y_max = 767; break; case ALPS_PROTO_V3: priv->hw_init = alps_hw_init_v3; @@ -1584,6 +1776,14 @@ static void alps_set_defaults(struct alps_data *priv) priv->x_bits = 23; priv->y_bits = 12; break; + case ALPS_PROTO_V6: + priv->hw_init = alps_hw_init_v6; + priv->process_packet = alps_process_packet_v6; + priv->set_abs_params = alps_set_abs_params_st; + priv->nibble_commands = alps_v6_nibble_commands; + priv->x_max = 2047; + priv->y_max = 1535; + break; } } @@ -1705,8 +1905,8 @@ static void alps_disconnect(struct psmouse *psmouse) static void alps_set_abs_params_st(struct alps_data *priv, struct input_dev *dev1) { - input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); - input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); + input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); + input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); } static void alps_set_abs_params_mt(struct alps_data *priv, diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index eee59853b9ce..704f0f924307 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -17,6 +17,7 @@ #define ALPS_PROTO_V3 3 #define ALPS_PROTO_V4 4 #define ALPS_PROTO_V5 5 +#define ALPS_PROTO_V6 6 /** * struct alps_model_info - touchpad ID table -- cgit From e696c68363740d3a8fe495e353de3ff26b86257a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 7 Dec 2013 07:13:56 -0800 Subject: Input: serio - fix sysfs layout Restore previous layout of sysfs attributes that was broken by commit 3778a2129bcce84f684cc0017ed20d2524afd289 (input: serio: remove bus usage of dev_attrs) which moved all serio device attributes into 'id' group, when only 'type', 'proto', 'id', and 'extra' should be in 'id' group and the rest of attributes should be attached directly to the device. Reported-by: Thomas Hellstrom Tested-by: Thomas Hellstrom Acked-by: Greg Kroah-Hartman Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 98707fb2cb5d..8f4c4ab04bc2 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -455,16 +455,26 @@ static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(proto); static DEVICE_ATTR_RO(id); static DEVICE_ATTR_RO(extra); -static DEVICE_ATTR_RO(modalias); -static DEVICE_ATTR_WO(drvctl); -static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); -static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); static struct attribute *serio_device_id_attrs[] = { &dev_attr_type.attr, &dev_attr_proto.attr, &dev_attr_id.attr, &dev_attr_extra.attr, + NULL +}; + +static struct attribute_group serio_id_attr_group = { + .name = "id", + .attrs = serio_device_id_attrs, +}; + +static DEVICE_ATTR_RO(modalias); +static DEVICE_ATTR_WO(drvctl); +static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); +static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); + +static struct attribute *serio_device_attrs[] = { &dev_attr_modalias.attr, &dev_attr_description.attr, &dev_attr_drvctl.attr, @@ -472,13 +482,13 @@ static struct attribute *serio_device_id_attrs[] = { NULL }; -static struct attribute_group serio_id_attr_group = { - .name = "id", - .attrs = serio_device_id_attrs, +static struct attribute_group serio_device_attr_group = { + .attrs = serio_device_attrs, }; static const struct attribute_group *serio_device_attr_groups[] = { &serio_id_attr_group, + &serio_device_attr_group, NULL }; -- cgit From 241ecf1ce528804d5ffc8fb386ff2a01b1f937c4 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 9 Dec 2013 22:13:10 -0800 Subject: Input: adxl34x - Fix bug in definition of ADXL346_2D_ORIENT Coverity report pointet out by Dmitry Reported-by: Dmitry Torokhov Signed-off-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 0735de3a6468..1cb1da294419 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -158,7 +158,7 @@ /* ORIENT ADXL346 only */ #define ADXL346_2D_VALID (1 << 6) -#define ADXL346_2D_ORIENT(x) (((x) & 0x3) >> 4) +#define ADXL346_2D_ORIENT(x) (((x) & 0x30) >> 4) #define ADXL346_3D_VALID (1 << 3) #define ADXL346_3D_ORIENT(x) ((x) & 0x7) #define ADXL346_2D_PORTRAIT_POS 0 /* +X */ -- cgit