* [PATCH v2] add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)
From: Florian Echtler @ 2013-10-20 16:49 UTC (permalink / raw)
To: linux-input, benjamin.tissoires, rydberg, dmitry.torokhov,
dh.herrmann
Cc: Florian "floe" Echtler
From: "Florian \"floe\" 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 | 446 ++++++++++++++++++++++++++++++++++++
3 files changed, 457 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..89f5d48
--- /dev/null
+++ b/drivers/input/touchscreen/sur40.c
@@ -0,0 +1,446 @@
+/*
+ Surface2.0/SUR40/PixelSense input driver
+
+ 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 */
+} __packed;
+
+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];
+} __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 <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: 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
+*/
+#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 */
+
+ struct sur40_data *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);
+ /* TODO: use a better orientation measure */
+ 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 = &(sur40->bulk_in_buffer->header);
+ struct sur40_blob *inblob = &(sur40->bulk_in_buffer->blobs[0]);
+
+ 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, sur40->bulk_in_size,
+ &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);
+ if (!sur40)
+ return -ENOMEM;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ kfree(sur40);
+ 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(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_dbg(&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_dbg(&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 "input: serio: use DEVICE_ATTR_RO()" added to driver-core tree
From: gregkh @ 2013-10-20 3:06 UTC (permalink / raw)
To: gregkh, dmitry.torokhov, linux-input
This is a note to let you know that I've just added the patch titled
input: serio: use DEVICE_ATTR_RO()
to my driver-core git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
in the driver-core-next branch.
The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release
during the merge window.
If you have any questions about this process, please let me know.
>From 7eab8ded347244f1464006ace851521254cabb07 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Mon, 7 Oct 2013 18:08:23 -0700
Subject: input: serio: use DEVICE_ATTR_RO()
Convert the serio sysfs fiels to use the DEVICE_ATTR_RO() macros to make
it easier to audit the correct sysfs file permission usage.
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: <linux-input@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/serio/serio.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 2b56855..478880e 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -373,34 +373,34 @@ static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
}
-static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.type);
}
-static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.proto);
}
-static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.id);
}
-static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.extra);
}
-static DEVICE_ATTR(type, S_IRUGO, serio_show_id_type, NULL);
-static DEVICE_ATTR(proto, S_IRUGO, serio_show_id_proto, NULL);
-static DEVICE_ATTR(id, S_IRUGO, serio_show_id_id, NULL);
-static DEVICE_ATTR(extra, S_IRUGO, serio_show_id_extra, NULL);
+static DEVICE_ATTR_RO(type);
+static DEVICE_ATTR_RO(proto);
+static DEVICE_ATTR_RO(id);
+static DEVICE_ATTR_RO(extra);
static struct attribute *serio_device_id_attrs[] = {
&dev_attr_type.attr,
--
1.8.4.6.g82e253f.dirty
^ permalink raw reply related
* patch "input: gameport: convert bus code to use dev_groups" added to driver-core tree
From: gregkh @ 2013-10-20 3:06 UTC (permalink / raw)
To: gregkh, dmitry.torokhov, linux-input
This is a note to let you know that I've just added the patch titled
input: gameport: convert bus code to use dev_groups
to my driver-core git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
in the driver-core-next branch.
The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release
during the merge window.
If you have any questions about this process, please let me know.
>From 0cba7de7f6cdcf84c9b75d29041c475aedeb45c9 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Mon, 7 Oct 2013 18:27:37 -0700
Subject: input: gameport: convert bus code to use dev_groups
The dev_attrs field of struct bus_type is going away soon, dev_groups
should be used instead. This converts the gameport bus code to use the
correct field.
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: <linux-input@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/gameport/gameport.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 922a7fe..24c41ba 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -422,14 +422,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
* Gameport port operations
*/
-static ssize_t gameport_show_description(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t gameport_description_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct gameport *gameport = to_gameport_port(dev);
return sprintf(buf, "%s\n", gameport->name);
}
+static DEVICE_ATTR(description, S_IRUGO, gameport_description_show, NULL);
-static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct gameport *gameport = to_gameport_port(dev);
struct device_driver *drv;
@@ -457,12 +458,14 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
return error ? error : count;
}
+static DEVICE_ATTR_WO(drvctl);
-static struct device_attribute gameport_device_attrs[] = {
- __ATTR(description, S_IRUGO, gameport_show_description, NULL),
- __ATTR(drvctl, S_IWUSR, NULL, gameport_rebind_driver),
- __ATTR_NULL
+static struct attribute *gameport_device_attrs[] = {
+ &dev_attr_description.attr,
+ &dev_attr_drvctl.attr,
+ NULL,
};
+ATTRIBUTE_GROUPS(gameport_device);
static void gameport_release_port(struct device *dev)
{
@@ -750,7 +753,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv)
static struct bus_type gameport_bus = {
.name = "gameport",
- .dev_attrs = gameport_device_attrs,
+ .dev_groups = gameport_device_groups,
.drv_groups = gameport_driver_groups,
.match = gameport_bus_match,
.probe = gameport_driver_probe,
--
1.8.4.6.g82e253f.dirty
^ permalink raw reply related
* patch "input: serio: remove bus usage of dev_attrs" added to driver-core tree
From: gregkh @ 2013-10-20 3:06 UTC (permalink / raw)
To: gregkh, dmitry.torokhov, linux-input
This is a note to let you know that I've just added the patch titled
input: serio: remove bus usage of dev_attrs
to my driver-core git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
in the driver-core-next branch.
The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)
The patch will also be merged in the next major kernel release
during the merge window.
If you have any questions about this process, please let me know.
>From 3778a2129bcce84f684cc0017ed20d2524afd289 Mon Sep 17 00:00:00 2001
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: Mon, 7 Oct 2013 18:09:08 -0700
Subject: input: serio: remove bus usage of dev_attrs
The dev_attrs field of struct bus_type is going away soon, so move the
remaining sysfs files that are being described with this field to use
dev_groups instead.
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: <linux-input@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/serio/serio.c | 62 ++++++++++++++++++++++-----------------------
1 file changed, 30 insertions(+), 32 deletions(-)
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 478880e..98707fb 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -365,7 +365,7 @@ static ssize_t serio_show_description(struct device *dev, struct device_attribut
return sprintf(buf, "%s\n", serio->name);
}
-static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
@@ -397,30 +397,7 @@ static ssize_t extra_show(struct device *dev, struct device_attribute *attr, cha
return sprintf(buf, "%02x\n", serio->id.extra);
}
-static DEVICE_ATTR_RO(type);
-static DEVICE_ATTR_RO(proto);
-static DEVICE_ATTR_RO(id);
-static DEVICE_ATTR_RO(extra);
-
-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 const struct attribute_group *serio_device_attr_groups[] = {
- &serio_id_attr_group,
- NULL
-};
-
-static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct serio *serio = to_serio_port(dev);
struct device_driver *drv;
@@ -474,14 +451,36 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *
return retval;
}
-static struct device_attribute serio_device_attrs[] = {
- __ATTR(description, S_IRUGO, serio_show_description, NULL),
- __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL),
- __ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
- __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
- __ATTR_NULL
+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,
+ &dev_attr_modalias.attr,
+ &dev_attr_description.attr,
+ &dev_attr_drvctl.attr,
+ &dev_attr_bind_mode.attr,
+ NULL
+};
+
+static struct attribute_group serio_id_attr_group = {
+ .name = "id",
+ .attrs = serio_device_id_attrs,
};
+static const struct attribute_group *serio_device_attr_groups[] = {
+ &serio_id_attr_group,
+ NULL
+};
static void serio_release_port(struct device *dev)
{
@@ -996,7 +995,6 @@ EXPORT_SYMBOL(serio_interrupt);
static struct bus_type serio_bus = {
.name = "serio",
- .dev_attrs = serio_device_attrs,
.drv_groups = serio_driver_groups,
.match = serio_bus_match,
.uevent = serio_uevent,
--
1.8.4.6.g82e253f.dirty
^ permalink raw reply related
* [PATCH v3 1/1] Input: Improve the performance of alps v5-protocol's touchpad
From: Yunkang Tang @ 2013-10-20 6:23 UTC (permalink / raw)
To: dmitry.torokhov, cernekee, dturvene; +Cc: linux-input, ndevos, yunkang.tang
Hi all,
Here is the 3rd version of supporting ALPS v5 protocol's device
Change since v2:
- Merge two patches into one patch because they're all for improving v5 device.
- Modify the source code according to Kevin's suggestions.
1) Simplify the alps_process_bitmap() function by using ffs() and fls().
2) Simplify the alps_decode_dolphin() function by using u64 for the palm data.
3) Reuse the alps_process_touchpad_packet_v3() for v5 device.
4) Add an sample for calculating touchpad's x_max&y_max by using sensor line number.
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
drivers/input/mouse/alps.c | 201 ++++++++++++++++++++++++++++++++++++---------
drivers/input/mouse/alps.h | 7 +-
2 files changed, 169 insertions(+), 39 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index ca7a26f..7cd0ac0 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -257,6 +257,50 @@ 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)
+{
+ int box_middle_x, box_middle_y;
+ unsigned int x_map, y_map;
+ unsigned char start_bit, end_bit;
+
+ x_map = fields->x_map;
+ y_map = fields->y_map;
+
+ if (!x_map || !y_map)
+ return;
+
+ /* Most-significant bit should never exceed max sensor line number */
+ if (fls(x_map) > priv->x_bits || fls(y_map) > priv->y_bits)
+ return;
+
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ if (fields->fingers > 1) {
+ start_bit = priv->x_bits - fls(x_map);
+ end_bit = priv->x_bits - ffs(x_map);
+ box_middle_x = (priv->x_max * (start_bit + end_bit)) /
+ (2 * (priv->x_bits - 1));
+
+ start_bit = ffs(y_map) - 1;
+ end_bit = fls(y_map) - 1;
+ box_middle_y = (priv->y_max * (start_bit + 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.
@@ -461,7 +505,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,48 +527,61 @@ 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)
{
+ u64 palm_data = 0;
+ 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_data = (p[1] & 0x7f) |
+ ((p[2] & 0x7f) << 7) |
+ ((p[4] & 0x7f) << 14) |
+ ((p[5] & 0x7f) << 21) |
+ ((p[3] & 0x07) << 28) |
+ (((u64)p[3] & 0x70) << 27) |
+ (((u64)p[0] & 0x01) << 34);
+
+ /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
+ f->y_map = palm_data & (BIT(priv->y_bits) - 1);
+
+ /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
+ f->x_map = (palm_data >> priv->y_bits) &
+ (BIT(priv->x_bits) - 1);
+ }
}
-static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+static void alps_process_touchpad_packet_v3_v5(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 x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- int fingers = 0, bmap_fingers;
- struct alps_fields f;
+ int fingers = 0, bmap_fn;
+ struct alps_fields f = {0};
- priv->decode_fields(&f, packet);
+ priv->decode_fields(&f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -540,19 +598,27 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
*/
if (f.is_mp) {
fingers = f.fingers;
- bmap_fingers = alps_process_bitmap(priv,
- f.x_map, f.y_map,
- &x1, &y1, &x2, &y2);
-
- /*
- * We shouldn't report more than one finger if
- * we don't have two coordinates.
- */
- if (fingers > 1 && bmap_fingers < 2)
- fingers = bmap_fingers;
+ if (priv->proto_version == ALPS_PROTO_V3) {
+ bmap_fn = alps_process_bitmap(priv, f.x_map,
+ f.y_map, &x1, &y1,
+ &x2, &y2);
+
+ /*
+ * We shouldn't report more than one finger if
+ * we don't have two coordinates.
+ */
+ if (fingers > 1 && bmap_fn < 2)
+ fingers = bmap_fn;
+ } else {
+ /* Since Dolphin's finger number is reliable,
+ * there is no need to compare with bmap_fn.
+ */
+ alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+ &x2, &y2);
+ }
/* Now process position packet */
- priv->decode_fields(&f, priv->multi_data);
+ priv->decode_fields(&f, priv->multi_data, psmouse);
} else {
priv->multi_packet = 0;
}
@@ -642,7 +708,7 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
return;
}
- alps_process_touchpad_packet_v3(psmouse);
+ alps_process_touchpad_packet_v3_v5(psmouse);
}
static void alps_process_packet_v4(struct psmouse *psmouse)
@@ -742,6 +808,17 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
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_v3_v5(psmouse);
+}
+
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -1519,6 +1596,52 @@ 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;
+
+ /* Dolphin's sensor line number is not fixed. It can be calculated
+ * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
+ * Further more, we can get device's x_max and y_max by multiplying
+ * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
+ *
+ * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
+ * real sensor line number X = 11 + 8 = 19, and
+ * real sensor line number Y = 8 + 1 = 9.
+ * So, x_max = (19 - 1) * 64 = 1152, and
+ * y_max = (9 - 1) * 64 = 512.
+ */
+ 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;
@@ -1571,7 +1694,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;
@@ -1645,11 +1768,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 eee5985..c5c53f4 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.
@@ -145,7 +149,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
* Re: [PATCH] typo fixes (coordiante -> coordinate) in am335x
From: Jan Lübbe @ 2013-10-19 16:02 UTC (permalink / raw)
To: Tony Lindgren, Samuel Ortiz, Lee Jones
Cc: linux-doc, linux-kernel, Zubair Lutfullah, linux-input,
linux-omap, linux-arm-kernel
In-Reply-To: <20130821075828.GZ7656@atomide.com>
On Wed, 2013-08-21 at 00:58 -0700, Tony Lindgren wrote:
> * Zubair Lutfullah <zubair.lutfullah@gmail.com> [130715 08:33]:
> > Did a grep for coordiante and replaced them all
> > with coordinate.
> >
> > This applies to the mfd-next tree.
>
> This should be safe to apply via the MFD tree as a non-critical
> fix assuming the bootloaders are not yet using this:
>
> Acked-by: Tony Lindgren <tony@atomide.com>
It seems this didn't get applied. It fixes the touchscreen on a
BeagleBone black with the 7" LCD and we should avoid having people use
the wrong binding.
Samuel or Lee: Could you take this patch?
Thanks,
Jan Lübbe
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] Input: move name/timer init to input_alloc_dev()
From: David Herrmann @ 2013-10-19 10:37 UTC (permalink / raw)
To: open list:HID CORE LAYER; +Cc: Dmitry Torokhov, David Herrmann
In-Reply-To: <1380731263-20962-1-git-send-email-dh.herrmann@gmail.com>
ping
On Wed, Oct 2, 2013 at 6:27 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> We want to allow drivers to call input_event() at any time after the
> device got allocated. This means input_event() and input_register_device()
> must be allowed to run in parallel.
>
> The only conflicting calls in input_register_device() are init_timer() and
> dev_set_name(). Both can safely be moved to device allocation and we're
> good to go.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
> drivers/input/input.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/input/input.c b/drivers/input/input.c
> index c044699..e75d015 100644
> --- a/drivers/input/input.c
> +++ b/drivers/input/input.c
> @@ -1734,6 +1734,7 @@ EXPORT_SYMBOL_GPL(input_class);
> */
> struct input_dev *input_allocate_device(void)
> {
> + static atomic_t input_no = ATOMIC_INIT(0);
> struct input_dev *dev;
>
> dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
> @@ -1743,9 +1744,13 @@ struct input_dev *input_allocate_device(void)
> device_initialize(&dev->dev);
> mutex_init(&dev->mutex);
> spin_lock_init(&dev->event_lock);
> + init_timer(&dev->timer);
> INIT_LIST_HEAD(&dev->h_list);
> INIT_LIST_HEAD(&dev->node);
>
> + dev_set_name(&dev->dev, "input%ld",
> + (unsigned long) atomic_inc_return(&input_no) - 1);
> +
> __module_get(THIS_MODULE);
> }
>
> @@ -2019,7 +2024,6 @@ static void devm_input_device_unregister(struct device *dev, void *res)
> */
> int input_register_device(struct input_dev *dev)
> {
> - static atomic_t input_no = ATOMIC_INIT(0);
> struct input_devres *devres = NULL;
> struct input_handler *handler;
> unsigned int packet_size;
> @@ -2059,7 +2063,6 @@ int input_register_device(struct input_dev *dev)
> * If delay and period are pre-set by the driver, then autorepeating
> * is handled by the driver itself and we don't do it in input.c.
> */
> - init_timer(&dev->timer);
> if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
> dev->timer.data = (long) dev;
> dev->timer.function = input_repeat_key;
> @@ -2073,9 +2076,6 @@ int input_register_device(struct input_dev *dev)
> if (!dev->setkeycode)
> dev->setkeycode = input_default_setkeycode;
>
> - dev_set_name(&dev->dev, "input%ld",
> - (unsigned long) atomic_inc_return(&input_no) - 1);
> -
> error = device_add(&dev->dev);
> if (error)
> goto err_free_vals;
> --
> 1.8.4
>
^ permalink raw reply
* Re: [PATCH 1/1] HID: wiimote: invert Y-Axis and add automatic calibration for Wii U Pro Controller
From: David Herrmann @ 2013-10-19 10:35 UTC (permalink / raw)
To: Rafael Brune; +Cc: open list:HID CORE LAYER
In-Reply-To: <121A2CAD-9706-4A86-AF20-60B25DF00101@rbrune.de>
Hi
On Thu, Oct 10, 2013 at 5:46 PM, Rafael Brune <mail@rbrune.de> wrote:
> Hi
>
> On Oct 10, 2013, at 11:16 AM, David Herrmann wrote:
>
>> Hi
>>
>> On Sun, Oct 6, 2013 at 8:44 PM, Rafael Brune <mail@rbrune.de> wrote:
>>> With these changes the Wii U Pro Controller fully complies
>>> to the gamepad-API and with the calibration is fully usable
>>> out-of-the-box without any user-space tools. This potentially
>>> breaks compatibility with software that relies on the two
>>> inverted Y-Axis but since current bluez 4.x and 5.x versions
>>> don't even support pairing with the controller yet the amount
>>> of people affected should be rather small.
>>
>> Did anyone try to read the calibration values from the EEPROM? Doing
>> calibration in the kernel is fine, but I'd rather have the
>> hardware-calibration values instead. Even if we cannot figure it out
>> now, we should try to stay as compatible to the real values as we can.
>>
>> So how about keeping the min/max and neutral point as we have it know
>> and instead adjusting the reported values by scaling/moving them?
>>
>
> After googling a little bit it seems like their might actually be no
> calibration data for the Classic Controller and Wii U Pro Controller. The
> midpoint is supposedly just detected when the device connects.
> http://wiibrew.org/wiki/Classic_Controller
I tried to digg into the EEPROM data and indeed, there seems to be no
calibration data. The pro-controller doesn't even provide a classic
EEPROM (it fails on EEPROM read/write).
> My code did not change what we output as the min/max/mid values it's
> still -0x800,0x000,0x800. As you suggest it scales/moves the raw values
> so that the reported values fall into that range.
Yepp, sorry, misread the patch.
>
>>> Signed-off-by: Rafael Brune <mail@rbrune.de>
>>> ---
>>> drivers/hid/hid-wiimote-modules.c | 45 +++++++++++++++++++++++++++++++++++----
>>> 1 file changed, 41 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
>>> index 2e7d644..1422b0b 100644
>>> --- a/drivers/hid/hid-wiimote-modules.c
>>> +++ b/drivers/hid/hid-wiimote-modules.c
>>> @@ -1640,10 +1640,41 @@ static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
>>> ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
>>> ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
>>>
>>> - input_report_abs(wdata->extension.input, ABS_X, lx - 0x800);
>>> - input_report_abs(wdata->extension.input, ABS_Y, ly - 0x800);
>>> - input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800);
>>> - input_report_abs(wdata->extension.input, ABS_RY, ry - 0x800);
>>> + /* Calibrating the sticks by saving the global min/max per axis */
>>> + if (lx < wdata->state.calib_bboard[0][0])
>>> + wdata->state.calib_bboard[0][0] = lx;
>>> + if (lx > wdata->state.calib_bboard[0][1])
>>> + wdata->state.calib_bboard[0][1] = lx;
>>> +
>>> + if (ly < wdata->state.calib_bboard[1][0])
>>> + wdata->state.calib_bboard[1][0] = ly;
>>> + if (ly > wdata->state.calib_bboard[1][1])
>>> + wdata->state.calib_bboard[1][1] = ly;
>>> +
>>> + if (rx < wdata->state.calib_bboard[2][0])
>>> + wdata->state.calib_bboard[2][0] = rx;
>>> + if (rx > wdata->state.calib_bboard[2][1])
>>> + wdata->state.calib_bboard[2][1] = rx;
>>> +
>>> + if (ry < wdata->state.calib_bboard[3][0])
>>> + wdata->state.calib_bboard[3][0] = ry;
>>> + if (ry > wdata->state.calib_bboard[3][1])
>>> + wdata->state.calib_bboard[3][1] = ry;
>>> +
>>> + /* Normalize using int math to prevent conversion to/from float */
>>> + lx = -2048 + (((__s32)(lx - wdata->state.calib_bboard[0][0]) * 4096)/
>>> + (wdata->state.calib_bboard[0][1]-wdata->state.calib_bboard[0][0]));
>>> + ly = -2048 + (((__s32)(ly - wdata->state.calib_bboard[1][0]) * 4096)/
>>> + (wdata->state.calib_bboard[1][1]-wdata->state.calib_bboard[1][0]));
>>> + rx = -2048 + (((__s32)(rx - wdata->state.calib_bboard[2][0]) * 4096)/
>>> + (wdata->state.calib_bboard[2][1]-wdata->state.calib_bboard[2][0]));
>>> + ry = -2048 + (((__s32)(ry - wdata->state.calib_bboard[3][0]) * 4096)/
>>> + (wdata->state.calib_bboard[3][1]-wdata->state.calib_bboard[3][0]));
>>
>> Don't use calib_bboard. Add a new array (or use a union). This is confusing.
>
> I agree, will do that.
>
>
>>> +
>>> + input_report_abs(wdata->extension.input, ABS_X, lx);
>>> + input_report_abs(wdata->extension.input, ABS_Y, -ly);
>>> + input_report_abs(wdata->extension.input, ABS_RX, rx);
>>> + input_report_abs(wdata->extension.input, ABS_RY, -ry);
>>>
>>> input_report_key(wdata->extension.input,
>>> wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
>>> @@ -1760,6 +1791,12 @@ static int wiimod_pro_probe(const struct wiimod_ops *ops,
>>> if (!wdata->extension.input)
>>> return -ENOMEM;
>>>
>>> + /* Initialize min/max values for all Axis with reasonable values */
>>> + for (i = 0; i < 4; ++i) {
>>> + wdata->state.calib_bboard[i][0] = 0x780;
>>> + wdata->state.calib_bboard[i][1] = 0x880;
>>
>> Ugh, these values look weird. We have a reported range of -0x400 to
>> +0x400 but you limit it to a virtual range of 0x100. That's a loss of
>> precision of 80%. Where are these values from?
>
> I picked these values arbitrarily as starting points since they will update
> during use of the gamepad as soon as lower/higher values are observed.
> As soon as the sticks have been moved to their extreme positions once
> everything is perfect.
>
> We could also set those values in a similar fashion as to what Nintendo
> seems to be doing. Wait for a first report of raw values, use them as the
> mid point and set these min/max values as midpoint +/- ~0x800.
There is no "first report". There is no guarantee that the first
report I receive in the driver is really the first report from the
device (unreliable transmission).
That leaves us with heuristics to detect the neutral point.
>
>>> + }
>>> +
>>> set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
>>> input_set_drvdata(wdata->extension.input, wdata);
>>
>> Thanks for hacking this up. Could you give me some values from your
>> device so I can see how big the deviation is? My device reports:
>>
>> Range: 0-4095 (0x0fff)
>> Neutral-Point: 2048 (0x800)
>>
>> I haven't seen any big deviations from these values. I can try to take
>> this over if you want, just let me know.
>>
>> Thanks
>> David
>
>
> When I write out the observed raw min/max values of all Axis I get these:
> LX: 1033 - 3326 (center~=2179 (0x883))
> LY: 857 - 3211 (center~=2034 (0x7F2))
> RX: 944 - 3176 (center~=2060 (0x80C))
> RY: 853 - 3159 (center~=2006 (0x7D6))
>
> So not really the whole range of 0x0FFF is actually used and offsets due
> to manufacturing differences are present.
Ok, so you have the same values as I do, just some different offsets.
So what I'd do is first swap the axes, then change the min/max to 1200
(or something like that) instead of 2048 and then add heuristics for
neutral-point detection.
For neutral-point detection, I would add a dynamic offset to the
driver which is adjusted during runtime. Some heuristics like if a
report stays the same for 5 continuous reports and is in the range
1700-2300, I'd take it as new neutral-point (or shift the neutral
point in its direction). I will try to get something working.. Ideas
welcome. But I don't like the "first report" approach, as it may be
_way_ off.
Thanks
David
^ permalink raw reply
* Re: [patch] HID: logitech-dj: small cleanup in rdcat()
From: walter harms @ 2013-10-19 9:46 UTC (permalink / raw)
To: Dan Carpenter; +Cc: Jiri Kosina, linux-input, kernel-janitors
In-Reply-To: <20131019090859.GD9312@longonot.mountain>
Am 19.10.2013 11:08, schrieb Dan Carpenter:
> We could pass the "rdsec" pointer instead of the address of the "rdesc"
> and it's a little simpler.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
>
> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
> index 2e53024..a7947d8 100644
> --- a/drivers/hid/hid-logitech-dj.c
> +++ b/drivers/hid/hid-logitech-dj.c
> @@ -542,9 +542,9 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
> return 0;
> }
>
> -static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
> +static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
> {
> - memcpy(*rdesc + *rsize, data, size);
> + memcpy(rdesc + *rsize, data, size);
> *rsize += size;
> }
That improves readability nicely, an other point is that the function hides the change of rsize.
IMHO it would be better either to return the new address or do the whole add on the caller
side:
suggestion 1:
rsize = rdcat();
suggestion 2:
rsize += rdcat();
Here you see immediately the new offset.
i know it is a matter of taste, it is just what i would do.
re,
wh
>
> @@ -567,31 +567,31 @@ static int logi_dj_ll_parse(struct hid_device *hid)
> if (djdev->reports_supported & STD_KEYBOARD) {
> dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
> __func__, djdev->reports_supported);
> - rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
> + rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
> }
>
> if (djdev->reports_supported & STD_MOUSE) {
> dbg_hid("%s: sending a mouse descriptor, reports_supported: "
> "%x\n", __func__, djdev->reports_supported);
> - rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
> + rdcat(rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
> }
>
> if (djdev->reports_supported & MULTIMEDIA) {
> dbg_hid("%s: sending a multimedia report descriptor: %x\n",
> __func__, djdev->reports_supported);
> - rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
> + rdcat(rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
> }
>
> if (djdev->reports_supported & POWER_KEYS) {
> dbg_hid("%s: sending a power keys report descriptor: %x\n",
> __func__, djdev->reports_supported);
> - rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
> + rdcat(rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
> }
>
> if (djdev->reports_supported & MEDIA_CENTER) {
> dbg_hid("%s: sending a media center report descriptor: %x\n",
> __func__, djdev->reports_supported);
> - rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
> + rdcat(rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
> }
>
> if (djdev->reports_supported & KBD_LEDS) {
> --
> To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [patch] HID: logitech-dj: small cleanup in rdcat()
From: Dan Carpenter @ 2013-10-19 9:08 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input, kernel-janitors
We could pass the "rdsec" pointer instead of the address of the "rdesc"
and it's a little simpler.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 2e53024..a7947d8 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -542,9 +542,9 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
return 0;
}
-static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
+static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
{
- memcpy(*rdesc + *rsize, data, size);
+ memcpy(rdesc + *rsize, data, size);
*rsize += size;
}
@@ -567,31 +567,31 @@ static int logi_dj_ll_parse(struct hid_device *hid)
if (djdev->reports_supported & STD_KEYBOARD) {
dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
__func__, djdev->reports_supported);
- rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
+ rdcat(rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
}
if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: "
"%x\n", __func__, djdev->reports_supported);
- rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
+ rdcat(rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
}
if (djdev->reports_supported & MULTIMEDIA) {
dbg_hid("%s: sending a multimedia report descriptor: %x\n",
__func__, djdev->reports_supported);
- rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
+ rdcat(rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
}
if (djdev->reports_supported & POWER_KEYS) {
dbg_hid("%s: sending a power keys report descriptor: %x\n",
__func__, djdev->reports_supported);
- rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
+ rdcat(rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
}
if (djdev->reports_supported & MEDIA_CENTER) {
dbg_hid("%s: sending a media center report descriptor: %x\n",
__func__, djdev->reports_supported);
- rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
+ rdcat(rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
}
if (djdev->reports_supported & KBD_LEDS) {
^ permalink raw reply related
* [PATCH] Input: wacom - add support for ISDv4 0x10E sensor
From: Jason Gerecke @ 2013-10-18 17:41 UTC (permalink / raw)
To: linux-input, linuxwacom-devel, dmitry.torokhov; +Cc: Jason Gerecke
Used in the Fujitsu T732
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
---
drivers/input/tablet/wacom_wac.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 1cbc4bb..782c253 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -2126,6 +2126,9 @@ static const struct wacom_features wacom_features_0x101 =
static const struct wacom_features wacom_features_0x10D =
{ "Wacom ISDv4 10D", WACOM_PKGLEN_MTTPC, 26202, 16325, 255,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x10E =
+ { "Wacom ISDv4 10E", WACOM_PKGLEN_MTTPC, 27760, 15694, 255,
+ 0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x10F =
{ "Wacom ISDv4 10F", WACOM_PKGLEN_MTTPC, 27760, 15694, 255,
0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2330,6 +2333,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x100) },
{ USB_DEVICE_WACOM(0x101) },
{ USB_DEVICE_WACOM(0x10D) },
+ { USB_DEVICE_WACOM(0x10E) },
{ USB_DEVICE_WACOM(0x10F) },
{ USB_DEVICE_WACOM(0x300) },
{ USB_DEVICE_WACOM(0x301) },
--
1.8.4
^ permalink raw reply related
* [PATCH] HID: hid-sensor-hub: fix report size
From: Srinivas Pandruvada @ 2013-10-18 16:48 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, Srinivas Pandruvada
The number of bytes in a field needs to take account of report_count
field. Need to multiply report_size and report_count to get total
number of bytes.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/hid/hid-sensor-hub.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 88fc5ae..a184e19 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -326,7 +326,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
field->logical == attr_usage_id) {
sensor_hub_fill_attr_info(info, i, report->id,
field->unit, field->unit_exponent,
- field->report_size);
+ field->report_size *
+ field->report_count);
ret = 0;
} else {
for (j = 0; j < field->maxusage; ++j) {
@@ -338,7 +339,8 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
i, report->id,
field->unit,
field->unit_exponent,
- field->report_size);
+ field->report_size *
+ field->report_count);
ret = 0;
break;
}
@@ -425,9 +427,10 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
i, report->field[i]->usage->collection_index,
report->field[i]->usage->hid,
- report->field[i]->report_size/8);
-
- sz = report->field[i]->report_size/8;
+ (report->field[i]->report_size *
+ report->field[i]->report_count)/8);
+ sz = (report->field[i]->report_size *
+ report->field[i]->report_count)/8;
if (pdata->pending.status && pdata->pending.attr_usage_id ==
report->field[i]->usage->hid) {
hid_dbg(hdev, "data was pending ...\n");
--
1.8.3.2
^ permalink raw reply related
* [PATCH] HID: wiimote: add LEGO-wiimote VID
From: David Herrmann @ 2013-10-18 14:26 UTC (permalink / raw)
To: linux-input; +Cc: Jiri Kosina, David Herrmann, stable
The LEGO-wiimote uses a different VID than the Nintendo ID. The device is
technically the same so add the ID.
Cc: <stable@vger.kernel.org> # 3.11+
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
---
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-wiimote-core.c | 5 ++++-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 95d2dff..e6c3a03 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1871,6 +1871,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
};
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ac803c5..000e0df 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -639,6 +639,7 @@
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
#define USB_VENDOR_ID_NINTENDO 0x057e
+#define USB_VENDOR_ID_NINTENDO2 0x054c
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index abb20db..1446f52 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -834,7 +834,8 @@ static void wiimote_init_set_type(struct wiimote_data *wdata,
goto done;
}
- if (vendor == USB_VENDOR_ID_NINTENDO) {
+ if (vendor == USB_VENDOR_ID_NINTENDO ||
+ vendor == USB_VENDOR_ID_NINTENDO2) {
if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE) {
devtype = WIIMOTE_DEV_GEN10;
goto done;
@@ -1855,6 +1856,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
static const struct hid_device_id wiimote_hid_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO2,
+ USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
--
1.8.4
^ permalink raw reply related
* Re: [PATCH 1/1] HID: Fix unit exponent parsing again
From: Jiri Kosina @ 2013-10-18 13:14 UTC (permalink / raw)
To: Nikolai Kondrashov; +Cc: Benjamin Tissoires, linux-input
In-Reply-To: <526132B4.2000008@gmail.com>
On Fri, 18 Oct 2013, Nikolai Kondrashov wrote:
> > I am about to apply it, just a minor thing -- you seem to have forgotten
> > your Signed-off-by: line in the patch. Could you please send it to me, so
> > that I can ammend it to the patch and apply it?
>
> Sure, sorry, haven't sent any kernel patches in a while.
>
> Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com>
Thanks, applied.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH 1/1] HID: Fix unit exponent parsing again
From: Nikolai Kondrashov @ 2013-10-18 13:08 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Benjamin Tissoires, linux-input
In-Reply-To: <alpine.LNX.2.00.1310181456500.31790@pobox.suse.cz>
Hi Jiri,
On 10/18/2013 03:58 PM, Jiri Kosina wrote:
> I am about to apply it, just a minor thing -- you seem to have forgotten
> your Signed-off-by: line in the patch. Could you please send it to me, so
> that I can ammend it to the patch and apply it?
Sure, sorry, haven't sent any kernel patches in a while.
Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com>
Sincerely,
Nick
^ permalink raw reply
* Re: [PATCH 1/1] HID: Fix unit exponent parsing again
From: Jiri Kosina @ 2013-10-18 12:58 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: Nikolai Kondrashov, linux-input
In-Reply-To: <CAN+gG=FC8Zvkt+9wcaMyo+akmqY-mm=xSPDqWOqGHEPwZx3XTQ@mail.gmail.com>
On Thu, 17 Oct 2013, Benjamin Tissoires wrote:
> > Revert some changes done in 774638386826621c984ab6994439f474709cac5e.
> >
> > Revert all changes done in hidinput_calc_abs_res as it mistakingly used
> > "Unit" item exponent nibbles to affect resolution value. This wasn't
> > breaking resolution calculation of relevant axes of any existing
> > devices, though, as they have only one dimension to their units and thus
> > 1 in the corresponding nible.
> >
> > Revert to reading "Unit Exponent" item value as a signed integer in
> > hid_parser_global to fix reading specification-complying values. This
> > fixes resolution calculation of devices complying to the HID standard,
> > including Huion, KYE, Waltop and UC-Logic graphics tablets which have
> > their report descriptors fixed by the drivers.
> >
> > Explanations follow.
[ ... snip ... ]
> I finally understood what you mean here, and why I introduced such a change.
> I have weird report descriptors available in the field which are
> making a funny use of units:
Ok, it took me quite some time to figure this all out. Good work Nikolai,
thanks.
I am about to apply it, just a minor thing -- you seem to have forgotten
your Signed-off-by: line in the patch. Could you please send it to me, so
that I can ammend it to the patch and apply it?
Thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [Patch v2][ 15/37] Input: tsc2007: Add device tree support.
From: Lothar Waßmann @ 2013-10-18 8:36 UTC (permalink / raw)
To: Denis Carikli
Cc: Sascha Hauer, Mark Rutland, devicetree, Dmitry Torokhov,
Pawel Moll, Stephen Warren, Ian Campbell, Rob Herring,
Eric Bénard, linux-input, linux-arm-kernel
In-Reply-To: <1382022155-21954-16-git-send-email-denis@eukrea.com>
Hi,
Denis Carikli <denis@eukrea.com> wrote:
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
> new file mode 100644
> index 0000000..d67b33f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
> @@ -0,0 +1,44 @@
> +* Texas Instruments tsc2007 touchscreen controller
> +
> +Required properties:
> +- compatible: must be "ti,tsc2007".
> +- reg: I2C address of the chip.
> +- pinctrl-0: Should specify pin control groups used for this controller
> + (see pinctrl bindings[0]).
> +- pinctrl-names: Should contain only one value - "default"
> + (see pinctrl bindings[0]).
> +- interrupt-parent: the phandle for the interrupt controller
> + (see interrupt binding[1]).
> +- interrupts: interrupt to which the chip is connected
> + (see interrupt binding[1]).
> +- x-plate-ohms: X-plate resistance in ohms.
> +
There is already a property 'ti,x-plate-ohms' (used for ads7846).
Should this be used here too instead of inventing a new one?
[...]
> @@ -175,10 +192,10 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
>
> /* pen is down, continue with the measurement */
> tsc2007_read_values(ts, &tc);
> -
> rt = tsc2007_calculate_pressure(ts, &tc);
>
> - if (rt == 0 && !ts->get_pendown_state) {
> + if ((ts->of && rt == 0 && ts->gpio < 0) ||
... && !gpio_is_valid(ts->gpio)) ||
for consistency?
> @@ -273,34 +294,64 @@ static void tsc2007_close(struct input_dev *input_dev)
> tsc2007_stop(ts);
> }
>
> -static int tsc2007_probe(struct i2c_client *client,
> - const struct i2c_device_id *id)
> +#ifdef CONFIG_OF
> +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
> + struct device_node *np)
> {
> - struct tsc2007 *ts;
> - struct tsc2007_platform_data *pdata = client->dev.platform_data;
> - struct input_dev *input_dev;
> - int err;
> -
> - if (!pdata) {
> - dev_err(&client->dev, "platform data is required!\n");
> + int err = 0;
> + u32 val32;
> + u64 val64;
> +
> + if (!of_property_read_u32(np, "max-rt", &val32))
> + ts->max_rt = val32;
> + else
> + ts->max_rt = MAX_12BIT;
> +
> + if (!of_property_read_u32(np, "fuzzy", &val32))
> + ts->fuzzy = val32;
> +
> + if (!of_property_read_u64(np, "poll-period", &val64))
> + ts->poll_period = val64;
> + else
> + ts->poll_period = 1;
> +
> + if (!of_property_read_u32(np, "x-plate-ohms", &val32)) {
> + ts->x_plate_ohms = val32;
> + } else {
> + dev_err(&client->dev,
> + "x-plate-ohms is not set up in the devicetree."
> + " (err %d).", err);
>
It's a bad habit to split messages like this, since it makes it harder
to grep the kernel source for a message in a logfile.
> return -EINVAL;
> }
>
> - if (!i2c_check_functionality(client->adapter,
> - I2C_FUNC_SMBUS_READ_WORD_DATA))
> - return -EIO;
> + ts->gpio = of_get_gpio(np, 0);
> + if (!gpio_is_valid(ts->gpio))
> + dev_err(&client->dev, "GPIO not found "
> + "(of_get_gpio returned %d)\n", ts->gpio);
>
dito (at least you should be consistent putting the space either in the
end of the first line or in the beginning of the next line!)
[...]
> @@ -309,13 +360,59 @@ static int tsc2007_probe(struct i2c_client *client,
> ts->poll_period = pdata->poll_period ? : 1;
> ts->get_pendown_state = pdata->get_pendown_state;
> ts->clear_penirq = pdata->clear_penirq;
> + ts->fuzzy = pdata->fuzzy;
>
> if (pdata->x_plate_ohms == 0) {
> dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
> - err = -EINVAL;
> + return -EINVAL;
> + }
> +
> + /* Used to detect if it is probed trough the device tree,
> + * in order to be able to use that information in the IRQ handler.
> + */
> + ts->of = 0;
> +
> + return 0;
> +}
> +
> +static int tsc2007_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct device_node *np = client->dev.of_node;
> + struct tsc2007_platform_data *pdata = client->dev.platform_data;
> + struct tsc2007 *ts;
> + struct input_dev *input_dev;
> + int err = 0;
> +
> + ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
>
devm_kzalloc()?
> @@ -389,10 +494,19 @@ static const struct i2c_device_id tsc2007_idtable[] = {
>
> MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
>
> +#ifdef CONFIG_OF
> +static const struct of_device_id tsc2007_of_match[] = {
> + { .compatible = "ti,tsc2007" },
> + { /* sentinel */ },
>
the redundant comma after the last entry in a struct initializer is
useful to ease adding more entries lateron. Since the empty entry
always has to be the last one, the comma doesn't make any sense here.
Lothar Waßmann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Problem with Mighty Mouse
From: Bastien Nocera @ 2013-10-17 22:43 UTC (permalink / raw)
To: Benjamin Tissoires; +Cc: linux-input
In-Reply-To: <CAN+gG=E3JgUZ9vGY7N-D3OYLGcRqy5OXu8w5WXjJ2YLuYW4UWw@mail.gmail.com>
On Thu, 2013-10-17 at 15:30 -0400, Benjamin Tissoires wrote:
> Hi Bastien,
>
> On Sat, Oct 12, 2013 at 7:48 PM, Bastien Nocera <hadess@hadess.net> wrote:
> > Heya,
> >
> > I've tested a Bluetooth Apple Mighty Mouse (AA1197) and though I can
> > move the cursor without a problem, none of the buttons work. evtest
> > doesn't see any button events.
> >
> > Any ideas what I should look at, or which tool I could use to capture
> > the raw data?
>
> you can use hid-recorder[1] to retrieve the raw events from hidraw (it
> mainly does a hexdump on /dev/hidrawX or you can use the kernel
> debugfs interface for some devices which are preventing hidraw to
> forward the events).
>
> Ideally, you should give the output of evtest (or evemu) and
> hid-recorder at the same time so we can have an idea of the input and
> the output of the kernel driver.
Colour me confused, it works again. I'll bear those advices in mind if
and when it happens again.
Cheers
^ permalink raw reply
* Re: Problem with Mighty Mouse
From: Benjamin Tissoires @ 2013-10-17 19:30 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-input
In-Reply-To: <1381621726.21761.7.camel@nuvo>
Hi Bastien,
On Sat, Oct 12, 2013 at 7:48 PM, Bastien Nocera <hadess@hadess.net> wrote:
> Heya,
>
> I've tested a Bluetooth Apple Mighty Mouse (AA1197) and though I can
> move the cursor without a problem, none of the buttons work. evtest
> doesn't see any button events.
>
> Any ideas what I should look at, or which tool I could use to capture
> the raw data?
you can use hid-recorder[1] to retrieve the raw events from hidraw (it
mainly does a hexdump on /dev/hidrawX or you can use the kernel
debugfs interface for some devices which are preventing hidraw to
forward the events).
Ideally, you should give the output of evtest (or evemu) and
hid-recorder at the same time so we can have an idea of the input and
the output of the kernel driver.
Cheers,
Benjamin
[1] http://bentiss.github.io/hid-replay-docs/
>
> Cheers
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/1] HID: Fix unit exponent parsing again
From: Benjamin Tissoires @ 2013-10-17 18:56 UTC (permalink / raw)
To: Nikolai Kondrashov; +Cc: Jiri Kosina, linux-input
In-Reply-To: <1381666192-25309-1-git-send-email-spbnick@gmail.com>
Hi Nikolai,
On Sun, Oct 13, 2013 at 8:09 AM, Nikolai Kondrashov <spbnick@gmail.com> wrote:
> Revert some changes done in 774638386826621c984ab6994439f474709cac5e.
>
> Revert all changes done in hidinput_calc_abs_res as it mistakingly used
> "Unit" item exponent nibbles to affect resolution value. This wasn't
> breaking resolution calculation of relevant axes of any existing
> devices, though, as they have only one dimension to their units and thus
> 1 in the corresponding nible.
>
> Revert to reading "Unit Exponent" item value as a signed integer in
> hid_parser_global to fix reading specification-complying values. This
> fixes resolution calculation of devices complying to the HID standard,
> including Huion, KYE, Waltop and UC-Logic graphics tablets which have
> their report descriptors fixed by the drivers.
>
> Explanations follow.
>
> There are two "unit exponents" in HID specification and it is important
> not to mix them. One is the global "Unit Exponent" item and another is
> nibble values in the global "Unit" item. See 6.2.2.7 Global Items.
>
> The "Unit Exponent" value is just a signed integer and is used to scale
> the integer resolution unit values, so fractions can be expressed.
>
> The nibbles of "Unit" value are used to select the unit system (nibble
> 0), and presence of a particular basic unit type in the unit formula and
> its *exponent* (or power, nibbles 1-6). And yes, the latter is in two
> complement and zero means absence of the unit type.
>
> Taking the representation example of (integer) joules from the
> specification:
>
> [mass(grams)][length(centimeters)^2][time(seconds)^-2] * 10^-7
>
> the "Unit Exponent" would be -7 (or 0xF9, if stored as a byte) and the
> "Unit" value would be 0xE121, signifying:
>
> Nibble Part Value Meaning
> ----- ---- ----- -------
> 0 System 1 SI Linear
> 1 Length 2 Centimeters^2
> 2 Mass 1 Grams
> 3 Time -2 Seconds^-2
>
> To give the resolution in e.g. hundredth of joules the "Unit Exponent"
> item value should have been -9.
>
> See also the examples of "Unit" values for some common units in the same
> chapter.
>
> However, there is a common misunderstanding about the "Unit Exponent"
> value encoding, where it is assumed to be stored the same as nibbles in
> "Unit" item. This is most likely due to the specification being a bit
> vague and overloading the term "unit exponent". This also was and still
> is proliferated by the official "HID Descriptor Tool", which makes this
> mistake and stores "Unit Exponent" as such. This format is also
> mentioned in books such as "USB Complete" and in Microsoft's hardware
> design guides.
>
> As a result many devices currently on the market use this encoding and
> so the driver should support them.
> ---
> drivers/hid/hid-core.c | 11 ++++++-----
> drivers/hid/hid-input.c | 13 ++++---------
> 2 files changed, 10 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index b8470b1..013cad0 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -319,7 +319,7 @@ static s32 item_sdata(struct hid_item *item)
>
> static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
> {
> - __u32 raw_value;
> + __s32 raw_value;
> switch (item->tag) {
> case HID_GLOBAL_ITEM_TAG_PUSH:
>
> @@ -370,10 +370,11 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
> return 0;
>
> case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
> - /* Units exponent negative numbers are given through a
> - * two's complement.
> - * See "6.2.2.7 Global Items" for more information. */
> - raw_value = item_udata(item);
> + /* Many devices provide unit exponent as a two's complement
> + * nibble due to the common misunderstanding of HID
> + * specification 1.11, 6.2.2.7 Global Items. Attempt to handle
> + * both this and the standard encoding. */
> + raw_value = item_sdata(item);
> if (!(raw_value & 0xfffffff0))
> parser->global.unit_exponent = hid_snto32(raw_value, 4);
> else
> diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
> index 8741d95..d97f232 100644
> --- a/drivers/hid/hid-input.c
> +++ b/drivers/hid/hid-input.c
> @@ -192,6 +192,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
> return -EINVAL;
> }
>
> +
> /**
> * hidinput_calc_abs_res - calculate an absolute axis resolution
> * @field: the HID report field to calculate resolution for
> @@ -234,23 +235,17 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
> case ABS_MT_TOOL_Y:
> case ABS_MT_TOUCH_MAJOR:
> case ABS_MT_TOUCH_MINOR:
> - if (field->unit & 0xffffff00) /* Not a length */
> - return 0;
> - unit_exponent += hid_snto32(field->unit >> 4, 4) - 1;
> - switch (field->unit & 0xf) {
> - case 0x1: /* If centimeters */
> + if (field->unit == 0x11) { /* If centimeters */
> /* Convert to millimeters */
> unit_exponent += 1;
> - break;
> - case 0x3: /* If inches */
> + } else if (field->unit == 0x13) { /* If inches */
> /* Convert to millimeters */
> prev = physical_extents;
> physical_extents *= 254;
> if (physical_extents < prev)
> return 0;
> unit_exponent -= 1;
> - break;
> - default:
> + } else {
I finally understood what you mean here, and why I introduced such a change.
I have weird report descriptors available in the field which are
making a funny use of units:
3M multitouch devices declare:
0x05, 0x01, // Usage Page (Generic Desktop) 148
0x26, 0xff, 0x7f, // Logical Maximum (32767) 150
0x75, 0x10, // Report Size (16) 153
0x55, 0x0e, // Unit Exponent (-2) 155
0x65, 0x33, // Unit (Inch^3,EngLinear) 157
0x09, 0x30, // Usage (X) 159
0x35, 0x00, // Physical Minimum (0) 161
0x46, 0x3a, 0x06, // Physical Maximum (1594) 163
0x81, 0x02, // Input (Data,Var,Abs) 166
which became fine with the non reverted code -> the unit exponent
became 1 ( = -2 + 3). However this is wrong according to the spec as
you mentioned because X and Y are not volumes (Inch^3), but Length
(Inch^1).
Even stranger, I have some eGalax devices which declares:
0x05, 0x01, // Usage Page (Generic Desktop) 58
0x09, 0x30, // Usage (X) 60
0x75, 0x10, // Report Size (16) 62
0x95, 0x01, // Report Count (1) 64
0x55, 0x0d, // Unit Exponent (-3) 66
0x65, 0x33, // Unit (Inch^3,EngLinear) 68
0x35, 0x00, // Physical Minimum (0) 70
0x46, 0xc1, 0x20, // Physical Maximum (8385) 72
0x26, 0xff, 0x7f, // Logical Maximum (32767) 75
0x81, 0x02, // Input (Data,Var,Abs) 78
X is a volume, but if you compute in the way it is currently
implemented, it leads to a non unit value :)
Fortunately, latest Win 8 specification for multitouch screens,
requires the unit and unit exponent fields to be correctly
implemented, which I can see on the reports I have.
So I was trying to fix a wrong and fancy interpretation of the spec,
based on some devices which did this bad interpretation.
To sum up:
acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Cheers,
Benjamin
> return 0;
> }
> break;
> --
> 1.8.4.rc3
>
^ permalink raw reply
* Re: [PATCH] HID: i2c-hid: Stop querying for init reports
From: Benjamin Tissoires @ 2013-10-17 17:57 UTC (permalink / raw)
To: Bibek Basu; +Cc: Jiri Kosina, linux-input, linux-kernel@vger.kernel.org
In-Reply-To: <1381825709-5098-1-git-send-email-bbasu@nvidia.com>
Hi Bibek,
On Tue, Oct 15, 2013 at 4:28 AM, Bibek Basu <bbasu@nvidia.com> wrote:
> According to specifications, HID over I2C devices
> are not bound to respond to query for INPUT
> REPORTS. Thus dropping the call during init
> as many devices does not respond causing error
> messages during boot.
>
This time, the patch is removing too many things that are correct. :)
see below to know what to remove and what to keep:
> Signed-off-by: Bibek Basu <bbasu@nvidia.com>
> ---
> drivers/hid/i2c-hid/i2c-hid.c | 59 -------------------------------------------
> 1 file changed, 59 deletions(-)
>
> diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
> index fd7ce37..58a4f12 100644
> --- a/drivers/hid/i2c-hid/i2c-hid.c
> +++ b/drivers/hid/i2c-hid/i2c-hid.c
> @@ -409,62 +409,6 @@ static int i2c_hid_get_report_length(struct hid_report *report)
> report->device->report_enum[report->type].numbered + 2;
> }
>
> -static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
> - size_t bufsize)
> -{
> - struct hid_device *hid = report->device;
> - struct i2c_client *client = hid->driver_data;
> - struct i2c_hid *ihid = i2c_get_clientdata(client);
> - unsigned int size, ret_size;
> -
> - size = i2c_hid_get_report_length(report);
> - if (i2c_hid_get_report(client,
> - report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
> - report->id, buffer, size))
> - return;
> -
> - i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, ihid->inbuf);
> -
> - ret_size = buffer[0] | (buffer[1] << 8);
> -
> - if (ret_size != size) {
> - dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
> - __func__, size, ret_size);
> - return;
> - }
> -
> - /* hid->driver_lock is held as we are in probe function,
> - * we just need to setup the input fields, so using
> - * hid_report_raw_event is safe. */
> - hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
> -}
This function should be kept
> -
> -/*
> - * Initialize all reports
> - */
> -static void i2c_hid_init_reports(struct hid_device *hid)
> -{
> - struct hid_report *report;
> - struct i2c_client *client = hid->driver_data;
> - struct i2c_hid *ihid = i2c_get_clientdata(client);
> - u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
> -
> - if (!inbuf) {
> - dev_err(&client->dev, "can not retrieve initial reports\n");
> - return;
> - }
> -
Above should be kept
> - list_for_each_entry(report,
> - &hid->report_enum[HID_INPUT_REPORT].report_list, list)
> - i2c_hid_init_report(report, inbuf, ihid->bufsize);
> -
these for lines should be removed (they are the one giving the errors
in the logs)
and please keep the rest of the code as is.
> - list_for_each_entry(report,
> - &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
> - i2c_hid_init_report(report, inbuf, ihid->bufsize);
Actually, this part is very important because we have no spontaneous
events emitted by features, so we don't know the value of the feature
until we probed it. So please keep this part as mentioned above.
Cheers,
Benjamin
> -
> - kfree(inbuf);
> -}
> -
> /*
> * Traverse the supplied list of reports and find the longest
> */
> @@ -683,9 +627,6 @@ static int i2c_hid_start(struct hid_device *hid)
> return ret;
> }
>
> - if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
> - i2c_hid_init_reports(hid);
> -
> return 0;
> }
>
> --
> 1.8.1.5
>
^ permalink raw reply
* Re: [PATCH v2] drivers: input: mouse: Remove useless casting in cypress_ps2.c
From: Dmitry Torokhov @ 2013-10-17 17:19 UTC (permalink / raw)
To: Geyslan G. Bem
Cc: dudl, kamal, mario_limonciello, git, linux-input, linux-kernel,
kernel-br
In-Reply-To: <1381962675-26876-1-git-send-email-geyslan@gmail.com>
On Wed, Oct 16, 2013 at 07:31:15PM -0300, Geyslan G. Bem wrote:
> Get rid of unnecessary (void *) casting in 'cypress_init' function.
>
> Signed-off-by: Geyslan G. Bem <geyslan@gmail.com>
Applied, thank you.
> ---
> drivers/input/mouse/cypress_ps2.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
> index f51765f..b87d7ba 100644
> --- a/drivers/input/mouse/cypress_ps2.c
> +++ b/drivers/input/mouse/cypress_ps2.c
> @@ -680,7 +680,7 @@ int cypress_init(struct psmouse *psmouse)
> struct cytp_data *cytp;
>
> cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
> - psmouse->private = (void *)cytp;
> + psmouse->private = cytp;
> if (cytp == NULL)
> return -ENOMEM;
>
> --
> 1.8.4
>
--
Dmitry
^ permalink raw reply
* [Patch v2][ 15/37] Input: tsc2007: Add device tree support.
From: Denis Carikli @ 2013-10-17 15:02 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-arm-kernel, Eric Bénard, Denis Carikli, Rob Herring,
Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell,
devicetree, Dmitry Torokhov, linux-input
In-Reply-To: <1382022155-21954-1-git-send-email-denis@eukrea.com>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Stephen Warren <swarren@wwwdotorg.org>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: devicetree@vger.kernel.org
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: Eric Bénard <eric@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
.../bindings/input/touchscreen/tsc2007.txt | 44 +++++
drivers/input/touchscreen/tsc2007.c | 200 +++++++++++++++-----
2 files changed, 201 insertions(+), 43 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
new file mode 100644
index 0000000..d67b33f
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt
@@ -0,0 +1,44 @@
+* Texas Instruments tsc2007 touchscreen controller
+
+Required properties:
+- compatible: must be "ti,tsc2007".
+- reg: I2C address of the chip.
+- pinctrl-0: Should specify pin control groups used for this controller
+ (see pinctrl bindings[0]).
+- pinctrl-names: Should contain only one value - "default"
+ (see pinctrl bindings[0]).
+- interrupt-parent: the phandle for the interrupt controller
+ (see interrupt binding[1]).
+- interrupts: interrupt to which the chip is connected
+ (see interrupt binding[1]).
+- x-plate-ohms: X-plate resistance in ohms.
+
+Optional properties:
+- gpios: the interrupt gpio the chip is connected to (trough the penirq pin)
+ (see GPIO binding[2] for more details).
+- max-rt: maximum pressure.
+- fuzzy: specifies the fuzz value that is used to filter noise from the event
+ stream.
+- poll-period: how much time to wait(in millisecond) before reading again the
+ values from the tsc2007.
+
+[0]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+[1]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+[2]: Documentation/devicetree/bindings/gpio/gpio.txt
+
+Example:
+ &i2c1 {
+ /* ... */
+ tsc2007@49 {
+ compatible = "ti,tsc2007";
+ reg = <0x49>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc2007_1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <0x0 0x8>;
+ gpios = <&gpio4 0 0>;
+ x-plate-ohms = <180>;
+ };
+
+ /* ... */
+ };
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 0b67ba4..b1ab6c0 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -26,6 +26,9 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -74,7 +77,10 @@ struct tsc2007 {
u16 max_rt;
unsigned long poll_delay;
unsigned long poll_period;
+ int fuzzy;
+ char of;
+ unsigned gpio;
int irq;
wait_queue_head_t wait;
@@ -84,6 +90,14 @@ struct tsc2007 {
void (*clear_penirq)(void);
};
+static int tsc2007_get_pendown_state_dt(struct tsc2007 *ts)
+{
+ if (gpio_is_valid(ts->gpio))
+ return !gpio_get_value(ts->gpio);
+ else
+ return true;
+}
+
static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
{
s32 data;
@@ -158,6 +172,9 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts)
* to fall back on the pressure reading.
*/
+ if (ts->of)
+ return tsc2007_get_pendown_state_dt(ts);
+
if (!ts->get_pendown_state)
return true;
@@ -175,10 +192,10 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
/* pen is down, continue with the measurement */
tsc2007_read_values(ts, &tc);
-
rt = tsc2007_calculate_pressure(ts, &tc);
- if (rt == 0 && !ts->get_pendown_state) {
+ if ((ts->of && rt == 0 && ts->gpio < 0) ||
+ (!ts->of && rt == 0 && !ts->get_pendown_state)) {
/*
* If pressure reported is 0 and we don't have
* callback to check pendown state, we have to
@@ -198,7 +215,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
-
} else {
/*
* Sample found inconsistent by debouncing or pressure is
@@ -217,7 +233,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
-
if (ts->clear_penirq)
ts->clear_penirq();
@@ -228,11 +243,17 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;
- if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
- return IRQ_WAKE_THREAD;
+ if (!ts->of) {
+ if (!ts->get_pendown_state || likely(ts->get_pendown_state()))
+ return IRQ_WAKE_THREAD;
- if (ts->clear_penirq)
- ts->clear_penirq();
+ if (ts->clear_penirq)
+ ts->clear_penirq();
+ } else {
+ if ((!gpio_is_valid(ts->gpio)) ||
+ likely(tsc2007_get_pendown_state_dt(ts)))
+ return IRQ_WAKE_THREAD;
+ }
return IRQ_HANDLED;
}
@@ -273,34 +294,64 @@ static void tsc2007_close(struct input_dev *input_dev)
tsc2007_stop(ts);
}
-static int tsc2007_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+#ifdef CONFIG_OF
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+ struct device_node *np)
{
- struct tsc2007 *ts;
- struct tsc2007_platform_data *pdata = client->dev.platform_data;
- struct input_dev *input_dev;
- int err;
-
- if (!pdata) {
- dev_err(&client->dev, "platform data is required!\n");
+ int err = 0;
+ u32 val32;
+ u64 val64;
+
+ if (!of_property_read_u32(np, "max-rt", &val32))
+ ts->max_rt = val32;
+ else
+ ts->max_rt = MAX_12BIT;
+
+ if (!of_property_read_u32(np, "fuzzy", &val32))
+ ts->fuzzy = val32;
+
+ if (!of_property_read_u64(np, "poll-period", &val64))
+ ts->poll_period = val64;
+ else
+ ts->poll_period = 1;
+
+ if (!of_property_read_u32(np, "x-plate-ohms", &val32)) {
+ ts->x_plate_ohms = val32;
+ } else {
+ dev_err(&client->dev,
+ "x-plate-ohms is not set up in the devicetree."
+ " (err %d).", err);
return -EINVAL;
}
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -EIO;
+ ts->gpio = of_get_gpio(np, 0);
+ if (!gpio_is_valid(ts->gpio))
+ dev_err(&client->dev, "GPIO not found "
+ "(of_get_gpio returned %d)\n", ts->gpio);
- ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
+ /* Used to detect if it is probed trough the device tree,
+ * in order to be able to use that information in the IRQ handler.
+ */
+ ts->of = 1;
- ts->client = client;
- ts->irq = client->irq;
- ts->input = input_dev;
- init_waitqueue_head(&ts->wait);
+ return 0;
+}
+#else
+static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts,
+ struct device_node *np)
+{
+ return -ENODEV;
+}
+#endif
+
+static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts,
+ struct tsc2007_platform_data *pdata,
+ const struct i2c_device_id *id)
+{
+ if (!pdata) {
+ dev_err(&client->dev, "platform data is required!\n");
+ return -EINVAL;
+ }
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
@@ -309,13 +360,59 @@ static int tsc2007_probe(struct i2c_client *client,
ts->poll_period = pdata->poll_period ? : 1;
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
+ ts->fuzzy = pdata->fuzzy;
if (pdata->x_plate_ohms == 0) {
dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
- err = -EINVAL;
+ return -EINVAL;
+ }
+
+ /* Used to detect if it is probed trough the device tree,
+ * in order to be able to use that information in the IRQ handler.
+ */
+ ts->of = 0;
+
+ return 0;
+}
+
+static int tsc2007_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct tsc2007_platform_data *pdata = client->dev.platform_data;
+ struct tsc2007 *ts;
+ struct input_dev *input_dev;
+ int err = 0;
+
+ ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ if (np)
+ err = tsc2007_probe_dt(client, ts, np);
+ else
+ err = tsc2007_probe_pdev(client, ts, pdata, id);
+
+ if (err)
+ goto err_free_mem;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ err = -EIO;
goto err_free_mem;
}
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ err = -ENOMEM;
+ goto err_free_input;
+ };
+
+ ts->client = client;
+ ts->irq = client->irq;
+ ts->input = input_dev;
+ init_waitqueue_head(&ts->wait);
+
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
@@ -331,19 +428,21 @@ static int tsc2007_probe(struct i2c_client *client,
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
- pdata->fuzzz, 0);
+ ts->fuzzy, 0);
- if (pdata->init_platform_hw)
- pdata->init_platform_hw();
+ if (!np) {
+ if (pdata->init_platform_hw)
+ pdata->init_platform_hw();
+ }
err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq,
IRQF_ONESHOT, client->dev.driver->name, ts);
if (err < 0) {
dev_err(&client->dev, "irq %d busy?\n", ts->irq);
- goto err_free_mem;
+ goto err_free_input;
}
tsc2007_stop(ts);
@@ -358,23 +457,29 @@ static int tsc2007_probe(struct i2c_client *client,
err_free_irq:
free_irq(ts->irq, ts);
- if (pdata->exit_platform_hw)
- pdata->exit_platform_hw();
- err_free_mem:
+ if (!np) {
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
+ }
+ err_free_input:
input_free_device(input_dev);
+ err_free_mem:
kfree(ts);
return err;
}
static int tsc2007_remove(struct i2c_client *client)
{
+ struct device_node *np = client->dev.of_node;
struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data;
free_irq(ts->irq, ts);
- if (pdata->exit_platform_hw)
- pdata->exit_platform_hw();
+ if (!np) {
+ if (pdata->exit_platform_hw)
+ pdata->exit_platform_hw();
+ }
input_unregister_device(ts->input);
kfree(ts);
@@ -389,10 +494,19 @@ static const struct i2c_device_id tsc2007_idtable[] = {
MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
+#ifdef CONFIG_OF
+static const struct of_device_id tsc2007_of_match[] = {
+ { .compatible = "ti,tsc2007" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, tsc2007_of_match);
+#endif
+
static struct i2c_driver tsc2007_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "tsc2007"
+ .name = "tsc2007",
+ .of_match_table = of_match_ptr(tsc2007_of_match),
},
.id_table = tsc2007_idtable,
.probe = tsc2007_probe,
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH 3/3] iio: at91: introduce touch screen support in iio adc driver
From: Josh Wu @ 2013-10-17 5:20 UTC (permalink / raw)
To: dmitry.torokhov
Cc: thomas.petazzoni, mark.rutland, devicetree, linux-iio,
nicolas.ferre, b.brezillon, Jonathan Cameron, linux-input,
maxime.ripard, plagnioj, linux-arm-kernel
In-Reply-To: <5255B918.2020705@kernel.org>
Hi, Dimitry
Could give some feedback for this v4 patch if you have time? Since It
has been stuck for a while.
Thanks.
Best Regards,
Josh Wu
On 10/10/2013 4:14 AM, Jonathan Cameron wrote:
> On 10/08/13 04:48, Josh Wu wrote:
>> AT91 ADC hardware integrate touch screen support. So this patch add touch
>> screen support for at91 adc iio driver.
>> To enable touch screen support in adc, you need to add the dt parameters:
>> 1. which type of touch are used? (4 or 5 wires), sample period time.
>> 2. correct pressure detect threshold value.
>>
>> In the meantime, since touch screen will use a interal period trigger of adc,
>> so it is conflict to other hardware triggers. Driver will disable the hardware
>> trigger support if touch screen is enabled.
>>
>> This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.
>>
>> Signed-off-by: Josh Wu <josh.wu@atmel.com>
>> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> CC: devicetree@vger.kernel.org
> Hi Josh. I am not going to take this for now both because I want to have
> a close read of it when I have more time and because I want input from
> Dmitry on this one.
>
> Thanks,
>
> Jonathan
>> ---
>> .../devicetree/bindings/arm/atmel-adc.txt | 7 +
>> arch/arm/mach-at91/include/mach/at91_adc.h | 34 ++
>> drivers/iio/adc/at91_adc.c | 388 ++++++++++++++++++--
>> 3 files changed, 405 insertions(+), 24 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> index 0e65e01..d106146 100644
>> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
>> @@ -23,6 +23,13 @@ Optional properties:
>> resolution will be used.
>> - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
>> - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>> + - atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
>> + value is set, then adc driver will enable touch screen
>> + support.
>> + NOTE: when adc touch screen enabled, the adc hardware trigger will be
>> + disabled. Since touch screen will occupied the trigger register.
>> + - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
>> + make touch detect more precision.
>>
>> Optional trigger Nodes:
>> - Required properties:
>> diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
>> index 048a57f..c287307 100644
>> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
>> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
>> @@ -60,14 +60,48 @@
>> #define AT91_ADC_IER 0x24 /* Interrupt Enable Register */
>> #define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */
>> #define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */
>> +#define AT91_ADC_IER_PEN (1 << 29)
>> +#define AT91_ADC_IER_NOPEN (1 << 30)
>> +#define AT91_ADC_IER_XRDY (1 << 20)
>> +#define AT91_ADC_IER_YRDY (1 << 21)
>> +#define AT91_ADC_IER_PRDY (1 << 22)
>> +#define AT91_ADC_ISR_PENS (1 << 31)
>>
>> #define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */
>> #define AT91_ADC_DATA (0x3ff)
>>
>> #define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */
>>
>> +#define AT91_ADC_ACR 0x94 /* Analog Control Register */
>> +#define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */
>> +
>> +#define AT91_ADC_TSMR 0xB0
>> +#define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */
>> +#define AT91_ADC_TSMR_TSMODE_NONE (0 << 0)
>> +#define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0)
>> +#define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0)
>> +#define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0)
>> +#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */
>> +#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4)
>> +#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */
>> +#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */
>> +#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28)
>> +#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */
>> +#define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */
>> +#define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */
>> +
>> +#define AT91_ADC_TSXPOSR 0xB4
>> +#define AT91_ADC_TSYPOSR 0xB8
>> +#define AT91_ADC_TSPRESSR 0xBC
>> +
>> #define AT91_ADC_TRGR_9260 AT91_ADC_MR
>> #define AT91_ADC_TRGR_9G45 0x08
>> #define AT91_ADC_TRGR_9X5 0xC0
>>
>> +/* Trigger Register bit field */
>> +#define AT91_ADC_TRGR_TRGPER (0xffff << 16)
>> +#define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16)
>> +#define AT91_ADC_TRGR_TRGMOD (0x7 << 0)
>> +#define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0)
>> +
>> #endif
>> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
>> index 22cf61d2..68ddd7f 100644
>> --- a/drivers/iio/adc/at91_adc.c
>> +++ b/drivers/iio/adc/at91_adc.c
>> @@ -11,6 +11,7 @@
>> #include <linux/clk.h>
>> #include <linux/err.h>
>> #include <linux/io.h>
>> +#include <linux/input.h>
>> #include <linux/interrupt.h>
>> #include <linux/jiffies.h>
>> #include <linux/kernel.h>
>> @@ -39,7 +40,23 @@
>> #define at91_adc_writel(st, reg, val) \
>> (writel_relaxed(val, st->reg_base + reg))
>>
>> +#define DRIVER_NAME "at91_adc"
>> +#define MAX_POS_BITS 12
>> +
>> +#define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
>> +#define TOUCH_PEN_DETECT_DEBOUNCE_US 200
>> +
>> struct at91_adc_caps {
>> + bool has_ts; /* Support touch screen */
>> + bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */
>> + /*
>> + * Numbers of sampling data will be averaged. Can be 0~3.
>> + * Hardware can average (2 ^ ts_filter_average) sample data.
>> + */
>> + u8 ts_filter_average;
>> + /* Pen Detection input pull-up resistor, can be 0~3 */
>> + u8 ts_pen_detect_sensitivity;
>> +
>> /* startup time calculate function */
>> u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
>>
>> @@ -47,6 +64,12 @@ struct at91_adc_caps {
>> struct at91_adc_reg_desc registers;
>> };
>>
>> +enum atmel_adc_ts_type {
>> + ATMEL_ADC_TOUCHSCREEN_NONE = 0,
>> + ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
>> + ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
>> +};
>> +
>> struct at91_adc_state {
>> struct clk *adc_clk;
>> u16 *buffer;
>> @@ -71,6 +94,26 @@ struct at91_adc_state {
>> bool low_res; /* the resolution corresponds to the lowest one */
>> wait_queue_head_t wq_data_avail;
>> struct at91_adc_caps *caps;
>> +
>> + /*
>> + * Following ADC channels are shared by touchscreen:
>> + *
>> + * CH0 -- Touch screen XP/UL
>> + * CH1 -- Touch screen XM/UR
>> + * CH2 -- Touch screen YP/LL
>> + * CH3 -- Touch screen YM/Sense
>> + * CH4 -- Touch screen LR(5-wire only)
>> + *
>> + * The bitfields below represents the reserved channel in the
>> + * touchscreen mode.
>> + */
>> +#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 0)
>> +#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 0)
>> + enum atmel_adc_ts_type touchscreen_type;
>> + struct input_dev *ts_input;
>> +
>> + u16 ts_sample_period_val;
>> + u32 ts_pressure_threshold;
>> };
>>
>> static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> @@ -105,14 +148,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>> return IRQ_HANDLED;
>> }
>>
>> -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>> +/* Handler for classic adc channel eoc trigger */
>> +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>> {
>> - struct iio_dev *idev = private;
>> struct at91_adc_state *st = iio_priv(idev);
>> - u32 status = at91_adc_readl(st, st->registers->status_register);
>> -
>> - if (!(status & st->registers->drdy_mask))
>> - return IRQ_HANDLED;
>>
>> if (iio_buffer_enabled(idev)) {
>> disable_irq_nosync(irq);
>> @@ -122,6 +161,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>> st->done = true;
>> wake_up_interruptible(&st->wq_data_avail);
>> }
>> +}
>> +
>> +static int at91_ts_sample(struct at91_adc_state *st)
>> +{
>> + unsigned int xscale, yscale, reg, z1, z2;
>> + unsigned int x, y, pres, xpos, ypos;
>> + unsigned int rxp = 1;
>> + unsigned int factor = 1000;
>> + struct iio_dev *idev = iio_priv_to_dev(st);
>> +
>> + unsigned int xyz_mask_bits = st->res;
>> + unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
>> +
>> + /* calculate position */
>> + /* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
>> + reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
>> + xpos = reg & xyz_mask;
>> + x = (xpos << MAX_POS_BITS) - xpos;
>> + xscale = (reg >> 16) & xyz_mask;
>> + if (xscale == 0) {
>> + dev_err(&idev->dev, "Error: xscale == 0!\n");
>> + return -1;
>> + }
>> + x /= xscale;
>> +
>> + /* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
>> + reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
>> + ypos = reg & xyz_mask;
>> + y = (ypos << MAX_POS_BITS) - ypos;
>> + yscale = (reg >> 16) & xyz_mask;
>> + if (yscale == 0) {
>> + dev_err(&idev->dev, "Error: yscale == 0!\n");
>> + return -1;
>> + }
>> + y /= yscale;
>> +
>> + /* calculate the pressure */
>> + reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
>> + z1 = reg & xyz_mask;
>> + z2 = (reg >> 16) & xyz_mask;
>> +
>> + if (z1 != 0)
>> + pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
>> + / factor;
>> + else
>> + pres = st->ts_pressure_threshold; /* no pen contacted */
>> +
>> + dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
>> + xpos, xscale, ypos, yscale, z1, z2, pres);
>> +
>> + if (pres < st->ts_pressure_threshold) {
>> + dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
>> + x, y, pres / factor);
>> + input_report_abs(st->ts_input, ABS_X, x);
>> + input_report_abs(st->ts_input, ABS_Y, y);
>> + input_report_abs(st->ts_input, ABS_PRESSURE, pres);
>> + input_report_key(st->ts_input, BTN_TOUCH, 1);
>> + input_sync(st->ts_input);
>> + } else {
>> + dev_dbg(&idev->dev, "pressure too low: not reporting\n");
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static irqreturn_t at91_adc_interrupt(int irq, void *private)
>> +{
>> + struct iio_dev *idev = private;
>> + struct at91_adc_state *st = iio_priv(idev);
>> + u32 status = at91_adc_readl(st, st->registers->status_register);
>> + const uint32_t ts_data_irq_mask =
>> + AT91_ADC_IER_XRDY |
>> + AT91_ADC_IER_YRDY |
>> + AT91_ADC_IER_PRDY;
>> +
>> + if (status & st->registers->drdy_mask)
>> + handle_adc_eoc_trigger(irq, idev);
>> +
>> + if (status & AT91_ADC_IER_PEN) {
>> + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
>> + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
>> + ts_data_irq_mask);
>> + /* Set up period trigger for sampling */
>> + at91_adc_writel(st, st->registers->trigger_register,
>> + AT91_ADC_TRGR_MOD_PERIOD_TRIG |
>> + AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
>> + } else if (status & AT91_ADC_IER_NOPEN) {
>> + at91_adc_writel(st, st->registers->trigger_register, 0);
>> + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
>> + ts_data_irq_mask);
>> + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
>> +
>> + input_report_key(st->ts_input, BTN_TOUCH, 0);
>> + input_sync(st->ts_input);
>> + } else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
>> + /* Now all touchscreen data is ready */
>> +
>> + if (status & AT91_ADC_ISR_PENS) {
>> + /* validate data by pen contact */
>> + at91_ts_sample(st);
>> + } else {
>> + /* triggered by event that is no pen contact, just read
>> + * them to clean the interrupt and discard all.
>> + */
>> + at91_adc_readl(st, AT91_ADC_TSXPOSR);
>> + at91_adc_readl(st, AT91_ADC_TSYPOSR);
>> + at91_adc_readl(st, AT91_ADC_TSPRESSR);
>> + }
>> + }
>>
>> return IRQ_HANDLED;
>> }
>> @@ -131,6 +279,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
>> struct at91_adc_state *st = iio_priv(idev);
>> struct iio_chan_spec *chan_array, *timestamp;
>> int bit, idx = 0;
>> + unsigned long rsvd_mask = 0;
>> +
>> + /* If touchscreen is enable, then reserve the adc channels */
>> + if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
>> + rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
>> + else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
>> + rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
>> +
>> + /* set up the channel mask to reserve touchscreen channels */
>> + st->channels_mask &= ~rsvd_mask;
>>
>> idev->num_channels = bitmap_weight(&st->channels_mask,
>> st->num_channels) + 1;
>> @@ -479,6 +637,39 @@ static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
>>
>> static const struct of_device_id at91_adc_dt_ids[];
>>
>> +static int at91_adc_probe_dt_ts(struct device_node *node,
>> + struct at91_adc_state *st, struct device *dev)
>> +{
>> + int ret;
>> + u32 prop;
>> +
>> + ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
>> + if (ret) {
>> + dev_info(dev, "ADC Touch screen is disabled.\n");
>> + return 0;
>> + }
>> +
>> + switch (prop) {
>> + case 4:
>> + case 5:
>> + st->touchscreen_type = prop;
>> + break;
>> + default:
>> + dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
>> + return -EINVAL;
>> + }
>> +
>> + prop = 0;
>> + of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
>> + st->ts_pressure_threshold = prop;
>> + if (st->ts_pressure_threshold) {
>> + return 0;
>> + } else {
>> + dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
>> + return -EINVAL;
>> + }
>> +}
>> +
>> static int at91_adc_probe_dt(struct at91_adc_state *st,
>> struct platform_device *pdev)
>> {
>> @@ -560,6 +751,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>> i++;
>> }
>>
>> + /* Check if touchscreen is supported. */
>> + if (st->caps->has_ts)
>> + return at91_adc_probe_dt_ts(node, st, &idev->dev);
>> + else
>> + dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
>> +
>> return 0;
>>
>> error_ret:
>> @@ -591,6 +788,114 @@ static const struct iio_info at91_adc_info = {
>> .read_raw = &at91_adc_read_raw,
>> };
>>
>> +/* Touchscreen related functions */
>> +static int atmel_ts_open(struct input_dev *dev)
>> +{
>> + struct at91_adc_state *st = input_get_drvdata(dev);
>> +
>> + at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
>> + return 0;
>> +}
>> +
>> +static void atmel_ts_close(struct input_dev *dev)
>> +{
>> + struct at91_adc_state *st = input_get_drvdata(dev);
>> +
>> + at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
>> +}
>> +
>> +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
>> +{
>> + u32 reg = 0, pendbc;
>> + int i = 0;
>> +
>> + if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
>> + reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
>> + else
>> + reg = AT91_ADC_TSMR_TSMODE_5WIRE;
>> +
>> + /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
>> + * pen detect noise.
>> + * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
>> + */
>> + pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
>> +
>> + while (pendbc >> ++i)
>> + ; /* Empty! Find the shift offset */
>> + if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
>> + pendbc = i;
>> + else
>> + pendbc = i - 1;
>> +
>> + if (st->caps->has_tsmr) {
>> + reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
>> + & AT91_ADC_TSMR_TSAV;
>> + reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
>> + reg |= AT91_ADC_TSMR_NOTSDMA;
>> + reg |= AT91_ADC_TSMR_PENDET_ENA;
>> + reg |= 0x03 << 8; /* TSFREQ, need bigger than TSAV */
>> +
>> + at91_adc_writel(st, AT91_ADC_TSMR, reg);
>> + } else {
>> + /* TODO: for 9g45 which has no TSMR */
>> + }
>> +
>> + /* Change adc internal resistor value for better pen detection,
>> + * default value is 100 kOhm.
>> + * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
>> + * option only available on ES2 and higher
>> + */
>> + at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
>> + & AT91_ADC_ACR_PENDETSENS);
>> +
>> + /* Sample Peroid Time = (TRGPER + 1) / ADCClock */
>> + st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
>> + adc_clk_khz / 1000) - 1, 1);
>> +
>> + return 0;
>> +}
>> +
>> +static int at91_ts_register(struct at91_adc_state *st,
>> + struct platform_device *pdev)
>> +{
>> + struct input_dev *input;
>> + struct iio_dev *idev = iio_priv_to_dev(st);
>> + int ret;
>> +
>> + input = input_allocate_device();
>> + if (!input) {
>> + dev_err(&idev->dev, "Failed to allocate TS device!\n");
>> + return -ENOMEM;
>> + }
>> +
>> + input->name = DRIVER_NAME;
>> + input->id.bustype = BUS_HOST;
>> + input->dev.parent = &pdev->dev;
>> + input->open = atmel_ts_open;
>> + input->close = atmel_ts_close;
>> +
>> + __set_bit(EV_ABS, input->evbit);
>> + __set_bit(EV_KEY, input->evbit);
>> + __set_bit(BTN_TOUCH, input->keybit);
>> + input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
>> + input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
>> + input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
>> +
>> + st->ts_input = input;
>> + input_set_drvdata(input, st);
>> +
>> + ret = input_register_device(input);
>> + if (ret)
>> + input_free_device(st->ts_input);
>> +
>> + return ret;
>> +}
>> +
>> +static void at91_ts_unregister(struct at91_adc_state *st)
>> +{
>> + input_unregister_device(st->ts_input);
>> +}
>> +
>> static int at91_adc_probe(struct platform_device *pdev)
>> {
>> unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
>> @@ -642,7 +947,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>> at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
>> at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
>> ret = request_irq(st->irq,
>> - at91_adc_eoc_trigger,
>> + at91_adc_interrupt,
>> 0,
>> pdev->dev.driver->name,
>> idev);
>> @@ -687,6 +992,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>> mstrclk = clk_get_rate(st->clk);
>> adc_clk = clk_get_rate(st->adc_clk);
>> adc_clk_khz = adc_clk / 1000;
>> +
>> + dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
>> + mstrclk, adc_clk);
>> +
>> prsc = (mstrclk / (2 * adc_clk)) - 1;
>>
>> if (!st->startup_time) {
>> @@ -723,30 +1032,52 @@ static int at91_adc_probe(struct platform_device *pdev)
>> init_waitqueue_head(&st->wq_data_avail);
>> mutex_init(&st->lock);
>>
>> - ret = at91_adc_buffer_init(idev);
>> - if (ret < 0) {
>> - dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
>> - goto error_disable_adc_clk;
>> - }
>> + /*
>> + * Since touch screen will set trigger register as period trigger. So
>> + * when touch screen is enabled, then we have to disable hardware
>> + * trigger for classic adc.
>> + */
>> + if (!st->touchscreen_type) {
>> + ret = at91_adc_buffer_init(idev);
>> + if (ret < 0) {
>> + dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
>> + goto error_disable_adc_clk;
>> + }
>>
>> - ret = at91_adc_trigger_init(idev);
>> - if (ret < 0) {
>> - dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
>> - goto error_unregister_buffer;
>> + ret = at91_adc_trigger_init(idev);
>> + if (ret < 0) {
>> + dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
>> + at91_adc_buffer_remove(idev);
>> + goto error_disable_adc_clk;
>> + }
>> + } else {
>> + if (!st->caps->has_tsmr) {
>> + dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
>> + goto error_disable_adc_clk;
>> + }
>> +
>> + ret = at91_ts_register(st, pdev);
>> + if (ret)
>> + goto error_disable_adc_clk;
>> +
>> + at91_ts_hw_init(st, adc_clk_khz);
>> }
>>
>> ret = iio_device_register(idev);
>> if (ret < 0) {
>> dev_err(&pdev->dev, "Couldn't register the device.\n");
>> - goto error_remove_triggers;
>> + goto error_iio_device_register;
>> }
>>
>> return 0;
>>
>> -error_remove_triggers:
>> - at91_adc_trigger_remove(idev);
>> -error_unregister_buffer:
>> - at91_adc_buffer_remove(idev);
>> +error_iio_device_register:
>> + if (!st->touchscreen_type) {
>> + at91_adc_trigger_remove(idev);
>> + at91_adc_buffer_remove(idev);
>> + } else {
>> + at91_ts_unregister(st);
>> + }
>> error_disable_adc_clk:
>> clk_disable_unprepare(st->adc_clk);
>> error_disable_clk:
>> @@ -762,8 +1093,12 @@ static int at91_adc_remove(struct platform_device *pdev)
>> struct at91_adc_state *st = iio_priv(idev);
>>
>> iio_device_unregister(idev);
>> - at91_adc_trigger_remove(idev);
>> - at91_adc_buffer_remove(idev);
>> + if (!st->touchscreen_type) {
>> + at91_adc_trigger_remove(idev);
>> + at91_adc_buffer_remove(idev);
>> + } else {
>> + at91_ts_unregister(st);
>> + }
>> clk_disable_unprepare(st->adc_clk);
>> clk_disable_unprepare(st->clk);
>> free_irq(st->irq, idev);
>> @@ -786,6 +1121,7 @@ static struct at91_adc_caps at91sam9260_caps = {
>> };
>>
>> static struct at91_adc_caps at91sam9g45_caps = {
>> + .has_ts = true,
>> .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
>> .num_channels = 8,
>> .registers = {
>> @@ -799,6 +1135,10 @@ static struct at91_adc_caps at91sam9g45_caps = {
>> };
>>
>> static struct at91_adc_caps at91sam9x5_caps = {
>> + .has_ts = true,
>> + .has_tsmr = true,
>> + .ts_filter_average = 3,
>> + .ts_pen_detect_sensitivity = 2,
>> .calc_startup_ticks = calc_startup_ticks_9x5,
>> .num_channels = 12,
>> .registers = {
>> @@ -825,7 +1165,7 @@ static struct platform_driver at91_adc_driver = {
>> .probe = at91_adc_probe,
>> .remove = at91_adc_remove,
>> .driver = {
>> - .name = "at91_adc",
>> + .name = DRIVER_NAME,
>> .of_match_table = of_match_ptr(at91_adc_dt_ids),
>> },
>> };
>>
^ permalink raw reply
* [PATCH] input: wacom - make sure touch_max is set for touch devices
From: Ping Cheng @ 2013-10-17 0:06 UTC (permalink / raw)
To: linux-input; +Cc: dmitry.torokhov, killertofu, Ping Cheng
Old single touch Tablet PCs do not have touch_max set at
wacom_features. Since touch device at lease supports one
finger, assign touch_max to 1 when touch usage is defined
in its HID Descriptor and touch_max is not pre-defined.
Signed-off-by: Ping Cheng <pingc@wacom.com>
--
This patch is based on last posted (unmerged) patch:
"add support for three new Intuos devices"
---
drivers/input/tablet/wacom_sys.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 81d5910..28066bc 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -304,7 +304,7 @@ static int wacom_parse_hid(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
char limit = 0;
/* result has to be defined as int for some devices */
- int result = 0;
+ int result = 0, touch_max = 0;
int i = 0, usage = WCM_UNDEFINED, finger = 0, pen = 0;
unsigned char *report;
@@ -351,7 +351,8 @@ static int wacom_parse_hid(struct usb_interface *intf,
if (usage == WCM_DESKTOP) {
if (finger) {
features->device_type = BTN_TOOL_FINGER;
-
+ /* touch device at least supports one touch point */
+ touch_max = 1;
switch (features->type) {
case TABLETPC2FG:
features->pktlen = WACOM_PKGLEN_TPC2FG;
@@ -504,6 +505,8 @@ static int wacom_parse_hid(struct usb_interface *intf,
}
out:
+ if (!features->touch_max && touch_max)
+ features->touch_max = touch_max;
result = 0;
kfree(report);
return result;
--
1.8.1.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox