Commit 976bacef authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID fix from Jiri Kosina:
 "This reverts a patch that causes regression in binding between HID
  devices and drivers during device unplug/replug cycle."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  HID: hidraw: put old deallocation mechanism in place
parents ce6d841e df0cfd69
...@@ -42,7 +42,6 @@ static struct cdev hidraw_cdev; ...@@ -42,7 +42,6 @@ static struct cdev hidraw_cdev;
static struct class *hidraw_class; static struct class *hidraw_class;
static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES]; static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
static DEFINE_MUTEX(minors_lock); 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) static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{ {
...@@ -114,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -114,7 +113,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
__u8 *buf; __u8 *buf;
int ret = 0; int ret = 0;
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { if (!hidraw_table[minor]) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
...@@ -262,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -262,7 +261,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
} }
mutex_lock(&minors_lock); mutex_lock(&minors_lock);
if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { if (!hidraw_table[minor]) {
err = -ENODEV; err = -ENODEV;
goto out_unlock; goto out_unlock;
} }
...@@ -299,12 +298,36 @@ static int hidraw_open(struct inode *inode, struct file *file) ...@@ -299,12 +298,36 @@ static int hidraw_open(struct inode *inode, struct file *file)
static int hidraw_release(struct inode * inode, struct file * file) static int hidraw_release(struct inode * inode, struct file * file)
{ {
unsigned int minor = iminor(inode); unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list = file->private_data; 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); 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); kfree(list);
return 0; ret = 0;
unlock:
mutex_unlock(&minors_lock);
return ret;
} }
static long hidraw_ioctl(struct file *file, unsigned int cmd, static long hidraw_ioctl(struct file *file, unsigned int cmd,
...@@ -506,7 +529,21 @@ EXPORT_SYMBOL_GPL(hidraw_connect); ...@@ -506,7 +529,21 @@ EXPORT_SYMBOL_GPL(hidraw_connect);
void hidraw_disconnect(struct hid_device *hid) void hidraw_disconnect(struct hid_device *hid)
{ {
struct hidraw *hidraw = hid->hidraw; struct hidraw *hidraw = hid->hidraw;
drop_ref(hidraw, 1);
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);
} }
EXPORT_SYMBOL_GPL(hidraw_disconnect); EXPORT_SYMBOL_GPL(hidraw_disconnect);
...@@ -555,23 +592,3 @@ void hidraw_exit(void) ...@@ -555,23 +592,3 @@ void hidraw_exit(void)
unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment