diff options
Diffstat (limited to 'drivers/hid/hidraw.c')
| -rw-r--r-- | drivers/hid/hidraw.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 894d52e05bf9..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 | } |
| @@ -310,7 +313,7 @@ int hidraw_connect(struct hid_device *hid) | |||
| 310 | 313 | ||
| 311 | result = -EINVAL; | 314 | result = -EINVAL; |
| 312 | 315 | ||
| 313 | spin_lock(&minors_lock); | 316 | mutex_lock(&minors_lock); |
| 314 | 317 | ||
| 315 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { | 318 | for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) { |
| 316 | if (hidraw_table[minor]) | 319 | if (hidraw_table[minor]) |
| @@ -320,9 +323,8 @@ int hidraw_connect(struct hid_device *hid) | |||
| 320 | break; | 323 | break; |
| 321 | } | 324 | } |
| 322 | 325 | ||
| 323 | spin_unlock(&minors_lock); | ||
| 324 | |||
| 325 | if (result) { | 326 | if (result) { |
| 327 | mutex_unlock(&minors_lock); | ||
| 326 | kfree(dev); | 328 | kfree(dev); |
| 327 | goto out; | 329 | goto out; |
| 328 | } | 330 | } |
| @@ -331,14 +333,14 @@ int hidraw_connect(struct hid_device *hid) | |||
| 331 | NULL, "%s%d", "hidraw", minor); | 333 | NULL, "%s%d", "hidraw", minor); |
| 332 | 334 | ||
| 333 | if (IS_ERR(dev->dev)) { | 335 | if (IS_ERR(dev->dev)) { |
| 334 | spin_lock(&minors_lock); | ||
| 335 | hidraw_table[minor] = NULL; | 336 | hidraw_table[minor] = NULL; |
| 336 | spin_unlock(&minors_lock); | 337 | mutex_unlock(&minors_lock); |
| 337 | result = PTR_ERR(dev->dev); | 338 | result = PTR_ERR(dev->dev); |
| 338 | kfree(dev); | 339 | kfree(dev); |
| 339 | goto out; | 340 | goto out; |
| 340 | } | 341 | } |
| 341 | 342 | ||
| 343 | mutex_unlock(&minors_lock); | ||
| 342 | init_waitqueue_head(&dev->wait); | 344 | init_waitqueue_head(&dev->wait); |
| 343 | INIT_LIST_HEAD(&dev->list); | 345 | INIT_LIST_HEAD(&dev->list); |
| 344 | 346 | ||
| @@ -360,9 +362,9 @@ void hidraw_disconnect(struct hid_device *hid) | |||
| 360 | 362 | ||
| 361 | hidraw->exist = 0; | 363 | hidraw->exist = 0; |
| 362 | 364 | ||
| 363 | spin_lock(&minors_lock); | 365 | mutex_lock(&minors_lock); |
| 364 | hidraw_table[hidraw->minor] = NULL; | 366 | hidraw_table[hidraw->minor] = NULL; |
| 365 | spin_unlock(&minors_lock); | 367 | mutex_unlock(&minors_lock); |
| 366 | 368 | ||
| 367 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); | 369 | device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); |
| 368 | 370 | ||
