linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] HID: uhid: User-space HID I/O driver
@ 2012-06-10 13:16 David Herrmann
  2012-06-10 13:16 ` [PATCH 01/16] HID: uhid: introduce user-space I/O driver support for HID David Herrmann
                   ` (17 more replies)
  0 siblings, 18 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

This adds a new low-level HID driver that allows user-space to implement the
transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
There is already an implementation of HOGP, see the
linux-bluetooth@vger.kernel.org mailing list for this.

I've split this into multiple patches to make review easier. This patchset is
already working for several months for the HOGP developers but there may still
be some issues with it. Please review.

The uhid_*() functions implement the basic module functionality. The
uhid_char_*() functions handle character-device related functionality. The
uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
functions are HID-callbacks.

I am open for any suggestions.

Regards
David

David Herrmann (16):
  HID: uhid: introduce user-space I/O driver support for HID
  HID: uhid: add internal message buffer
  HID: uhid: allow poll()'ing on uhid devices
  HID: uhid: implement read() on uhid devices
  HID: uhid: implement write() on uhid devices
  HID: uhid: add UHID_CREATE and UHID_DESTROY events
  HID: uhid: allow feeding input data into uhid devices
  HID: uhid: forward hid report-descriptor to hid core
  HID: uhid: add UHID_START and UHID_STOP events
  HID: uhid: forward open/close events to user-space
  HID: uhid: forward output request to user-space
  HID: uhid: forward raw output reports to user-space
  HID: uhid: implement feature requests
  HID: uhid: add documentation
  HID: uhid: add example program
  MAINTAINERS: add UHID entry

 Documentation/hid/uhid.txt  |  169 +++++++++++++
 MAINTAINERS                 |    7 +
 drivers/hid/Kconfig         |   21 ++
 drivers/hid/Makefile        |    1 +
 drivers/hid/uhid.c          |  572 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/Kbuild        |    1 +
 include/linux/uhid.h        |  104 ++++++++
 samples/uhid/Makefile       |   10 +
 samples/uhid/uhid-example.c |  381 ++++++++++++++++++++++++++++
 9 files changed, 1266 insertions(+)
 create mode 100644 Documentation/hid/uhid.txt
 create mode 100644 drivers/hid/uhid.c
 create mode 100644 include/linux/uhid.h
 create mode 100644 samples/uhid/Makefile
 create mode 100644 samples/uhid/uhid-example.c

-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/16] HID: uhid: introduce user-space I/O driver support for HID
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 02/16] HID: uhid: add internal message buffer David Herrmann
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

This adds a dummy driver that will support user-space I/O drivers for the
HID subsystem. This allows to write transport-level drivers like USB-HID
and Bluetooth-HID in user-space.

Low-Energy Bluetooth needs this to feed HID data that is parsed in
user-space back into the kernel.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/Kconfig  |   21 ++++++++++++
 drivers/hid/Makefile |    1 +
 drivers/hid/uhid.c   |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 drivers/hid/uhid.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ca7e76c..89bd6b4 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -59,6 +59,27 @@ config HIDRAW
 
 	If unsure, say Y.
 
+config UHID
+	tristate "User-space I/O driver support for HID subsystem"
+	depends on HID
+	default n
+	---help---
+	Say Y here if you want to provide HID I/O Drivers from user-space.
+	This allows to write I/O drivers in user-space and feed the data from
+	the device into the kernel. The kernel parses the HID reports, loads the
+	corresponding HID Device Driver or provides input devices on top of your
+	user-space device.
+
+	This driver cannot be used to parse HID-reports in user-space and write
+	special HID-drivers. You should use hidraw for that.
+	Instead, this driver allows to write the transport-layer driver in
+	user-space like USB-HID and Bluetooth-HID do in kernel-space.
+
+	If unsure, say N.
+
+	To compile this driver as a module, choose M here: the
+	module will be called uhid.
+
 source "drivers/hid/usbhid/Kconfig"
 
 menu "Special HID drivers"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 05913c5..dedc932 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -8,6 +8,7 @@ ifdef CONFIG_DEBUG_FS
 endif
 
 obj-$(CONFIG_HID)		+= hid.o
