aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2012-06-10 09:16:18 -0400
committerJiri Kosina <jkosina@suse.cz>2012-06-18 07:42:01 -0400
commitd365c6cfd337a2bccdc65eacce271a311ea1072c (patch)
treefcd33cd4935c8c1c0acdebaaa62047d35e103e86 /drivers/hid
parent6664ef72a47459f883d3409ca9b2fa200015704b (diff)
HID: uhid: add UHID_CREATE and UHID_DESTROY events
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> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/uhid.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 31e8379cfd15..61ee7cc32ccf 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -29,6 +29,11 @@
29 29
30struct uhid_device { 30struct uhid_device {
31 struct mutex devlock; 31 struct mutex devlock;
32 bool running;
33
34 __u8 *rd_data;
35 uint rd_size;
36
32 struct hid_device *hid; 37 struct hid_device *hid;
33 struct uhid_event input_buf; 38 struct uhid_event input_buf;
34 39
@@ -75,6 +80,136 @@ static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
75 return 0; 80 return 0;
76} 81}
77 82
83static int uhid_hid_start(struct hid_device *hid)
84{
85 return 0;
86}
87
88static void uhid_hid_stop(struct hid_device *hid)
89{
90}
91
92static int uhid_hid_open(struct hid_device *hid)
93{
94 return 0;
95}
96
97static void uhid_hid_close(struct hid_device *hid)
98{
99}
100
101static int uhid_hid_input(struct input_dev *input, unsigned int type,
102 unsigned int code, int value)
103{
104 return 0;
105}
106
107static int uhid_hid_parse(struct hid_device *hid)
108{
109 return 0;
110}
111
112static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
113 __u8 *buf, size_t count, unsigned char rtype)
114{
115 return 0;
116}
117
118static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
119 unsigned char report_type)
120{
121 return 0;
122}
123
124static struct hid_ll_driver uhid_hid_driver = {
125 .start = uhid_hid_start,
126 .stop = uhid_hid_stop,
127 .open = uhid_hid_open,
128 .close = uhid_hid_close,
129 .hidinput_input_event = uhid_hid_input,
130 .parse = uhid_hid_parse,
131};
132
133static int uhid_dev_create(struct uhid_device *uhid,
134 const struct uhid_event *ev)
135{
136 struct hid_device *hid;
137 int ret;
138
139 if (uhid->running)
140 return -EALREADY;
141
142 uhid->rd_size = ev->u.create.rd_size;
143 if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
144 return -EINVAL;
145
146 uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
147 if (!uhid->rd_data)
148 return -ENOMEM;
149
150 if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
151 uhid->rd_size)) {
152 ret = -EFAULT;
153 goto err_free;
154 }
155
156 hid = hid_allocate_device();
157 if (IS_ERR(hid)) {
158 ret = PTR_ERR(hid);
159 goto err_free;
160 }
161
162 strncpy(hid->name, ev->u.create.name, 127);
163 hid->name[127] = 0;
164 strncpy(hid->phys, ev->u.create.phys, 63);
165 hid->phys[63] = 0;
166 strncpy(hid->uniq, ev->u.create.uniq, 63);
167 hid->uniq[63] = 0;
168
169 hid->ll_driver = &uhid_hid_driver;
170 hid->hid_get_raw_report = uhid_hid_get_raw;
171 hid->hid_output_raw_report = uhid_hid_output_raw;
172 hid->bus = ev->u.create.bus;
173 hid->vendor = ev->u.create.vendor;
174 hid->product = ev->u.create.product;
175 hid->version = ev->u.create.version;
176 hid->country = ev->u.create.country;
177 hid->driver_data = uhid;
178 hid->dev.parent = uhid_misc.this_device;
179
180 uhid->hid = hid;
181 uhid->running = true;
182
183 ret = hid_add_device(hid);
184 if (ret) {
185 hid_err(hid, "Cannot register HID device\n");
186 goto err_hid;
187 }
188
189 return 0;
190
191err_hid:
192 hid_destroy_device(hid);
193 uhid->hid = NULL;
194 uhid->running = false;
195err_free:
196 kfree(uhid->rd_data);
197 return ret;
198}
199
200static int uhid_dev_destroy(struct uhid_device *uhid)
201{
202 if (!uhid->running)
203 return -EINVAL;
204
205 uhid->running = false;
206
207 hid_destroy_device(uhid->hid);
208 kfree(uhid->rd_data);
209
210 return 0;
211}
212
78static int uhid_char_open(struct inode *inode, struct file *file) 213static int uhid_char_open(struct inode *inode, struct file *file)
79{ 214{
80 struct uhid_device *uhid; 215 struct uhid_device *uhid;
@@ -86,6 +221,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
86 mutex_init(&uhid->devlock); 221 mutex_init(&uhid->devlock);
87 spin_lock_init(&uhid->qlock); 222 spin_lock_init(&uhid->qlock);
88 init_waitqueue_head(&uhid->waitq); 223 init_waitqueue_head(&uhid->waitq);
224 uhid->running = false;
89 225
90 file->private_data = uhid; 226 file->private_data = uhid;
91 nonseekable_open(inode, file); 227 nonseekable_open(inode, file);
@@ -98,6 +234,8 @@ static int uhid_char_release(struct inode *inode, struct file *file)
98 struct uhid_device *uhid = file->private_data; 234 struct uhid_device *uhid = file->private_data;
99 unsigned int i; 235 unsigned int i;
100 236
237 uhid_dev_destroy(uhid);
238
101 for (i = 0; i < UHID_BUFSIZE; ++i) 239 for (i = 0; i < UHID_BUFSIZE; ++i)
102 kfree(uhid->outq[i]); 240 kfree(uhid->outq[i]);
103 241
@@ -177,6 +315,12 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
177 } 315 }
178 316
179 switch (uhid->input_buf.type) { 317 switch (uhid->input_buf.type) {
318 case UHID_CREATE:
319 ret = uhid_dev_create(uhid, &uhid->input_buf);
320 break;
321 case UHID_DESTROY:
322 ret = uhid_dev_destroy(uhid);
323 break;
180 default: 324 default:
181 ret = -EOPNOTSUPP; 325 ret = -EOPNOTSUPP;
182 } 326 }