summaryrefslogtreecommitdiff
path: root/usr/src/dkms_source_tree/hidraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/dkms_source_tree/hidraw.c')
-rw-r--r--usr/src/dkms_source_tree/hidraw.c153
1 files changed, 102 insertions, 51 deletions
diff --git a/usr/src/dkms_source_tree/hidraw.c b/usr/src/dkms_source_tree/hidraw.c
index 8c030d9..3ccd478 100644
--- a/usr/src/dkms_source_tree/hidraw.c
+++ b/usr/src/dkms_source_tree/hidraw.c
@@ -28,8 +28,10 @@
28#include <linux/poll.h> 28#include <linux/poll.h>
29#include <linux/device.h> 29#include <linux/device.h>
30#include <linux/major.h> 30#include <linux/major.h>
31#include <linux/slab.h>
31#include <linux/hid.h> 32#include <linux/hid.h>
32#include <linux/mutex.h> 33#include <linux/mutex.h>
34#include <linux/sched.h>
33#include <linux/smp_lock.h> 35#include <linux/smp_lock.h>
34 36
35#include <linux/hidraw.h> 37#include <linux/hidraw.h>
@@ -38,7 +40,7 @@ static int hidraw_major;
38static struct cdev hidraw_cdev; 40static struct cdev hidraw_cdev;
39static struct class *hidraw_class; 41static struct class *hidraw_class;
40static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; 42static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
41static DEFINE_SPINLOCK(minors_lock); 43static DEFINE_MUTEX(minors_lock);
42 44
43static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 45static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
44{ 46{
@@ -47,10 +49,9 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
47 char *report; 49 char *report;
48 DECLARE_WAITQUEUE(wait, current); 50 DECLARE_WAITQUEUE(wait, current);
49 51
50 while (ret == 0) { 52 mutex_lock(&list->read_mutex);
51
52 mutex_lock(&list->read_mutex);
53 53
54 while (ret == 0) {
54 if (list->head == list->tail) { 55 if (list->head == list->tail) {
55 add_wait_queue(&list->hidraw->wait, &wait); 56 add_wait_queue(&list->hidraw->wait, &wait);
56 set_current_state(TASK_INTERRUPTIBLE); 57 set_current_state(TASK_INTERRUPTIBLE);
@@ -105,38 +106,48 @@ out:
105static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 106static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
106{ 107{
107 unsigned int minor = iminor(file->f_path.dentry->d_inode); 108 unsigned int minor = iminor(file->f_path.dentry->d_inode);
108 /* FIXME: What stops hidraw_table going NULL */ 109 struct hid_device *dev;
109 struct hid_device *dev = hidraw_table[minor]->hid;
110 __u8 *buf; 110 __u8 *buf;
111 int ret = 0; 111 int ret = 0;
112 112
113 if (!dev->hid_output_raw_report) 113 mutex_lock(&minors_lock);
114 return -ENODEV; 114 dev = hidraw_table[minor]->hid;
115
116 if (!dev->hid_output_raw_report) {
117 ret = -ENODEV;
118 goto out;
119 }
115 120
116 if (count > HID_MAX_BUFFER_SIZE) { 121 if (count > HID_MAX_BUFFER_SIZE) {
117 printk(KERN_WARNING "hidraw: pid %d passed too large report\n", 122 printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
118 task_pid_nr(current)); 123 task_pid_nr(current));
119 return -EINVAL; 124 ret = -EINVAL;
125 goto out;
120 } 126 }
121 127
122 if (count < 2) { 128 if (count < 2) {
123 printk(KERN_WARNING "hidraw: pid %d passed too short report\n", 129 printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
124 task_pid_nr(current)); 130 task_pid_nr(current));
125 return -EINVAL; 131 ret = -EINVAL;
132 goto out;
126 } 133 }
127 134
128 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); 135 buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
129 if (!buf) 136 if (!buf) {
130 return -ENOMEM; 137 ret = -ENOMEM;
138 goto out;
139 }
131 140
132 if (copy_from_user(buf, buffer, count)) { 141 if (copy_from_user(buf, buffer, count)) {
133 ret = -EFAULT; 142 ret = -EFAULT;
134 goto out; 143 goto out_free;
135 } 144 }
136 145
137 ret = dev->hid_output_raw_report(dev, buf, count); 146 ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
138out: 147out_free:
139 kfree(buf); 148 kfree(buf);
149out:
150 mutex_unlock(&minors_lock);
140 return ret; 151 return ret;
141} 152}
142 153
@@ -159,16 +170,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
159 struct hidraw_list *list; 170 struct hidraw_list *list;
160 int err = 0; 171 int err = 0;
161 172
162 lock_kernel();
163 if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { 173 if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
164 err = -ENOMEM; 174 err = -ENOMEM;
165 goto out; 175 goto out;
166 } 176 }
167 177
168 spin_lock(&minors_lock); 178 mutex_lock(&minors_lock);
169 if (!hidraw_table[minor]) { 179 if (!hidraw_table[minor]) {
170 printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
171 minor);
172 kfree(list); 180 kfree(list);
173 err = -ENODEV; 181 err = -ENODEV;
174 goto out_unlock; 182 goto out_unlock;
@@ -180,13 +188,23 @@ static int hidraw_open(struct inode *inode, struct file *file)
180 file->private_data = list; 188 file->private_data = list;
181 189
182 dev = hidraw_table[minor]; 190 dev = hidraw_table[minor];
183 if (!dev->open++) 191 if (!dev->open++) {
184 dev->hid->hid_open(dev->hid); 192 if (dev->hid->ll_driver->power) {
193 err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
194 if (err < 0)
195 goto out_unlock;
196 }
197 err = dev->hid->ll_driver->open(dev->hid);
198 if (err < 0) {
199 if (dev->hid->ll_driver->power)
200 dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
201 dev->open--;
202 }
203 }
185 204
186out_unlock: 205out_unlock:
187 spin_unlock(&minors_lock); 206 mutex_unlock(&minors_lock);
188out: 207out:
189 unlock_kernel();
190 return err; 208 return err;
191 209
192} 210}
@@ -197,19 +215,19 @@ static int hidraw_release(struct inode * inode, struct file * file)
197 struct hidraw *dev; 215 struct hidraw *dev;
198 struct hidraw_list *list = file->private_data; 216 struct hidraw_list *list = file->private_data;
199 217
200 if (!hidraw_table[minor]) { 218 if (!hidraw_table[minor])
201 printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
202 minor);
203 return -ENODEV; 219 return -ENODEV;
204 }
205 220
206 list_del(&list->node); 221 list_del(&list->node);
207 dev = hidraw_table[minor]; 222 dev = hidraw_table[minor];
208 if (!dev->open--) { 223 if (!--dev->open) {
209 if (list->hidraw->exist) 224 if (list->hidraw->exist) {
210 dev->hid->hid_close(dev->hid); 225 if (dev->hid->ll_driver->power)
211 else 226 dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
227 dev->hid->ll_driver->close(dev->hid);
228 } else {
212 kfree(list->hidraw); 229 kfree(list->hidraw);
230 }
213 } 231 }
214 232
215 kfree(list); 233 kfree(list);
@@ -223,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
223 struct inode *inode = file->f_path.dentry->d_inode; 241 struct inode *inode = file->f_path.dentry->d_inode;
224 unsigned int minor = iminor(inode); 242 unsigned int minor = iminor(inode);
225 long ret = 0; 243 long ret = 0;
226 /* FIXME: What stops hidraw_table going NULL */ 244 struct hidraw *dev;
227 struct hidraw *dev = hidraw_table[minor];
228 void __user *user_arg = (void __user*) arg; 245 void __user *user_arg = (void __user*) arg;
229 246
230 lock_kernel(); 247 mutex_lock(&minors_lock);
248 dev = hidraw_table[minor];
249
231 switch (cmd) { 250 switch (cmd) {
232 case HIDIOCGRDESCSIZE: 251 case HIDIOCGRDESCSIZE:
233 if (put_user(dev->hid->rsize, (int __user *)arg)) 252 if (put_user(dev->hid->rsize, (int __user *)arg))
@@ -262,8 +281,45 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
262 break; 281 break;
263 } 282 }
264 default: 283 default:
265 ret = -ENOTTY; 284 {
285 struct hid_device *hid = dev->hid;
286 if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) {
287 ret = -EINVAL;
288 break;
289 }
290
291 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
292 int len;
293 if (!hid->name) {
294 ret = 0;
295 break;
296 }
297 len = strlen(hid->name) + 1;
298 if (len > _IOC_SIZE(cmd))
299 len = _IOC_SIZE(cmd);
300 ret = copy_to_user(user_arg, hid->name, len) ?
301 -EFAULT : len;
302 break;
303 }
304
305 if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
306 int len;
307 if (!hid->phys) {
308 ret = 0;
309 break;
310 }
311 len = strlen(hid->phys) + 1;
312 if (len > _IOC_SIZE(cmd))
313 len = _IOC_SIZE(cmd);
314 ret = copy_to_user(user_arg, hid->phys, len) ?
315 -EFAULT : len;
316 break;
317 }
318 }
319
320 ret = -ENOTTY;
266 } 321 }
322 mutex_unlock(&minors_lock);
267 return ret; 323 return ret;
268} 324}
269 325
@@ -298,10 +354,7 @@ int hidraw_connect(struct hid_device *hid)
298 int minor, result; 354 int minor, result;
299 struct hidraw *dev; 355 struct hidraw *dev;
300 356
301 /* TODO currently we accept any HID device. This should later 357 /* we accept any HID device, no matter the applications */
302 * probably be fixed to accept only those devices which provide
303 * non-input applications
304 */
305 358
306 dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL); 359 dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
307 if (!dev) 360 if (!dev)
@@ -309,7 +362,7 @@ int hidraw_connect(struct hid_device *hid)
309 362
310 result = -EINVAL; 363 result = -EINVAL;
311 364
312 spin_lock(&minors_lock); 365 mutex_lock(&minors_lock);
313 366
314 for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { 367 for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
315 if (hidraw_table[minor]) 368 if (hidraw_table[minor])
@@ -319,26 +372,24 @@ int hidraw_connect(struct hid_device *hid)
319 break; 372 break;
320 } 373 }
321 374
322 spin_unlock(&minors_lock);
323
324 if (result) { 375 if (result) {
376 mutex_unlock(&minors_lock);
325 kfree(dev); 377 kfree(dev);
326 goto out; 378 goto out;
327 } 379 }
328 380
329 dev->dev = device_create_drvdata(hidraw_class, NULL, 381 dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
330 MKDEV(hidraw_major, minor), NULL, 382 NULL, "%s%d", "hidraw", minor);
331 "%s%d", "hidraw", minor);
332 383
333 if (IS_ERR(dev->dev)) { 384 if (IS_ERR(dev->dev)) {
334 spin_lock(&minors_lock);
335 hidraw_table[minor] = NULL; 385 hidraw_table[minor] = NULL;
336 spin_unlock(&minors_lock); 386 mutex_unlock(&minors_lock);
337 result = PTR_ERR(dev->dev); 387 result = PTR_ERR(dev->dev);
338 kfree(dev); 388 kfree(dev);
339 goto out; 389 goto out;
340 } 390 }
341 391
392 mutex_unlock(&minors_lock);
342 init_waitqueue_head(&dev->wait); 393 init_waitqueue_head(&dev->wait);
343 INIT_LIST_HEAD(&dev->list); 394 INIT_LIST_HEAD(&dev->list);
344 395
@@ -360,14 +411,14 @@ void hidraw_disconnect(struct hid_device *hid)
360 411
361 hidraw->exist = 0; 412 hidraw->exist = 0;
362 413
363 spin_lock(&minors_lock); 414 mutex_lock(&minors_lock);
364 hidraw_table[hidraw->minor] = NULL; 415 hidraw_table[hidraw->minor] = NULL;
365 spin_unlock(&minors_lock); 416 mutex_unlock(&minors_lock);
366 417
367 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); 418 device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
368 419
369 if (hidraw->open) { 420 if (hidraw->open) {
370 hid->hid_close(hid); 421 hid->ll_driver->close(hid);
371 wake_up_interruptible(&hidraw->wait); 422 wake_up_interruptible(&hidraw->wait);
372 } else { 423 } else {
373 kfree(hidraw); 424 kfree(hidraw);
@@ -404,7 +455,7 @@ out:
404 return result; 455 return result;
405} 456}
406 457
407void __exit hidraw_exit(void) 458void hidraw_exit(void)
408{ 459{
409 dev_t dev_id = MKDEV(hidraw_major, 0); 460 dev_t dev_id = MKDEV(hidraw_major, 0);
410 461