+obj-$(CONFIG_UHID)		+= uhid.o
 
 obj-$(CONFIG_HID_GENERIC)	+= hid-generic.o
 
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
new file mode 100644
index 0000000..5b02d6c
--- /dev/null
+++ b/drivers/hid/uhid.c
@@ -0,0 +1,88 @@
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/atomic.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/uhid.h>
+#include <linux/wait.h>
+
+#define UHID_NAME	"uhid"
+
+static struct miscdevice uhid_misc;
+
+static int uhid_char_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int uhid_char_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t uhid_char_read(struct file *file, char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
+{
+	return 0;
+}
+
+static const struct file_operations uhid_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uhid_char_open,
+	.release	= uhid_char_release,
+	.read		= uhid_char_read,
+	.write		= uhid_char_write,
+	.poll		= uhid_char_poll,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice uhid_misc = {
+	.fops		= &uhid_fops,
+	.minor		= MISC_DYNAMIC_MINOR,
+	.name		= UHID_NAME,
+};
+
+static int __init uhid_init(void)
+{
+	return misc_register(&uhid_misc);
+}
+
+static void __exit uhid_exit(void)
+{
+	misc_deregister(&uhid_misc);
+}
+
+module_init(uhid_init);
+module_exit(uhid_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
+MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/16] HID: uhid: add internal message buffer
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
  2012-06-10 13:16 ` [PATCH 01/16] HID: uhid: introduce user-space I/O driver support for HID David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 03/16] HID: uhid: allow poll()'ing on uhid devices David Herrmann
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

When receiving messages from the HID subsystem, we need to process them
and store them in an internal buffer so user-space can read() on the char
device to retrieve the messages.

This adds a static buffer for 32 messages to each uhid device. Each
message is dynamically allocated so the uhid_device structure does not get
too big.

uhid_queue() adds a message to the buffer. If the buffer is full, the
message is discarded. uhid_queue_event() is an helper for messages without
payload.

This also adds a public header: uhid.h. It contains the declarations for
the user-space API. It is built around "struct uhid_event" which contains
a type field which specifies the event type and each event can then add a
variable-length payload. For now, there is only a dummy event but later
patches will add new event types and payloads.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/Kbuild |    1 +
 include/linux/uhid.h |   33 +++++++++++++++++++++++++
 3 files changed, 99 insertions(+)
 create mode 100644 include/linux/uhid.h

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 5b02d6c..05ef4b0 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -25,16 +25,81 @@
 #include <linux/wait.h>
 
 #define UHID_NAME	"uhid"
+#define UHID_BUFSIZE	32
+
+struct uhid_device {
+	struct hid_device *hid;
+
+	wait_queue_head_t waitq;
+	spinlock_t qlock;
+	__u8 head;
+	__u8 tail;
+	struct uhid_event *outq[UHID_BUFSIZE];
+};
 
 static struct miscdevice uhid_misc;
 
+static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
+{
+	__u8 newhead;
+
+	newhead = (uhid->head + 1) % UHID_BUFSIZE;
+
+	if (newhead != uhid->tail) {
+		uhid->outq[uhid->head] = ev;
+		uhid->head = newhead;
+		wake_up_interruptible(&uhid->waitq);
+	} else {
+		hid_warn(uhid->hid, "Output queue is full\n");
+		kfree(ev);
+	}
+}
+
+static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
+{
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = event;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return 0;
+}
+
 static int uhid_char_open(struct inode *inode, struct file *file)
 {
+	struct uhid_device *uhid;
+
+	uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
+	if (!uhid)
+		return -ENOMEM;
+
+	spin_lock_init(&uhid->qlock);
+	init_waitqueue_head(&uhid->waitq);
+
+	file->private_data = uhid;
+	nonseekable_open(inode, file);
+
 	return 0;
 }
 
 static int uhid_char_release(struct inode *inode, struct file *file)
 {
+	struct uhid_device *uhid = file->private_data;
+	unsigned int i;
+
+	for (i = 0; i < UHID_BUFSIZE; ++i)
+		kfree(uhid->outq[i]);
+
+	kfree(uhid);
+
 	return 0;
 }
 
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 3973783..8cdabec 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -373,6 +373,7 @@ header-y += tty.h
 header-y += types.h
 header-y += udf_fs_i.h
 header-y += udp.h
+header-y += uhid.h
 header-y += uinput.h
 header-y += uio.h
 header-y += ultrasound.h
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
new file mode 100644
index 0000000..16b786a
--- /dev/null
+++ b/include/linux/uhid.h
@@ -0,0 +1,33 @@
+#ifndef __UHID_H_
+#define __UHID_H_
+
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Public header for user-space communication. We try to keep every structure
+ * aligned but to be safe we also use __attribute__((__packed__)). Therefore,
+ * the communication should be ABI compatible even between architectures.
+ */
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+enum uhid_event_type {
+	UHID_DUMMY,
+};
+
+struct uhid_event {
+	__u32 type;
+} __attribute__((__packed__));
+
+#endif /* __UHID_H_ */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/16] HID: uhid: allow poll()'ing on uhid devices
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
  2012-06-10 13:16 ` [PATCH 01/16] HID: uhid: introduce user-space I/O driver support for HID David Herrmann
  2012-06-10 13:16 ` [PATCH 02/16] HID: uhid: add internal message buffer David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 04/16] HID: uhid: implement read() " David Herrmann
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

As long as the internal buffer is not empty, we return POLLIN to
user-space.

uhid->head and uhid->tail are no atomics so the comparison may return
inexact results. However, this doesn't matter here as user-space would
need to poll() in two threads simultaneously to trigger this. And in this
case it doesn't matter if a cached result is returned or the exact new
result as user-space does not know which thread returns first from poll()
and the following read(). So it is safe to compare the values without
locking.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 05ef4b0..b1a477f 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -117,6 +117,13 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 
 static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
 {
+	struct uhid_device *uhid = file->private_data;
+
+	poll_wait(file, &uhid->waitq, wait);
+
+	if (uhid->head != uhid->tail)
+		return POLLIN | POLLRDNORM;
+
 	return 0;
 }
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/16] HID: uhid: implement read() on uhid devices
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (2 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 03/16] HID: uhid: allow poll()'ing on uhid devices David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 05/16] HID: uhid: implement write() " David Herrmann
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

User-space can use read() to get a single event from uhid devices. read()
does never return multiple events. This allows us to extend the event
structure and still keep backwards compatibility.

If user-space wants to get multiple events in one syscall, they should use
the readv()/writev() syscalls which are supported by uhid.

This introduces a new lock which helps us synchronizing simultaneous reads
from user-space. We also correctly return -EINVAL/-EFAULT only on errors
and retry the read() when some other thread captured the event faster than
we did.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c |   46 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index b1a477f..9386082 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -28,6 +28,7 @@
 #define UHID_BUFSIZE	32
 
 struct uhid_device {
+	struct mutex devlock;
 	struct hid_device *hid;
 
 	wait_queue_head_t waitq;
@@ -81,6 +82,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
 	if (!uhid)
 		return -ENOMEM;
 
+	mutex_init(&uhid->devlock);
 	spin_lock_init(&uhid->qlock);
 	init_waitqueue_head(&uhid->waitq);
 
@@ -106,7 +108,49 @@ static int uhid_char_release(struct inode *inode, struct file *file)
 static ssize_t uhid_char_read(struct file *file, char __user *buffer,
 				size_t count, loff_t *ppos)
 {
-	return 0;
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	unsigned long flags;
+	size_t len;
+
+	/* they need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+try_again:
+	if (file->f_flags & O_NONBLOCK) {
+		if (uhid->head == uhid->tail)
+			return -EAGAIN;
+	} else {
+		ret = wait_event_interruptible(uhid->waitq,
+						uhid->head != uhid->tail);
+		if (ret)
+			return ret;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	if (uhid->head == uhid->tail) {
+		mutex_unlock(&uhid->devlock);
+		goto try_again;
+	} else {
+		len = min(count, sizeof(**uhid->outq));
+		if (copy_to_user(buffer, &uhid->outq[uhid->tail], len)) {
+			ret = -EFAULT;
+		} else {
+			kfree(uhid->outq[uhid->tail]);
+			uhid->outq[uhid->tail] = NULL;
+
+			spin_lock_irqsave(&uhid->qlock, flags);
+			uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
+			spin_unlock_irqrestore(&uhid->qlock, flags);
+		}
+	}
+
+	mutex_unlock(&uhid->devlock);
+	return ret ? ret : len;
 }
 
 static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/16] HID: uhid: implement write() on uhid devices
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (3 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 04/16] HID: uhid: implement read() " David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 06/16] HID: uhid: add UHID_CREATE and UHID_DESTROY events David Herrmann
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

Similar to read() you can only write() a single event with one call to an
uhid device. To write multiple events use writev() which is supported by
uhid.

We currently always return -EOPNOTSUPP but other events will be added in
later patches.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c |   31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 9386082..31e8379 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -30,6 +30,7 @@
 struct uhid_device {
 	struct mutex devlock;
 	struct hid_device *hid;
+	struct uhid_event input_buf;
 
 	wait_queue_head_t waitq;
 	spinlock_t qlock;
@@ -156,7 +157,35 @@ try_again:
 static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 				size_t count, loff_t *ppos)
 {
-	return 0;
+	struct uhid_device *uhid = file->private_data;
+	int ret;
+	size_t len;
+
+	/* we need at least the "type" member of uhid_event */
+	if (count < sizeof(__u32))
+		return -EINVAL;
+
+	ret = mutex_lock_interruptible(&uhid->devlock);
+	if (ret)
+		return ret;
+
+	memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
+	len = min(count, sizeof(uhid->input_buf));
+	if (copy_from_user(&uhid->input_buf, buffer, len)) {
+		ret = -EFAULT;
+		goto unlock;
+	}
+
+	switch (uhid->input_buf.type) {
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+unlock:
+	mutex_unlock(&uhid->devlock);
+
+	/* return "count" not "len" to not confuse the caller */
+	return ret ? ret : count;
 }
 
 static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/16] HID: uhid: add UHID_CREATE and UHID_DESTROY events
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (4 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 05/16] HID: uhid: implement write() " David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 07/16] HID: uhid: allow feeding input data into uhid devices David Herrmann
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

UHID_CREATE and UHID_DESTROY are used to create and destroy a device on an
open uhid char-device. Internally, we allocate and register an HID device
with the HID core and immediately start the device. From now on events may
be received or sent to the device.

The UHID_CREATE event has a payload similar to the data used by
Bluetooth-HIDP when creating a new connection.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |  144 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/uhid.h |   21 +++++++-
 2 files changed, 164 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 31e8379..61ee7cc 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -29,6 +29,11 @@
 
 struct uhid_device {
 	struct mutex devlock;
+	bool running;
+
+	__u8 *rd_data;
+	uint rd_size;
+
 	struct hid_device *hid;
 	struct uhid_event input_buf;
 
@@ -75,6 +80,136 @@ static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
 	return 0;
 }
 
+static int uhid_hid_start(struct hid_device *hid)
+{
+	return 0;
+}
+
+static void uhid_hid_stop(struct hid_device *hid)
+{
+}
+
+static int uhid_hid_open(struct hid_device *hid)
+{
+	return 0;
+}
+
+static void uhid_hid_close(struct hid_device *hid)
+{
+}
+
+static int uhid_hid_input(struct input_dev *input, unsigned int type,
+			  unsigned int code, int value)
+{
+	return 0;
+}
+
+static int uhid_hid_parse(struct hid_device *hid)
+{
+	return 0;
+}
+
+static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
+			    __u8 *buf, size_t count, unsigned char rtype)
+{
+	return 0;
+}
+
+static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
+			       unsigned char report_type)
+{
+	return 0;
+}
+
+static struct hid_ll_driver uhid_hid_driver = {
+	.start = uhid_hid_start,
+	.stop = uhid_hid_stop,
+	.open = uhid_hid_open,
+	.close = uhid_hid_close,
+	.hidinput_input_event = uhid_hid_input,
+	.parse = uhid_hid_parse,
+};
+
+static int uhid_dev_create(struct uhid_device *uhid,
+			   const struct uhid_event *ev)
+{
+	struct hid_device *hid;
+	int ret;
+
+	if (uhid->running)
+		return -EALREADY;
+
+	uhid->rd_size = ev->u.create.rd_size;
+	if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
+		return -EINVAL;
+
+	uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+	if (!uhid->rd_data)
+		return -ENOMEM;
+
+	if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
+			   uhid->rd_size)) {
+		ret = -EFAULT;
+		goto err_free;
+	}
+
+	hid = hid_allocate_device();
+	if (IS_ERR(hid)) {
+		ret = PTR_ERR(hid);
+		goto err_free;
+	}
+
+	strncpy(hid->name, ev->u.create.name, 127);
+	hid->name[127] = 0;
+	strncpy(hid->phys, ev->u.create.phys, 63);
+	hid->phys[63] = 0;
+	strncpy(hid->uniq, ev->u.create.uniq, 63);
+	hid->uniq[63] = 0;
+
+	hid->ll_driver = &uhid_hid_driver;
+	hid->hid_get_raw_report = uhid_hid_get_raw;
+	hid->hid_output_raw_report = uhid_hid_output_raw;
+	hid->bus = ev->u.create.bus;
+	hid->vendor = ev->u.create.vendor;
+	hid->product = ev->u.create.product;
+	hid->version = ev->u.create.version;
+	hid->country = ev->u.create.country;
+	hid->driver_data = uhid;
+	hid->dev.parent = uhid_misc.this_device;
+
+	uhid->hid = hid;
+	uhid->running = true;
+
+	ret = hid_add_device(hid);
+	if (ret) {
+		hid_err(hid, "Cannot register HID device\n");
+		goto err_hid;
+	}
+
+	return 0;
+
+err_hid:
+	hid_destroy_device(hid);
+	uhid->hid = NULL;
+	uhid->running = false;
+err_free:
+	kfree(uhid->rd_data);
+	return ret;
+}
+
+static int uhid_dev_destroy(struct uhid_device *uhid)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	uhid->running = false;
+
+	hid_destroy_device(uhid->hid);
+	kfree(uhid->rd_data);
+
+	return 0;
+}
+
 static int uhid_char_open(struct inode *inode, struct file *file)
 {
 	struct uhid_device *uhid;
@@ -86,6 +221,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
 	mutex_init(&uhid->devlock);
 	spin_lock_init(&uhid->qlock);
 	init_waitqueue_head(&uhid->waitq);
+	uhid->running = false;
 
 	file->private_data = uhid;
 	nonseekable_open(inode, file);
@@ -98,6 +234,8 @@ static int uhid_char_release(struct inode *inode, struct file *file)
 	struct uhid_device *uhid = file->private_data;
 	unsigned int i;
 
+	uhid_dev_destroy(uhid);
+
 	for (i = 0; i < UHID_BUFSIZE; ++i)
 		kfree(uhid->outq[i]);
 
@@ -177,6 +315,12 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 	}
 
 	switch (uhid->input_buf.type) {
+	case UHID_CREATE:
+		ret = uhid_dev_create(uhid, &uhid->input_buf);
+		break;
+	case UHID_DESTROY:
+		ret = uhid_dev_destroy(uhid);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 16b786a..8a493e6 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -23,11 +23,30 @@
 #include <linux/types.h>
 
 enum uhid_event_type {
-	UHID_DUMMY,
+	UHID_CREATE,
+	UHID_DESTROY,
 };
 
+struct uhid_create_req {
+	__u8 name[128];
+	__u8 phys[64];
+	__u8 uniq[64];
+	__u8 __user *rd_data;
+	__u16 rd_size;
+
+	__u16 bus;
+	__u32 vendor;
+	__u32 product;
+	__u32 version;
+	__u32 country;
+} __attribute__((__packed__));
+
 struct uhid_event {
 	__u32 type;
+
+	union {
+		struct uhid_create_req create;
+	} u;
 } __attribute__((__packed__));
 
 #endif /* __UHID_H_ */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/16] HID: uhid: allow feeding input data into uhid devices
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (5 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 06/16] HID: uhid: add UHID_CREATE and UHID_DESTROY events David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 08/16] HID: uhid: forward hid report-descriptor to hid core David Herrmann
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

This adds a new event type UHID_INPUT which allows user-space to feed raw
HID reports into the HID subsystem. We copy the data into kernel memory
and directly feed it into the HID core.

There is no error handling of the events couldn't be parsed so user-space
should consider all events successfull unless read() returns an error.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |   14 ++++++++++++++
 include/linux/uhid.h |    9 +++++++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 61ee7cc..3d1ebda 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -210,6 +210,17 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
 	return 0;
 }
 
+static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
+{
+	if (!uhid->running)
+		return -EINVAL;
+
+	hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
+			 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
+
+	return 0;
+}
+
 static int uhid_char_open(struct inode *inode, struct file *file)
 {
 	struct uhid_device *uhid;
@@ -321,6 +332,9 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 	case UHID_DESTROY:
 		ret = uhid_dev_destroy(uhid);
 		break;
+	case UHID_INPUT:
+		ret = uhid_dev_input(uhid, &uhid->input_buf);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 8a493e6..6eb42be 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -25,6 +25,7 @@
 enum uhid_event_type {
 	UHID_CREATE,
 	UHID_DESTROY,
+	UHID_INPUT,
 };
 
 struct uhid_create_req {
@@ -41,11 +42,19 @@ struct uhid_create_req {
 	__u32 country;
 } __attribute__((__packed__));
 
+#define UHID_DATA_MAX 4096
+
+struct uhid_input_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+} __attribute__((__packed__));
+
 struct uhid_event {
 	__u32 type;
 
 	union {
 		struct uhid_create_req create;
+		struct uhid_input_req input;
 	} u;
 } __attribute__((__packed__));
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/16] HID: uhid: forward hid report-descriptor to hid core
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (6 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 07/16] HID: uhid: allow feeding input data into uhid devices David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 09/16] HID: uhid: add UHID_START and UHID_STOP events David Herrmann
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

When the uhid_hid_parse callback is called we simply forward it to
hid_parse_report() with the data that we got in the UHID_CREATE event.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 3d1ebda..0d011db 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -106,7 +106,9 @@ static int uhid_hid_input(struct input_dev *input, unsigned int type,
 
 static int uhid_hid_parse(struct hid_device *hid)
 {
-	return 0;
+	struct uhid_device *uhid = hid->driver_data;
+
+	return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
 }
 
 static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/16] HID: uhid: add UHID_START and UHID_STOP events
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (7 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 08/16] HID: uhid: forward hid report-descriptor to hid core David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 10/16] HID: uhid: forward open/close events to user-space David Herrmann
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

We send UHID_START and UHID_STOP events to user-space when the HID core
starts/stops the device. This notifies user-space about driver readiness
and data-I/O can start now.

This directly forwards the callbacks from hid-core to user-space.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |    8 +++++++-
 include/linux/uhid.h |    2 ++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 0d011db..2e7f3a0 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -82,11 +82,17 @@ static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
 
 static int uhid_hid_start(struct hid_device *hid)
 {
-	return 0;
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_START);
 }
 
 static void uhid_hid_stop(struct hid_device *hid)
 {
+	struct uhid_device *uhid = hid->driver_data;
+
+	hid->claimed = 0;
+	uhid_queue_event(uhid, UHID_STOP);
 }
 
 static int uhid_hid_open(struct hid_device *hid)
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 6eb42be..f8ce6f7 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -25,6 +25,8 @@
 enum uhid_event_type {
 	UHID_CREATE,
 	UHID_DESTROY,
+	UHID_START,
+	UHID_STOP,
 	UHID_INPUT,
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/16] HID: uhid: forward open/close events to user-space
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (8 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 09/16] HID: uhid: add UHID_START and UHID_STOP events David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 11/16] HID: uhid: forward output request " David Herrmann
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

HID core notifies us with *_open/*_close callbacks when there is an actual
user of our device. We forward these to user-space so they can react on
this. This allows user-space to skip I/O unless they receive an OPEN
event. When they receive a CLOSE event they can stop I/O again to save
energy.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |    7 ++++++-
 include/linux/uhid.h |    2 ++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 2e7f3a0..0226ba3f 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -97,11 +97,16 @@ static void uhid_hid_stop(struct hid_device *hid)
 
 static int uhid_hid_open(struct hid_device *hid)
 {
-	return 0;
+	struct uhid_device *uhid = hid->driver_data;
+
+	return uhid_queue_event(uhid, UHID_OPEN);
 }
 
 static void uhid_hid_close(struct hid_device *hid)
 {
+	struct uhid_device *uhid = hid->driver_data;
+
+	uhid_queue_event(uhid, UHID_CLOSE);
 }
 
 static int uhid_hid_input(struct input_dev *input, unsigned int type,
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index f8ce6f7..351650b 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -27,6 +27,8 @@ enum uhid_event_type {
 	UHID_DESTROY,
 	UHID_START,
 	UHID_STOP,
+	UHID_OPEN,
+	UHID_CLOSE,
 	UHID_INPUT,
 };
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/16] HID: uhid: forward output request to user-space
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (9 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 10/16] HID: uhid: forward open/close events to user-space David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 12/16] HID: uhid: forward raw output reports " David Herrmann
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

If the hid-driver wants to send standardized data to the device it uses a
linux input_event. We forward this to the user-space transport-level
driver so they can perform the requested action on the device.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |   18 ++++++++++++++++++
 include/linux/uhid.h |    8 ++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 0226ba3f..4dd693e 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -112,6 +112,24 @@ static void uhid_hid_close(struct hid_device *hid)
 static int uhid_hid_input(struct input_dev *input, unsigned int type,
 			  unsigned int code, int value)
 {
+	struct hid_device *hid = input_get_drvdata(input);
+	struct uhid_device *uhid = hid->driver_data;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT_EV;
+	ev->u.output_ev.type = type;
+	ev->u.output_ev.code = code;
+	ev->u.output_ev.value = value;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
 	return 0;
 }
 
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 351650b..3fa4849 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -29,6 +29,7 @@ enum uhid_event_type {
 	UHID_STOP,
 	UHID_OPEN,
 	UHID_CLOSE,
+	UHID_OUTPUT_EV,
 	UHID_INPUT,
 };
 
@@ -53,12 +54,19 @@ struct uhid_input_req {
 	__u16 size;
 } __attribute__((__packed__));
 
+struct uhid_output_ev_req {
+	__u16 type;
+	__u16 code;
+	__s32 value;
+} __attribute__((__packed__));
+
 struct uhid_event {
 	__u32 type;
 
 	union {
 		struct uhid_create_req create;
 		struct uhid_input_req input;
+		struct uhid_output_ev_req output_ev;
 	} u;
 } __attribute__((__packed__));
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/16] HID: uhid: forward raw output reports to user-space
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (10 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 11/16] HID: uhid: forward output request " David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 13/16] HID: uhid: implement feature requests David Herrmann
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

Some drivers that use non-standard HID features require raw output reports
sent to the device. We now forward these requests directly to user-space
so the transport-level driver can correctly send it to the device or
handle it correspondingly.

There is no way to signal back whether the transmission was successful,
moreover, there might be lots of messages coming out from the driver
flushing the output-queue. However, there is currently no driver that
causes this so we are safe. If some drivers need to transmit lots of data
this way, we need a method to synchronize this and can implement another
UHID_OUTPUT_SYNC event.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |   34 +++++++++++++++++++++++++++++++++-
 include/linux/uhid.h |   14 ++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 4dd693e..421c492 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -149,7 +149,39 @@ static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
 static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
 			       unsigned char report_type)
 {
-	return 0;
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 rtype;
+	unsigned long flags;
+	struct uhid_event *ev;
+
+	switch (report_type) {
+	case HID_FEATURE_REPORT:
+		rtype = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		rtype = UHID_OUTPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (count < 1 || count > UHID_DATA_MAX)
+		return -EINVAL;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->type = UHID_OUTPUT;
+	ev->u.output.size = count;
+	ev->u.output.rtype = rtype;
+	memcpy(ev->u.output.data, buf, count);
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	return count;
 }
 
 static struct hid_ll_driver uhid_hid_driver = {
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 3fa4849..2c97255 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -29,6 +29,7 @@ enum uhid_event_type {
 	UHID_STOP,
 	UHID_OPEN,
 	UHID_CLOSE,
+	UHID_OUTPUT,
 	UHID_OUTPUT_EV,
 	UHID_INPUT,
 };
@@ -49,11 +50,23 @@ struct uhid_create_req {
 
 #define UHID_DATA_MAX 4096
 
+enum uhid_report_type {
+	UHID_FEATURE_REPORT,
+	UHID_OUTPUT_REPORT,
+	UHID_INPUT_REPORT,
+};
+
 struct uhid_input_req {
 	__u8 data[UHID_DATA_MAX];
 	__u16 size;
 } __attribute__((__packed__));
 
+struct uhid_output_req {
+	__u8 data[UHID_DATA_MAX];
+	__u16 size;
+	__u8 rtype;
+} __attribute__((__packed__));
+
 struct uhid_output_ev_req {
 	__u16 type;
 	__u16 code;
@@ -66,6 +79,7 @@ struct uhid_event {
 	union {
 		struct uhid_create_req create;
 		struct uhid_input_req input;
+		struct uhid_output_req output;
 		struct uhid_output_ev_req output_ev;
 	} u;
 } __attribute__((__packed__));
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/16] HID: uhid: implement feature requests
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (11 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 12/16] HID: uhid: forward raw output reports " David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 14/16] HID: uhid: add documentation David Herrmann
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

HID standard allows sending a feature request to the device which is
answered by an HID report. uhid implements this by sending a UHID_FEATURE
event to user-space which then must answer with UHID_FEATURE_ANSWER. If it
doesn't do this in a timely manner, the request is discarded silently.

We serialize the feature requests, that is, there is always only a single
active feature-request sent to user-space, other requests have to wait.
HIDP and USB-HID do it the same way.

Because we discard feature-requests silently, we must make sure to match
a response to the corresponding request. We use sequence-IDs for this so
user-space must copy the ID from the request into the answer.
Feature-answers are ignored if they do not contain the same ID as the
currently pending feature request.

Internally, we must make sure that feature-requests are synchronized with
UHID_DESTROY and close() events. We must not dead-lock when closing the
HID device, either, so we have to use separate locks.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 drivers/hid/uhid.c   |  120 +++++++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/uhid.h |   17 +++++++
 2 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 421c492..ea560bf 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -42,6 +42,12 @@ struct uhid_device {
 	__u8 head;
 	__u8 tail;
 	struct uhid_event *outq[UHID_BUFSIZE];
+
+	struct mutex report_lock;
+	wait_queue_head_t report_wait;
+	atomic_t report_done;
+	atomic_t report_id;
+	struct uhid_event report_buf;
 };
 
 static struct miscdevice uhid_misc;
@@ -143,7 +149,84 @@ static int uhid_hid_parse(struct hid_device *hid)
 static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
 			    __u8 *buf, size_t count, unsigned char rtype)
 {
-	return 0;
+	struct uhid_device *uhid = hid->driver_data;
+	__u8 report_type;
+	struct uhid_event *ev;
+	unsigned long flags;
+	int ret;
+	size_t len;
+	struct uhid_feature_answer_req *req;
+
+	if (!uhid->running)
+		return -EIO;
+
+	switch (rtype) {
+	case HID_FEATURE_REPORT:
+		report_type = UHID_FEATURE_REPORT;
+		break;
+	case HID_OUTPUT_REPORT:
+		report_type = UHID_OUTPUT_REPORT;
+		break;
+	case HID_INPUT_REPORT:
+		report_type = UHID_INPUT_REPORT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&uhid->report_lock);
+	if (ret)
+		return ret;
+
+	ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+	ev->type = UHID_FEATURE;
+	ev->u.feature.id = atomic_inc_return(&uhid->report_id);
+	ev->u.feature.rnum = rnum;
+	ev->u.feature.rtype = report_type;
+
+	atomic_set(&uhid->report_done, 0);
+	uhid_queue(uhid, ev);
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+
+	ret = wait_event_interruptible_timeout(uhid->report_wait,
+				atomic_read(&uhid->report_done), 5 * HZ);
+
+	/*
+	 * Make sure "uhid->running" is cleared on shutdown before
+	 * "uhid->report_done" is set.
+	 */
+	smp_rmb();
+	if (!ret || !uhid->running) {
+		ret = -EIO;
+	} else if (ret < 0) {
+		ret = -ERESTARTSYS;
+	} else {
+		spin_lock_irqsave(&uhid->qlock, flags);
+		req = &uhid->report_buf.u.feature_answer;
+
+		if (req->err) {
+			ret = -EIO;
+		} else {
+			ret = 0;
+			len = min(count,
+				min_t(size_t, req->size, UHID_DATA_MAX));
+			memcpy(buf, req->data, len);
+		}
+
+		spin_unlock_irqrestore(&uhid->qlock, flags);
+	}
+
+	atomic_set(&uhid->report_done, 1);
+
+unlock:
+	mutex_unlock(&uhid->report_lock);
+	return ret ? ret : len;
 }
 
 static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
@@ -265,7 +348,11 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
 	if (!uhid->running)
 		return -EINVAL;
 
+	/* clear "running" before setting "report_done" */
 	uhid->running = false;
+	smp_wmb();
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
 
 	hid_destroy_device(uhid->hid);
 	kfree(uhid->rd_data);
@@ -284,6 +371,31 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
 	return 0;
 }
 
+static int uhid_dev_feature_answer(struct uhid_device *uhid,
+				   struct uhid_event *ev)
+{
+	unsigned long flags;
+
+	if (!uhid->running)
+		return -EINVAL;
+
+	spin_lock_irqsave(&uhid->qlock, flags);
+
+	/* id for old report; drop it silently */
+	if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
+		goto unlock;
+	if (atomic_read(&uhid->report_done))
+		goto unlock;
+
+	memcpy(&uhid->report_buf, ev, sizeof(*ev));
+	atomic_set(&uhid->report_done, 1);
+	wake_up_interruptible(&uhid->report_wait);
+
+unlock:
+	spin_unlock_irqrestore(&uhid->qlock, flags);
+	return 0;
+}
+
 static int uhid_char_open(struct inode *inode, struct file *file)
 {
 	struct uhid_device *uhid;
@@ -293,9 +405,12 @@ static int uhid_char_open(struct inode *inode, struct file *file)
 		return -ENOMEM;
 
 	mutex_init(&uhid->devlock);
+	mutex_init(&uhid->report_lock);
 	spin_lock_init(&uhid->qlock);
 	init_waitqueue_head(&uhid->waitq);
+	init_waitqueue_head(&uhid->report_wait);
 	uhid->running = false;
+	atomic_set(&uhid->report_done, 1);
 
 	file->private_data = uhid;
 	nonseekable_open(inode, file);
@@ -398,6 +513,9 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
 	case UHID_INPUT:
 		ret = uhid_dev_input(uhid, &uhid->input_buf);
 		break;
+	case UHID_FEATURE_ANSWER:
+		ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
diff --git a/include/linux/uhid.h b/include/linux/uhid.h
index 2c97255..9c6974f 100644
--- a/include/linux/uhid.h
+++ b/include/linux/uhid.h
@@ -32,6 +32,8 @@ enum uhid_event_type {
 	UHID_OUTPUT,
 	UHID_OUTPUT_EV,
 	UHID_INPUT,
+	UHID_FEATURE,
+	UHID_FEATURE_ANSWER,
 };
 
 struct uhid_create_req {
@@ -73,6 +75,19 @@ struct uhid_output_ev_req {
 	__s32 value;
 } __attribute__((__packed__));
 
+struct uhid_feature_req {
+	__u32 id;
+	__u8 rnum;
+	__u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_feature_answer_req {
+	__u32 id;
+	__u16 err;
+	__u16 size;
+	__u8 data[UHID_DATA_MAX];
+};
+
 struct uhid_event {
 	__u32 type;
 
@@ -81,6 +96,8 @@ struct uhid_event {
 		struct uhid_input_req input;
 		struct uhid_output_req output;
 		struct uhid_output_ev_req output_ev;
+		struct uhid_feature_req feature;
+		struct uhid_feature_answer_req feature_answer;
 	} u;
 } __attribute__((__packed__));
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/16] HID: uhid: add documentation
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (12 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 13/16] HID: uhid: implement feature requests David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 15/16] HID: uhid: add example program David Herrmann
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

This describes the protocol used by uhid for user-space applications. It
describes the details like non-blocking I/O and readv/writev for multiple
events per syscall.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 Documentation/hid/uhid.txt |  169 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 169 insertions(+)
 create mode 100644 Documentation/hid/uhid.txt

diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
new file mode 100644
index 0000000..4627c42
--- /dev/null
+++ b/Documentation/hid/uhid.txt
@@ -0,0 +1,169 @@
+      UHID - User-space I/O driver support for HID subsystem
+     ========================================================
+
+The HID subsystem needs two kinds of drivers. In this document we call them:
+
+ 1. The "HID I/O Driver" is the driver that performs raw data I/O to the
+    low-level device. Internally, they register an hid_ll_driver structure with
+    the HID core. They perform device setup, read raw data from the device and
+    push it into the HID subsystem and they provide a callback so the HID
+    subsystem can send data to the device.
+
+ 2. The "HID Device Driver" is the driver that parses HID reports and reacts on
+    them. There are generic drivers like "generic-usb" and "generic-bluetooth"
+    which adhere to the HID specification and provide the standardizes features.
+    But there may be special drivers and quirks for each non-standard device out
+    there. Internally, they use the hid_driver structure.
+
+Historically, the USB stack was the first subsystem to provide an HID I/O
+Driver. However, other standards like Bluetooth have adopted the HID specs and
+may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O
+Drivers in user-space and feed the data into the kernel HID-subsystem.
+
+This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
+and similar. It does not provide a way to write HID Device Drivers, though. Use
+hidraw for this purpose.
+
+There is an example user-space application in ./samples/uhid/uhid-example.c
+
+The UHID API
+------------
+
+UHID is accessed through a character misc-device. The minor-number is allocated
+dynamically so you need to rely on udev (or similar) to create the device node.
+This is /dev/uhid by default.
+
+If a new device is detected by your HID I/O Driver and you want to register this
+device with the HID subsystem, then you need to open /dev/uhid once for each
+device you want to register. All further communication is done by read()'ing or
+write()'ing "struct uhid_event" objects. Non-blocking operations are supported
+by setting O_NONBLOCK.
+
+struct uhid_event {
+        __u32 type;
+        union {
+                struct uhid_create_req create;
+                struct uhid_data_req data;
+                ...
+        } u;
+};
+
+The "type" field contains the ID of the event. Depending on the ID different
+payloads are sent. You must not split a single event across multiple read()'s or
+multiple write()'s. A single event must always be sent as a whole. Furthermore,
+only a single event can be sent per read() or write(). Pending data is ignored.
+If you want to handle multiple events in a single syscall, then use vectored
+I/O with readv()/writev().
+
+The first thing you should do is sending an UHID_CREATE event. This will
+register the device. UHID will respond with an UHID_START event. You can now
+start sending data to and reading data from UHID. However, unless UHID sends the
+UHID_OPEN event, the internally attached HID Device Driver has no user attached.
+That is, you might put your device asleep unless you receive the UHID_OPEN
+event. If you receive the UHID_OPEN event, you should start I/O. If the last
+user closes the HID device, you will receive an UHID_CLOSE event. This may be
+followed by an UHID_OPEN event again and so on. There is no need to perform
+reference-counting in user-space. That is, you will never receive multiple
+UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
+ref-counting for you.
+You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
+though the device may have no users.
+
+If you want to send data to the HID subsystem, you send an HID_INPUT event with
+your raw data payload. If the kernel wants to send data to the device, you will
+read an UHID_OUTPUT or UHID_OUTPUT_EV event.
+
+If your device disconnects, you should send an UHID_DESTROY event. This will
+unregister the device. You can now send UHID_CREATE again to register a new
+device.
+If you close() the fd, the device is automatically unregistered and destroyed
+internally.
+
+write()
+-------
+write() allows you to modify the state of the device and feed input data into
+the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
+UHID_INPUT. The kernel will parse the event immediately and if the event ID is
+not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
+-EINVAL is returned, otherwise, the amount of data that was read is returned and
+the request was handled successfully.
+
+  UHID_CREATE:
+  This creates the internal HID device. No I/O is possible until you send this
+  event to the kernel. The payload is of type struct uhid_create_req and
+  contains information about your device. You can start I/O now.
+
+  UHID_DESTROY:
+  This destroys the internal HID device. No further I/O will be accepted. There
+  may still be pending messages that you can receive with read() but no further
+  UHID_INPUT events can be sent to the kernel.
+  You can create a new device by sending UHID_CREATE again. There is no need to
+  reopen the character device.
+
+  UHID_INPUT:
+  You must send UHID_CREATE before sending input to the kernel! This event
+  contains a data-payload. This is the raw data that you read from your device.
+  The kernel will parse the HID reports and react on it.
+
+  UHID_FEATURE_ANSWER:
+  If you receive a UHID_FEATURE request you must answer with this request. You
+  must copy the "id" field from the request into the answer. Set the "err" field
+  to 0 if no error occured or to EIO if an I/O error occurred.
+  If "err" is 0 then you should fill the buffer of the answer with the results
+  of the feature request and set "size" correspondingly.
+
+read()
+------
+read() will return a queued ouput report. These output reports can be of type
+UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
+reaction is required to any of them but you should handle them according to your
+needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
+
+  UHID_START:
+  This is sent when the HID device is started. Consider this as an answer to
+  UHID_CREATE. This is always the first event that is sent.
+
+  UHID_STOP:
+  This is sent when the HID device is stopped. Consider this as an answer to
+  UHID_DESTROY.
+  If the kernel HID device driver closes the device manually (that is, you
+  didn't send UHID_DESTROY) then you should consider this device closed and send
+  an UHID_DESTROY event. You may want to reregister your device, though. This is
+  always the last message that is sent to you unless you reopen the device with
+  UHID_CREATE.
+
+  UHID_OPEN:
+  This is sent when the HID device is opened. That is, the data that the HID
+  device provides is read by some other process. You may ignore this event but
+  it is useful for power-management. As long as you haven't received this event
+  there is actually no other process that reads your data so there is no need to
+  send UHID_INPUT events to the kernel.
+
+  UHID_CLOSE:
+  This is sent when there are no more processes which read the HID data. It is
+  the counterpart of UHID_OPEN and you may as well ignore this event.
+
+  UHID_OUTPUT:
+  This is sent if the HID device driver wants to send raw data to the I/O
+  device. You should read the payload and forward it to the device. The payload
+  is of type "struct uhid_data_req".
+  This may be received even though you haven't received UHID_OPEN, yet.
+
+  UHID_OUTPUT_EV:
+  Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
+  is called for force-feedback, LED or similar events which are received through
+  an input device by the HID subsystem. You should convert this into raw reports
+  and send them to your device similar to events of type UHID_OUTPUT.
+
+  UHID_FEATURE:
+  This event is sent if the kernel driver wants to perform a feature request as
+  described in the HID specs. The report-type and report-number are available in
+  the payload.
+  The kernel serializes feature requests so there will never be two in parallel.
+  However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5
+  seconds, then the requests will be dropped and a new one might be sent.
+  Therefore, the payload also contains an "id" field that identifies every
+  request.
+
+Document by:
+  David Herrmann <dh.herrmann@googlemail.com>
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/16] HID: uhid: add example program
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (13 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 14/16] HID: uhid: add documentation David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-10 13:16 ` [PATCH 16/16] MAINTAINERS: add UHID entry David Herrmann
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

This adds an example user-space program that emulates a 3 button mouse
with wheel. It detects keyboard presses and moves the mouse accordingly.

It register a fake HID device to feed the raw HID reports into the kernel.
In this example, you could use uinput to get the same result, but this
shows how to get the same behavior with uhid so you don't need HID parsers
in user-space.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
When testing this make sure to include the uhid.h header. It is safe to compile
it with the un-installed headers with -I./include/linux

 samples/uhid/Makefile       |   10 ++
 samples/uhid/uhid-example.c |  381 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 391 insertions(+)
 create mode 100644 samples/uhid/Makefile
 create mode 100644 samples/uhid/uhid-example.c

diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile
new file mode 100644
index 0000000..c95a696
--- /dev/null
+++ b/samples/uhid/Makefile
@@ -0,0 +1,10 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := uhid-example
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c
new file mode 100644
index 0000000..03ce3c0
--- /dev/null
+++ b/samples/uhid/uhid-example.c
@@ -0,0 +1,381 @@
+/*
+ * UHID Example
+ *
+ * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
+ *
+ * The code may be used by anyone for any purpose,
+ * and can serve as a starting point for developing
+ * applications using uhid.
+ */
+
+/* UHID Example
+ * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
+ * program as root and then use the following keys to control the mouse:
+ *   q: Quit the application
+ *   1: Toggle left button (down, up, ...)
+ *   2: Toggle right button
+ *   3: Toggle middle button
+ *   a: Move mouse left
+ *   d: Move mouse right
+ *   w: Move mouse up
+ *   s: Move mouse down
+ *   r: Move wheel up
+ *   f: Move wheel down
+ *
+ * If uhid is not available as /dev/uhid, then you can pass a different path as
+ * first argument.
+ * If <linux/uhid.h> is not installed in /usr, then compile this with:
+ *   gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
+ * And ignore the warning about kernel headers. However, it is recommended to
+ * use the installed uhid.h if available.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <linux/uhid.h>
+
+/* HID Report Desciptor
+ * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
+ * as the kernel will parse it:
+ *
+ * INPUT[INPUT]
+ *   Field(0)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       Button.0001
+ *       Button.0002
+ *       Button.0003
+ *     Logical Minimum(0)
+ *     Logical Maximum(1)
+ *     Report Size(1)
+ *     Report Count(3)
+ *     Report Offset(0)
+ *     Flags( Variable Absolute )
+ *   Field(1)
+ *     Physical(GenericDesktop.Pointer)
+ *     Application(GenericDesktop.Mouse)
+ *     Usage(3)
+ *       GenericDesktop.X
+ *       GenericDesktop.Y
+ *       GenericDesktop.Wheel
+ *     Logical Minimum(-128)
+ *     Logical Maximum(127)
+ *     Report Size(8)
+ *     Report Count(3)
+ *     Report Offset(8)
+ *     Flags( Variable Relative )
+ *
+ * This is the mapping that we expect:
+ *   Button.0001 ---> Key.LeftBtn
+ *   Button.0002 ---> Key.RightBtn
+ *   Button.0003 ---> Key.MiddleBtn
+ *   GenericDesktop.X ---> Relative.X
+ *   GenericDesktop.Y ---> Relative.Y
+ *   GenericDesktop.Wheel ---> Relative.Wheel
+ *
+ * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
+ * This file should print the same information as showed above.
+ */
+
+static unsigned char rdesc[] = {
+	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
+	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+	0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+	0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
+	0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
+	0x81, 0x06, 0xc0, 0xc0,
+};
+
+static int uhid_write(int fd, const struct uhid_event *ev)
+{
+	ssize_t ret;
+
+	ret = write(fd, ev, sizeof(*ev));
+	if (ret < 0) {
+		fprintf(stderr, "Cannot write to uhid: %m\n");
+		return -errno;
+	} else if (ret != sizeof(*ev)) {
+		fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	} else {
+		return 0;
+	}
+}
+
+static int create(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_CREATE;
+	strcpy((char*)ev.u.create.name, "test-uhid-device");
+	ev.u.create.rd_data = rdesc;
+	ev.u.create.rd_size = sizeof(rdesc);
+	ev.u.create.bus = BUS_USB;
+	ev.u.create.vendor = 0x15d9;
+	ev.u.create.product = 0x0a37;
+	ev.u.create.version = 0;
+	ev.u.create.country = 0;
+
+	return uhid_write(fd, &ev);
+}
+
+static void destroy(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_DESTROY;
+
+	uhid_write(fd, &ev);
+}
+
+static int event(int fd)
+{
+	struct uhid_event ev;
+	ssize_t ret;
+
+	memset(&ev, 0, sizeof(ev));
+	ret = read(fd, &ev, sizeof(ev));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on uhid-cdev\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read uhid-cdev: %m\n");
+		return -errno;
+	} else if (ret != sizeof(ev)) {
+		fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
+			ret, sizeof(ev));
+		return -EFAULT;
+	}
+
+	switch (ev.type) {
+	case UHID_START:
+		fprintf(stderr, "UHID_START from uhid-dev\n");
+		break;
+	case UHID_STOP:
+		fprintf(stderr, "UHID_STOP from uhid-dev\n");
+		break;
+	case UHID_OPEN:
+		fprintf(stderr, "UHID_OPEN from uhid-dev\n");
+		break;
+	case UHID_CLOSE:
+		fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
+		break;
+	case UHID_OUTPUT:
+		fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
+		break;
+	case UHID_OUTPUT_EV:
+		fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
+		break;
+	default:
+		fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
+	}
+
+	return 0;
+}
+
+static bool btn1_down;
+static bool btn2_down;
+static bool btn3_down;
+static signed char abs_hor;
+static signed char abs_ver;
+static signed char wheel;
+
+static int send_event(int fd)
+{
+	struct uhid_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.type = UHID_INPUT;
+	ev.u.input.size = 4;
+
+	if (btn1_down)
+		ev.u.input.data[0] |= 0x1;
+	if (btn2_down)
+		ev.u.input.data[0] |= 0x2;
+	if (btn3_down)
+		ev.u.input.data[0] |= 0x4;
+
+	ev.u.input.data[1] = abs_hor;
+	ev.u.input.data[2] = abs_ver;
+	ev.u.input.data[3] = wheel;
+
+	return uhid_write(fd, &ev);
+}
+
+static int keyboard(int fd)
+{
+	char buf[128];
+	ssize_t ret, i;
+
+	ret = read(STDIN_FILENO, buf, sizeof(buf));
+	if (ret == 0) {
+		fprintf(stderr, "Read HUP on stdin\n");
+		return -EFAULT;
+	} else if (ret < 0) {
+		fprintf(stderr, "Cannot read stdin: %m\n");
+		return -errno;
+	}
+
+	for (i = 0; i < ret; ++i) {
+		switch (buf[i]) {
+		case '1':
+			btn1_down = !btn1_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '2':
+			btn2_down = !btn2_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case '3':
+			btn3_down = !btn3_down;
+			ret = send_event(fd);
+			if (ret)
+				return ret;
+			break;
+		case 'a':
+			abs_hor = -20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'd':
+			abs_hor = 20;
+			ret = send_event(fd);
+			abs_hor = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'w':
+			abs_ver = -20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 's':
+			abs_ver = 20;
+			ret = send_event(fd);
+			abs_ver = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'r':
+			wheel = 1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'f':
+			wheel = -1;
+			ret = send_event(fd);
+			wheel = 0;
+			if (ret)
+				return ret;
+			break;
+		case 'q':
+			return -ECANCELED;
+		default:
+			fprintf(stderr, "Invalid input: %c\n", buf[i]);
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int fd;
+	const char *path = "/dev/uhid";
+	struct pollfd pfds[2];
+	int ret;
+	struct termios state;
+
+	ret = tcgetattr(STDIN_FILENO, &state);
+	if (ret) {
+		fprintf(stderr, "Cannot get tty state\n");
+	} else {
+		state.c_lflag &= ~ICANON;
+		state.c_cc[VMIN] = 1;
+		ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
+		if (ret)
+			fprintf(stderr, "Cannot set tty state\n");
+	}
+
+	if (argc >= 2) {
+		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+			fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
+			return EXIT_SUCCESS;
+		} else {
+			path = argv[1];
+		}
+	}
+
+	fprintf(stderr, "Open uhid-cdev %s\n", path);
+	fd = open(path, O_RDWR | O_CLOEXEC);
+	if (fd < 0) {
+		fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
+		return EXIT_FAILURE;
+	}
+
+	fprintf(stderr, "Create uhid device\n");
+	ret = create(fd);
+	if (ret) {
+		close(fd);
+		return EXIT_FAILURE;
+	}
+
+	pfds[0].fd = STDIN_FILENO;
+	pfds[0].events = POLLIN;
+	pfds[1].fd = fd;
+	pfds[1].events = POLLIN;
+
+	fprintf(stderr, "Press 'q' to quit...\n");
+	while (1) {
+		ret = poll(pfds, 2, -1);
+		if (ret < 0) {
+			fprintf(stderr, "Cannot poll for fds: %m\n");
+			break;
+		}
+		if (pfds[0].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on stdin\n");
+			break;
+		}
+		if (pfds[1].revents & POLLHUP) {
+			fprintf(stderr, "Received HUP on uhid-cdev\n");
+			break;
+		}
+
+		if (pfds[0].revents & POLLIN) {
+			ret = keyboard(fd);
+			if (ret)
+				break;
+		}
+		if (pfds[1].revents & POLLIN) {
+			ret = event(fd);
+			if (ret)
+				break;
+		}
+	}
+
+	fprintf(stderr, "Destroy uhid device\n");
+	destroy(fd);
+	return EXIT_SUCCESS;
+}
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/16] MAINTAINERS: add UHID entry
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (14 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 15/16] HID: uhid: add example program David Herrmann
@ 2012-06-10 13:16 ` David Herrmann
  2012-06-11 14:46 ` [PATCH 00/16] HID: uhid: User-space HID I/O driver Joao Paulo Rechi Vita
  2012-06-18 11:46 ` Jiri Kosina
  17 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-10 13:16 UTC (permalink / raw)
  To: linux-input; +Cc: jkosina, David Herrmann

Add an UHID entry to the MAINTAINERS file.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
 MAINTAINERS |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aa067a9..4997519 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6886,6 +6886,13 @@ S:	Maintained
 F:	Documentation/filesystems/ufs.txt
 F:	fs/ufs/
 
+UHID USERSPACE HID IO DRIVER:
+M:	David Herrmann <dh.herrmann@googlemail.com>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/uhid.c
+F:	include/linux/uhid.h
+
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 L:	linux-usb@vger.kernel.org
 S:	Orphan
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (15 preceding siblings ...)
  2012-06-10 13:16 ` [PATCH 16/16] MAINTAINERS: add UHID entry David Herrmann
