diff options
Diffstat (limited to 'drivers/hid/hidraw.c')
-rw-r--r-- | drivers/hid/hidraw.c | 50 |
1 files changed, 27 insertions, 23 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 6eadf1a9b3cc..3ccd47850677 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -106,38 +106,48 @@ out: | |||
106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 106 | static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
107 | { | 107 | { |
108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); | 108 | unsigned int minor = iminor(file->f_path.dentry->d_inode); |
109 | /* FIXME: What stops hidraw_table going NULL */ | 109 | struct hid_device *dev; |
110 | struct hid_device *dev = hidraw_table[minor]->hid; | ||
111 | __u8 *buf; | 110 | __u8 *buf; |
112 | int ret = 0; | 111 | int ret = 0; |
113 | 112 | ||
114 | if (!dev->hid_output_raw_report) | 113 | mutex_lock(&minors_lock); |
115 | return -ENODEV; | 114 | dev = hidraw_table[minor]->hid; |
115 | |||
116 | if (!dev->hid_output_raw_report) { | ||
117 | ret = -ENODEV; | ||
118 | goto out; | ||
119 | } | ||
116 | 120 | ||
117 | if (count > HID_MAX_BUFFER_SIZE) { | 121 | if (count > HID_MAX_BUFFER_SIZE) { |
118 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", | 122 | printk(KERN_WARNING "hidraw: pid %d passed too large report\n", |
119 | task_pid_nr(current)); | 123 | task_pid_nr(current)); |
120 | return -EINVAL; | 124 | ret = -EINVAL; |
125 | goto out; | ||
121 | } | 126 | } |
122 | 127 | ||
123 | if (count < 2) { | 128 | if (count < 2) { |
124 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", | 129 | printk(KERN_WARNING "hidraw: pid %d passed too short report\n", |
125 | task_pid_nr(current)); | 130 | task_pid_nr(current)); |
126 | return -EINVAL; | 131 | ret = -EINVAL; |
132 | goto out; | ||
127 | } | 133 | } |
128 | 134 | ||
129 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); | 135 | buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); |
130 | if (!buf) | 136 | if (!buf) { |
131 | return -ENOMEM; | 137 | ret = -ENOMEM; |
138 | goto out; | ||
139 | } | ||
132 | 140 | ||
133 | if (copy_from_user(buf, buffer, count)) { | 141 | if (copy_from_user(buf, buffer, count)) { |
134 | ret = -EFAULT; | 142 | ret = -EFAULT; |
135 | goto out; | 143 | goto out_free; |
136 | } | 144 | } |
137 | 145 | ||
138 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); | 146 | ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); |
139 | out: | 147 | out_free: |
140 | kfree(buf); | 148 | kfree(buf); |
149 | out: | ||
150 | mutex_unlock(&minors_lock); | ||
141 | return ret; | 151 | return ret; |
142 | } | 152 | } |
143 | 153 | ||
@@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
165 | goto out; | 175 | goto out; |
166 | } | 176 | } |
167 | 177 | ||
168 | lock_kernel(); | ||
169 | mutex_lock(&minors_lock); | 178 | mutex_lock(&minors_lock); |
170 | if (!hidraw_table[minor]) { | 179 | if (!hidraw_table[minor]) { |
171 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
172 | minor); | ||
173 | kfree(list); | 180 | kfree(list); |
174 | err = -ENODEV; | 181 | err = -ENODEV; |
175 | goto out_unlock; | 182 | goto out_unlock; |
@@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) | |||
197 | 204 | ||
198 | out_unlock: | 205 | out_unlock: |
199 | mutex_unlock(&minors_lock); | 206 | mutex_unlock(&minors_lock); |
200 | unlock_kernel(); | ||
201 | out: | 207 | out: |
202 | return err; | 208 | return err; |
203 | 209 | ||
@@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) | |||
209 | struct hidraw *dev; | 215 | struct hidraw *dev; |
210 | struct hidraw_list *list = file->private_data; | 216 | struct hidraw_list *list = file->private_data; |
211 | 217 | ||
212 | if (!hidraw_table[minor]) { | 218 | if (!hidraw_table[minor]) |
213 | printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", | ||
214 | minor); | ||
215 | return -ENODEV; | 219 | return -ENODEV; |
216 | } | ||
217 | 220 | ||
218 | list_del(&list->node); | 221 | list_del(&list->node); |
219 | dev = hidraw_table[minor]; | 222 | dev = hidraw_table[minor]; |
@@ -238,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
238 | struct inode *inode = file->f_path.dentry->d_inode; | 241 | struct inode *inode = file->f_path.dentry->d_inode; |
239 | unsigned int minor = iminor(inode); | 242 | unsigned int minor = iminor(inode); |
240 | long ret = 0; | 243 | long ret = 0; |
241 | /* FIXME: What stops hidraw_table going NULL */ | 244 | struct hidraw *dev; |
242 | struct hidraw *dev = hidraw_table[minor]; | ||
243 | void __user *user_arg = (void __user*) arg; | 245 | void __user *user_arg = (void __user*) arg; |
244 | 246 | ||
245 | lock_kernel(); | 247 | mutex_lock(&minors_lock); |
248 | dev = hidraw_table[minor]; | ||
249 | |||
246 | switch (cmd) { | 250 | switch (cmd) { |
247 | case HIDIOCGRDESCSIZE: | 251 | case HIDIOCGRDESCSIZE: |
248 | if (put_user(dev->hid->rsize, (int __user *)arg)) | 252 | if (put_user(dev->hid->rsize, (int __user *)arg)) |
@@ -311,11 +315,11 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, | |||
311 | -EFAULT : len; | 315 | -EFAULT : len; |
312 | break; | 316 | break; |
313 | } | 317 | } |
314 | } | 318 | } |
315 | 319 | ||
316 | ret = -ENOTTY; | 320 | ret = -ENOTTY; |
317 | } | 321 | } |
318 | unlock_kernel(); | 322 | mutex_unlock(&minors_lock); |
319 | return ret; | 323 | return ret; |
320 | } | 324 | } |
321 | 325 | ||