diff options
author | David Herrmann <dh.herrmann@googlemail.com> | 2012-06-10 09:16:14 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-06-18 07:42:00 -0400 |
commit | ace3d8614ab0e6544f5f85921085b55b915fe9aa (patch) | |
tree | b666635c332af039a991d8391b4f24ac62a51182 /drivers/hid/uhid.c | |
parent | 1ccd7a2a33f2b47e46c51f4501e9623a51d28090 (diff) |
HID: uhid: add internal message buffer
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>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/uhid.c')
-rw-r--r-- | drivers/hid/uhid.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 5b02d6cb0e60..05ef4b05a63e 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c | |||
@@ -25,16 +25,81 @@ | |||
25 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
26 | 26 | ||
27 | #define UHID_NAME "uhid" | 27 | #define UHID_NAME "uhid" |
28 | #define UHID_BUFSIZE 32 | ||
29 | |||
30 | struct uhid_device { | ||
31 | struct hid_device *hid; | ||
32 | |||
33 | wait_queue_head_t waitq; | ||
34 | spinlock_t qlock; | ||
35 | __u8 head; | ||
36 | __u8 tail; | ||
37 | struct uhid_event *outq[UHID_BUFSIZE]; | ||
38 | }; | ||
28 | 39 | ||
29 | static struct miscdevice uhid_misc; | 40 | static struct miscdevice uhid_misc; |
30 | 41 | ||
42 | static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) | ||
43 | { | ||
44 | __u8 newhead; | ||
45 | |||
46 | newhead = (uhid->head + 1) % UHID_BUFSIZE; | ||
47 | |||
48 | if (newhead != uhid->tail) { | ||
49 | uhid->outq[uhid->head] = ev; | ||
50 | uhid->head = newhead; | ||
51 | wake_up_interruptible(&uhid->waitq); | ||
52 | } else { | ||
53 | hid_warn(uhid->hid, "Output queue is full\n"); | ||
54 | kfree(ev); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static int uhid_queue_event(struct uhid_device *uhid, __u32 event) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | struct uhid_event *ev; | ||
62 | |||
63 | ev = kzalloc(sizeof(*ev), GFP_KERNEL); | ||
64 | if (!ev) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | ev->type = event; | ||
68 | |||
69 | spin_lock_irqsave(&uhid->qlock, flags); | ||
70 | uhid_queue(uhid, ev); | ||
71 | spin_unlock_irqrestore(&uhid->qlock, flags); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
31 | static int uhid_char_open(struct inode *inode, struct file *file) | 76 | static int uhid_char_open(struct inode *inode, struct file *file) |
32 | { | 77 | { |
78 | struct uhid_device *uhid; | ||
79 | |||
80 | uhid = kzalloc(sizeof(*uhid), GFP_KERNEL); | ||
81 | if (!uhid) | ||
82 | return -ENOMEM; | ||
83 | |||
84 | spin_lock_init(&uhid->qlock); | ||
85 | init_waitqueue_head(&uhid->waitq); | ||
86 | |||
87 | file->private_data = uhid; | ||
88 | nonseekable_open(inode, file); | ||
89 | |||
33 | return 0; | 90 | return 0; |
34 | } | 91 | } |
35 | 92 | ||
36 | static int uhid_char_release(struct inode *inode, struct file *file) | 93 | static int uhid_char_release(struct inode *inode, struct file *file) |
37 | { | 94 | { |
95 | struct uhid_device *uhid = file->private_data; | ||
96 | unsigned int i; | ||
97 | |||
98 | for (i = 0; i < UHID_BUFSIZE; ++i) | ||
99 | kfree(uhid->outq[i]); | ||
100 | |||
101 | kfree(uhid); | ||
102 | |||
38 | return 0; | 103 | return 0; |
39 | } | 104 | } |
40 | 105 | ||