@ 2012-06-11 14:46 ` Joao Paulo Rechi Vita
  2012-06-11 17:56   ` David Herrmann
  2012-06-18 11:46 ` Jiri Kosina
  17 siblings, 1 reply; 25+ messages in thread
From: Joao Paulo Rechi Vita @ 2012-06-11 14:46 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, jkosina

On Sun, Jun 10, 2012 at 10:16 AM, David Herrmann
<dh.herrmann@googlemail.com> wrote:
> This adds a new low-level HID driver that allows user-space to implement the
> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
> There is already an implementation of HOGP, see the
> linux-bluetooth@vger.kernel.org mailing list for this.
>
> I've split this into multiple patches to make review easier. This patchset is
> already working for several months for the HOGP developers but there may still
> be some issues with it. Please review.
>
> The uhid_*() functions implement the basic module functionality. The
> uhid_char_*() functions handle character-device related functionality. The
> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
> functions are HID-callbacks.
>
> I am open for any suggestions.
>

Hello David,

I've noticed one regression from the patch you've sent without Feature
Reports support to the one with Feature Reports support (which was the
previous patch, before the split) with the events coming from the char
device. The event_type values we're all coming out of its enum type
range. Have you tested this lately, with this new patch? I'll apply
and test it right now.

-- 
João Paulo Rechi Vita
Openbossa Labs - INdT
--
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	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-06-11 14:46 ` [PATCH 00/16] HID: uhid: User-space HID I/O driver Joao Paulo Rechi Vita
@ 2012-06-11 17:56   ` David Herrmann
       [not found]     ` <CAAngNMa3GMqrgZUrx=XqaRWfK2MaFMewK6OEQU_=4oPj1FOMNw@mail.gmail.com>
  0 siblings, 1 reply; 25+ messages in thread
