diff options
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r-- | drivers/hid/hidraw.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index af3edb98df43..7685ae6808c4 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -38,7 +38,7 @@ static int hidraw_major; | |||
38 | static struct cdev hidraw_cdev; | 38 | static struct cdev hidraw_cdev; |
39 | static struct class *hidraw_class; | 39 | static struct class *hidraw_class; |
40 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; | 40 | static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; |
41 | static DEFINE_SPINLOCK(minors_lock); | 41 | static DEFINE_MUTEX(minors_lock); |
42 | 42 | ||
43 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 43 | static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
44 | { | 44 | { |
@@ -159,13 +159,13 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
159 | struct hidraw_list *list; | 159 | struct hidraw_list *list; |
160 | int err = 0; | 160 | int err = 0; |
161 | 161 | ||
162 | lock_kernel(); | ||
163 | if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { | 162 | if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) { |
164 | err = -ENOMEM; | 163 | err = -ENOMEM; |
165 | goto out; | 164 | goto out; |
166 | } | 165 | } |
167 | 166 | ||
168 | spin_lock(&minors_lock); | 167 | lock_kernel(); |
168 | mutex_lock(&minors_lock); | ||
169 | if (!hidraw_table[minor]) { | 169 | if (!hidraw_table[minor]) { |
170 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | 170 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", |
171 | minor); | 171 | minor); |
@@ -180,13 +180,16 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
180 | file->private_data = list; | 180 | file->private_data = list; |
181 | 181 | ||
182 | dev = hidraw_table[minor]; | 182 | dev = hidraw_table[minor]; |
183 | if (!dev->open++) | 183 | if (!dev->open++) { |
184 | dev->hid->ll_driver->open(dev->hid); | 184 | err = dev->hid->ll_driver->open(dev->hid); |
185 | if (err < 0) | ||
186 | dev->open--; | ||
187 | } | ||
185 | 188 | ||
186 | out_unlock: | 189 | out_unlock: |
187 | spin_unlock(&minors_lock); | 190 | mutex_unlock(&minors_lock); |
188 | out: | ||
189 | unlock_kernel(); | 191 | unlock_kernel(); |
192 | out: | ||
190 | return err; | 193 | return err; |
191 | 194 | ||
192 | } | 195 | } |
@@ -264,6 +267,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
264 | default: | 267 | default: |
265 | ret = -ENOTTY; | 268 | ret = -ENOTTY; |
266 | } | 269 | } |
270 | unlock_kernel(); | ||
267 | return ret; | 271 | return ret; |
268 | } | 272 | } |
269 | 273 | ||
@@ -309,7 +313,7 @@ int hidraw_connect(struct hid_device *hid) | |||
309 | 313 | ||
310 | result = -EINVAL; | 314 | result = -EINVAL; |
311 | 315 | ||
312 | spin_lock(&minors_lock); | 316 | mutex_lock(&minors_lock); |
313 | 317 | ||
314 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { | 318 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { |
315 | if (hidraw_table[minor]) | 319 | if (hidraw_table[minor]) |
@@ -319,9 +323,8 @@ int hidraw_connect(struct hid_device *hid) | |||
319 | break; | 323 | break; |
320 | } | 324 | } |
321 | 325 | ||
322 | spin_unlock(&minors_lock); | ||
323 | |||
324 | if (result) { | 326 | if (result) { |
327 | mutex_unlock(&minors_lock); | ||
325 | kfree(dev); | 328 | kfree(dev); |
326 | goto out; | 329 | goto out; |
327 | } | 330 | } |
@@ -330,14 +333,14 @@ int hidraw_connect(struct hid_device *hid) | |||
330 | NULL, "%s%d", "hidraw", minor); | 333 | NULL, "%s%d", "hidraw", minor); |
331 | 334 | ||
332 | if (IS_ERR(dev->dev)) { | 335 | if (IS_ERR(dev->dev)) { |
333 | spin_lock(&minors_lock); | ||
334 | hidraw_table[minor] = NULL; | 336 | hidraw_table[minor] = NULL; |
335 | spin_unlock(&minors_lock); | 337 | mutex_unlock(&minors_lock); |
336 | result = PTR_ERR(dev->dev); | 338 | result = PTR_ERR(dev->dev); |
337 | kfree(dev); | 339 | kfree(dev); |
338 | goto out; | 340 | goto out; |
339 | } | 341 | } |
340 | 342 | ||
343 | mutex_unlock(&minors_lock); | ||
341 | init_waitqueue_head(&dev->wait); | 344 | init_waitqueue_head(&dev->wait); |
342 | INIT_LIST_HEAD(&dev->list); | 345 | INIT_LIST_HEAD(&dev->list); |
343 | 346 | ||
@@ -359,9 +362,9 @@ void hidraw_disconnect(struct hid_device *hid) | |||
359 | 362 | ||
360 | hidraw->exist = 0; | 363 | hidraw->exist = 0; |
361 | 364 | ||
362 | spin_lock(&minors_lock); | 365 | mutex_lock(&minors_lock); |
363 | hidraw_table[hidraw->minor] = NULL; | 366 | hidraw_table[hidraw->minor] = NULL; |
364 | spin_unlock(&minors_lock); | 367 | mutex_unlock(&minors_lock); |
365 | 368 | ||
366 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | 369 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); |
367 | 370 | ||
@@ -403,7 +406,7 @@ out: | |||
403 | return result; | 406 | return result; |
404 | } | 407 | } |
405 | 408 | ||
406 | void __exit hidraw_exit(void) | 409 | void hidraw_exit(void) |
407 | { | 410 | { |
408 | dev_t dev_id = MKDEV(hidraw_major, 0); | 411 | dev_t dev_id = MKDEV(hidraw_major, 0); |
409 | 412 | ||