diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-17 09:32:49 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-17 09:32:49 -0300 |
commit | 214e2ca2b82d335935a861c253fe94c61ad77aad (patch) | |
tree | eee42ff74d10470789d919b8499737ad0e919360 /drivers/hid/hidraw.c | |
parent | 1fdead8ad31d3aa833bc37739273fcde89ace93c (diff) | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
Merge tag 'v3.7-rc1' into staging/for_v3.8
Linux 3.7-rc1
* tag 'v3.7-rc1': (9579 commits)
Linux 3.7-rc1
x86, boot: Explicitly include autoconf.h for hostprogs
perf: Fix UAPI fallout
ARM: config: make sure that platforms are ordered by option string
ARM: config: sort select statements alphanumerically
UAPI: (Scripted) Disintegrate include/linux/byteorder
UAPI: (Scripted) Disintegrate include/linux
UAPI: Unexport linux/blk_types.h
UAPI: Unexport part of linux/ppp-comp.h
perf: Handle new rbtree implementation
procfs: don't need a PATH_MAX allocation to hold a string representation of an int
vfs: embed struct filename inside of names_cache allocation if possible
audit: make audit_inode take struct filename
vfs: make path_openat take a struct filename pointer
vfs: turn do_path_lookup into wrapper around struct filename variant
audit: allow audit code to satisfy getname requests from its names_list
vfs: define struct filename and have getname() return it
btrfs: Fix compilation with user namespace support enabled
userns: Fix posix_acl_file_xattr_userns gid conversion
userns: Properly print bluetooth socket uids
...
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r-- | drivers/hid/hidraw.c | 84 |
1 files changed, 37 insertions, 47 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 3b6f7bf5a77..17d15bb610d 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -42,6 +42,7 @@ static struct cdev hidraw_cdev; static struct class *hidraw_class; static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; static DEFINE_MUTEX(minors_lock); +static void drop_ref(struct hidraw *hid, int exists_bit); static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -113,7 +114,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, __u8 *buf; int ret = 0; - if (!hidraw_table[minor]) { + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { ret = -ENODEV; goto out; } @@ -261,7 +262,7 @@ static int hidraw_open(struct inode *inode, struct file *file) } mutex_lock(&minors_lock); - if (!hidraw_table[minor]) { + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { err = -ENODEV; goto out_unlock; } @@ -298,36 +299,12 @@ out: static int hidraw_release(struct inode * inode, struct file * file) { unsigned int minor = iminor(inode); - struct hidraw *dev; struct hidraw_list *list = file->private_data; - int ret; - int i; - - mutex_lock(&minors_lock); - if (!hidraw_table[minor]) { - ret = -ENODEV; - goto unlock; - } + drop_ref(hidraw_table[minor], 0); list_del(&list->node); - dev = hidraw_table[minor]; - if (!--dev->open) { - if (list->hidraw->exist) { - hid_hw_power(dev->hid, PM_HINT_NORMAL); - hid_hw_close(dev->hid); - } else { - kfree(list->hidraw); - } - } - - for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i) - kfree(list->buffer[i].value); kfree(list); - ret = 0; -unlock: - mutex_unlock(&minors_lock); - - return ret; + return 0; } static long hidraw_ioctl(struct file *file, unsigned int cmd, @@ -529,21 +506,7 @@ EXPORT_SYMBOL_GPL(hidraw_connect); void hidraw_disconnect(struct hid_device *hid) { struct hidraw *hidraw = hid->hidraw; - - mutex_lock(&minors_lock); - hidraw->exist = 0; - - device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); - - hidraw_table[hidraw->minor] = NULL; - - if (hidraw->open) { - hid_hw_close(hid); - wake_up_interruptible(&hidraw->wait); - } else { - kfree(hidraw); - } - mutex_unlock(&minors_lock); + drop_ref(hidraw, 1); } EXPORT_SYMBOL_GPL(hidraw_disconnect); @@ -559,21 +522,28 @@ int __init hidraw_init(void) if (result < 0) { pr_warn("can't get major number\n"); - result = 0; goto out; } hidraw_class = class_create(THIS_MODULE, "hidraw"); if (IS_ERR(hidraw_class)) { result = PTR_ERR(hidraw_class); - unregister_chrdev(hidraw_major, "hidraw"); - goto out; + goto error_cdev; } cdev_init(&hidraw_cdev, &hidraw_ops); - cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); + result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES); + if (result < 0) + goto error_class; + out: return result; + +error_class: + class_destroy(hidraw_class); +error_cdev: + unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); + goto out; } void hidraw_exit(void) @@ -585,3 +555,23 @@ void hidraw_exit(void) unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); } + +static void drop_ref(struct hidraw *hidraw, int exists_bit) +{ + mutex_lock(&minors_lock); + if (exists_bit) { + hid_hw_close(hidraw->hid); + hidraw->exist = 0; + if (hidraw->open) + wake_up_interruptible(&hidraw->wait); + } else { + --hidraw->open; + } + + if (!hidraw->open && !hidraw->exist) { + device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor)); + hidraw_table[hidraw->minor] = NULL; + kfree(hidraw); + } + mutex_unlock(&minors_lock); +} |