From: David Herrmann @ 2012-06-11 17:56 UTC (permalink / raw)
  To: Joao Paulo Rechi Vita; +Cc: linux-input, jkosina

Hi Joao

On Mon, Jun 11, 2012 at 4:46 PM, Joao Paulo Rechi Vita
<jprvita@openbossa.org> wrote:
> On Sun, Jun 10, 2012 at 10:16 AM, David Herrmann
> <dh.herrmann@googlemail.com> wrote:
>> This adds a new low-level HID driver that allows user-space to implement the
>> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
>> There is already an implementation of HOGP, see the
>> linux-bluetooth@vger.kernel.org mailing list for this.
>>
>> I've split this into multiple patches to make review easier. This patchset is
>> already working for several months for the HOGP developers but there may still
>> be some issues with it. Please review.
>>
>> The uhid_*() functions implement the basic module functionality. The
>> uhid_char_*() functions handle character-device related functionality. The
>> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
>> functions are HID-callbacks.
>>
>> I am open for any suggestions.
>>
>
> Hello David,
>
> I've noticed one regression from the patch you've sent without Feature
> Reports support to the one with Feature Reports support (which was the
> previous patch, before the split) with the events coming from the char
> device. The event_type values we're all coming out of its enum type
> range. Have you tested this lately, with this new patch? I'll apply
> and test it right now.

I don't understand. What do you mean with "are all coming out of its
enum type range"? Are the type values incorrect and not the ones
defined in uhid.h?

> --
> João Paulo Rechi Vita
> Openbossa Labs - INdT

Thanks for testing
David
--
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	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
       [not found]     ` <CAAngNMa3GMqrgZUrx=XqaRWfK2MaFMewK6OEQU_=4oPj1FOMNw@mail.gmail.com>
@ 2012-06-14 22:05       ` Joao Paulo Rechi Vita
  2012-06-16 12:44         ` David Herrmann
  0 siblings, 1 reply; 25+ messages in thread
From: Joao Paulo Rechi Vita @ 2012-06-14 22:05 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input, Jiri Kosina

On Mon, Jun 11, 2012 at 11:40 PM, Joao Paulo Rechi Vita
<jprvita@openbossa.org> wrote:
> On Mon, Jun 11, 2012 at 2:56 PM, David Herrmann
> <dh.herrmann@googlemail.com> wrote:
>> Hi Joao
>>
>> On Mon, Jun 11, 2012 at 4:46 PM, Joao Paulo Rechi Vita
>> <jprvita@openbossa.org> wrote:
>>> On Sun, Jun 10, 2012 at 10:16 AM, David Herrmann
>>> <dh.herrmann@googlemail.com> wrote:
>>>> This adds a new low-level HID driver that allows user-space to implement the
>>>> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
>>>> There is already an implementation of HOGP, see the
>>>> linux-bluetooth@vger.kernel.org mailing list for this.
>>>>
>>>> I've split this into multiple patches to make review easier. This patchset is
>>>> already working for several months for the HOGP developers but there may still
>>>> be some issues with it. Please review.
>>>>
>>>> The uhid_*() functions implement the basic module functionality. The
>>>> uhid_char_*() functions handle character-device related functionality. The
>>>> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
>>>> functions are HID-callbacks.
>>>>
>>>> I am open for any suggestions.
>>>>
>>>
>>> Hello David,
>>>
>>> I've noticed one regression from the patch you've sent without Feature
>>> Reports support to the one with Feature Reports support (which was the
>>> previous patch, before the split) with the events coming from the char
>>> device. The event_type values we're all coming out of its enum type
>>> range. Have you tested this lately, with this new patch? I'll apply
>>> and test it right now.
>>
>> I don't understand. What do you mean with "are all coming out of its
>> enum type range"? Are the type values incorrect and not the ones
>> defined in uhid.h?
>>
>
> Exactly, the "event_type" field if of type "enum uhid_event_type",
> which ranges from 0 to 10. The values coming from the char device are
> numbers with around 10-12 digits.
>

(sorry, I forgot to cc the list on the original response)

I've tested this new version split in several patches. Input reports
support works fine, but the event_type value is still broken. This is
a minor issue IMO, since it just affects output and feature reports
support, which is not completed implemented in the userspace side of
HoG yet. I don't see a problem in having the series integrated
upstream and we fix this problem later on.

-- 
João Paulo Rechi Vita
Openbossa Labs - INdT
--
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	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-06-14 22:05       ` Joao Paulo Rechi Vita
@ 2012-06-16 12:44         ` David Herrmann
  0 siblings, 0 replies; 25+ messages in thread
From: David Herrmann @ 2012-06-16 12:44 UTC (permalink / raw)
  To: Joao Paulo Rechi Vita; +Cc: linux-input, Jiri Kosina

Hi Joao

On Fri, Jun 15, 2012 at 12:05 AM, Joao Paulo Rechi Vita
<jprvita@openbossa.org> wrote:
> On Mon, Jun 11, 2012 at 11:40 PM, Joao Paulo Rechi Vita
> (sorry, I forgot to cc the list on the original response)
>
> I've tested this new version split in several patches. Input reports
> support works fine, but the event_type value is still broken. This is
> a minor issue IMO, since it just affects output and feature reports
> support, which is not completed implemented in the userspace side of
> HoG yet. I don't see a problem in having the series integrated
> upstream and we fix this problem later on.

I tested the full patchset again to be sure and it works fine here.
Can you describe your problem in more detail? You applied the full
patchset, right? And all the events work except the FEATURE request?
What isn't working exactly here? Do you never receive the feature
request? What does the "type" field say exactly? What do you expect it
to report? Please describe the whole test-case you run as I cannot
follow.

Regards
David

> --
> João Paulo Rechi Vita
> Openbossa Labs - INdT
--
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	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
                   ` (16 preceding siblings ...)
  2012-06-11 14:46 ` [PATCH 00/16] HID: uhid: User-space HID I/O driver Joao Paulo Rechi Vita
@ 2012-06-18 11:46 ` Jiri Kosina
  2012-07-02 21:05   ` Joao Paulo Rechi Vita
  17 siblings, 1 reply; 25+ messages in thread
From: Jiri Kosina @ 2012-06-18 11:46 UTC (permalink / raw)
  To: David Herrmann; +Cc: linux-input

On Sun, 10 Jun 2012, David Herrmann wrote:

> This adds a new low-level HID driver that allows user-space to implement the
> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
> There is already an implementation of HOGP, see the
> linux-bluetooth@vger.kernel.org mailing list for this.
> 
> I've split this into multiple patches to make review easier. This patchset is
> already working for several months for the HOGP developers but there may still
> be some issues with it. Please review.
> 
> The uhid_*() functions implement the basic module functionality. The
> uhid_char_*() functions handle character-device related functionality. The
> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
> functions are HID-callbacks.
> 
> I am open for any suggestions.

David,

I have just finished my review and haven't found any principal issues. I 
am queueing the patchset in my tree.

Thanks a lot for your work on this,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-06-18 11:46 ` Jiri Kosina
@ 2012-07-02 21:05   ` Joao Paulo Rechi Vita
  2012-07-02 21:19     ` David Herrmann
  0 siblings, 1 reply; 25+ messages in thread
From: Joao Paulo Rechi Vita @ 2012-07-02 21:05 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: David Herrmann, linux-input

On Mon, Jun 18, 2012 at 8:46 AM, Jiri Kosina <jkosina@suse.cz> wrote:
> On Sun, 10 Jun 2012, David Herrmann wrote:
>
>> This adds a new low-level HID driver that allows user-space to implement the
>> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
>> There is already an implementation of HOGP, see the
>> linux-bluetooth@vger.kernel.org mailing list for this.
>>
>> I've split this into multiple patches to make review easier. This patchset is
>> already working for several months for the HOGP developers but there may still
>> be some issues with it. Please review.
>>
>> The uhid_*() functions implement the basic module functionality. The
>> uhid_char_*() functions handle character-device related functionality. The
>> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
>> functions are HID-callbacks.
>>
>> I am open for any suggestions.
>
> David,
>
> I have just finished my review and haven't found any principal issues. I
> am queueing the patchset in my tree.
>

Just for information, when is this going to hit upstream trees (not
sure if its Linus' directly or other intermediate tree)? 3.6 merge
window?

-- 
João Paulo Rechi Vita
Openbossa Labs - INdT
--
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	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-07-02 21:05   ` Joao Paulo Rechi Vita
@ 2012-07-02 21:19     ` David Herrmann
  2012-07-03  2:15       ` Jiri Kosina
  0 siblings, 1 reply; 25+ messages in thread
From: David Herrmann @ 2012-07-02 21:19 UTC (permalink / raw)
  To: Joao Paulo Rechi Vita; +Cc: Jiri Kosina, linux-input

Hi Joao

On Mon, Jul 2, 2012 at 11:05 PM, Joao Paulo Rechi Vita
<jprvita@openbossa.org> wrote:
> On Mon, Jun 18, 2012 at 8:46 AM, Jiri Kosina <jkosina@suse.cz> wrote:
>> On Sun, 10 Jun 2012, David Herrmann wrote:
>>
>>> This adds a new low-level HID driver that allows user-space to implement the
>>> transport-layer. This is needed by HOGP (HID over Gatt on Bluetooth Low Energy).
>>> There is already an implementation of HOGP, see the
>>> linux-bluetooth@vger.kernel.org mailing list for this.
>>>
>>> I've split this into multiple patches to make review easier. This patchset is
>>> already working for several months for the HOGP developers but there may still
>>> be some issues with it. Please review.
>>>
>>> The uhid_*() functions implement the basic module functionality. The
>>> uhid_char_*() functions handle character-device related functionality. The
>>> uhid_dev_*() functions handle the uhid-device object and the uhid_hid_*()
>>> functions are HID-callbacks.
>>>
>>> I am open for any suggestions.
>>
>> David,
>>
>> I have just finished my review and haven't found any principal issues. I
>> am queueing the patchset in my tree.
>>
>
> Just for information, when is this going to hit upstream trees (not
> sure if its Linus' directly or other intermediate tree)? 3.6 merge
> window?

If Jiri does not delay it due to bugs in linux-next it will hit
upstream with next merge window (hopefully ;)).

Regards
David

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/16] HID: uhid: User-space HID I/O driver
  2012-07-02 21:19     ` David Herrmann
@ 2012-07-03  2:15       ` Jiri Kosina
  0 siblings, 0 replies; 25+ messages in thread
From: Jiri Kosina @ 2012-07-03  2:15 UTC (permalink / raw)
  To: David Herrmann; +Cc: Joao Paulo Rechi Vita, linux-input

On Mon, 2 Jul 2012, David Herrmann wrote:

> > Just for information, when is this going to hit upstream trees (not
> > sure if its Linus' directly or other intermediate tree)? 3.6 merge
> > window?
> 
> If Jiri does not delay it due to bugs in linux-next it will hit
> upstream with next merge window (hopefully ;)).

Yup, I am indeed scheduling uhid for 3.6 merge window.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2012-07-03  2:15 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-10 13:16 [PATCH 00/16] HID: uhid: User-space HID I/O driver David Herrmann
2012-06-10 13:16 ` [PATCH 01/16] HID: uhid: introduce user-space I/O driver support for HID David Herrmann
2012-06-10 13:16 ` [PATCH 02/16] HID: uhid: add internal message buffer David Herrmann
2012-06-10 13:16 ` [PATCH 03/16] HID: uhid: allow poll()'ing on uhid devices David Herrmann
2012-06-10 13:16 ` [PATCH 04/16] HID: uhid: implement read() " David Herrmann
2012-06-10 13:16 ` [PATCH 05/16] HID: uhid: implement write() " David Herrmann
2012-06-10 13:16 ` [PATCH 06/16] HID: uhid: add UHID_CREATE and UHID_DESTROY events David Herrmann
2012-06-10 13:16 ` [PATCH 07/16] HID: uhid: allow feeding input data into uhid devices David Herrmann
2012-06-10 13:16 ` [PATCH 08/16] HID: uhid: forward hid report-descriptor to hid core David Herrmann
2012-06-10 13:16 ` [PATCH 09/16] HID: uhid: add UHID_START and UHID_STOP events David Herrmann
2012-06-10 13:16 ` [PATCH 10/16] HID: uhid: forward open/close events to user-space David Herrmann
2012-06-10 13:16 ` [PATCH 11/16] HID: uhid: forward output request " David Herrmann
2012-06-10 13:16 ` [PATCH 12/16] HID: uhid: forward raw output reports " David Herrmann
2012-06-10 13:16 ` [PATCH 13/16] HID: uhid: implement feature requests David Herrmann
2012-06-10 13:16 ` [PATCH 14/16] HID: uhid: add documentation David Herrmann
2012-06-10 13:16 ` [PATCH 15/16] HID: uhid: add example program David Herrmann
2012-06-10 13:16 ` [PATCH 16/16] MAINTAINERS: add UHID entry David Herrmann
2012-06-11 14:46 ` [PATCH 00/16] HID: uhid: User-space HID I/O driver Joao Paulo Rechi Vita
2012-06-11 17:56   ` David Herrmann
     [not found]     ` <CAAngNMa3GMqrgZUrx=XqaRWfK2MaFMewK6OEQU_=4oPj1FOMNw@mail.gmail.com>
2012-06-14 22:05       ` Joao Paulo Rechi Vita
2012-06-16 12:44         ` David Herrmann
2012-06-18 11:46 ` Jiri Kosina
2012-07-02 21:05   ` Joao Paulo Rechi Vita
2012-07-02 21:19     ` David Herrmann
2012-07-03  2:15       ` Jiri Kosina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).