diff options
Diffstat (limited to 'drivers/hid/hid-roccat.c')
-rw-r--r-- | drivers/hid/hid-roccat.c | 53 |
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index a14c579ea781..5666e7587b18 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c | |||
@@ -26,8 +26,7 @@ | |||
26 | #include <linux/cdev.h> | 26 | #include <linux/cdev.h> |
27 | #include <linux/poll.h> | 27 | #include <linux/poll.h> |
28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
29 | 29 | #include <linux/hid-roccat.h> | |
30 | #include "hid-roccat.h" | ||
31 | 30 | ||
32 | #define ROCCAT_FIRST_MINOR 0 | 31 | #define ROCCAT_FIRST_MINOR 0 |
33 | #define ROCCAT_MAX_DEVICES 8 | 32 | #define ROCCAT_MAX_DEVICES 8 |
@@ -37,11 +36,11 @@ | |||
37 | 36 | ||
38 | struct roccat_report { | 37 | struct roccat_report { |
39 | uint8_t *value; | 38 | uint8_t *value; |
40 | int len; | ||
41 | }; | 39 | }; |
42 | 40 | ||
43 | struct roccat_device { | 41 | struct roccat_device { |
44 | unsigned int minor; | 42 | unsigned int minor; |
43 | int report_size; | ||
45 | int open; | 44 | int open; |
46 | int exist; | 45 | int exist; |
47 | wait_queue_head_t wait; | 46 | wait_queue_head_t wait; |
@@ -123,7 +122,7 @@ static ssize_t roccat_read(struct file *file, char __user *buffer, | |||
123 | * If report is larger than requested amount of data, rest of report | 122 | * If report is larger than requested amount of data, rest of report |
124 | * is lost! | 123 | * is lost! |
125 | */ | 124 | */ |
126 | len = report->len > count ? count : report->len; | 125 | len = device->report_size > count ? count : device->report_size; |
127 | 126 | ||
128 | if (copy_to_user(buffer, report->value, len)) { | 127 | if (copy_to_user(buffer, report->value, len)) { |
129 | retval = -EFAULT; | 128 | retval = -EFAULT; |
@@ -248,26 +247,25 @@ static int roccat_release(struct inode *inode, struct file *file) | |||
248 | * | 247 | * |
249 | * This is called from interrupt handler. | 248 | * This is called from interrupt handler. |
250 | */ | 249 | */ |
251 | int roccat_report_event(int minor, u8 const *data, int len) | 250 | int roccat_report_event(int minor, u8 const *data) |
252 | { | 251 | { |
253 | struct roccat_device *device; | 252 | struct roccat_device *device; |
254 | struct roccat_reader *reader; | 253 | struct roccat_reader *reader; |
255 | struct roccat_report *report; | 254 | struct roccat_report *report; |
256 | uint8_t *new_value; | 255 | uint8_t *new_value; |
257 | 256 | ||
258 | new_value = kmemdup(data, len, GFP_ATOMIC); | 257 | device = devices[minor]; |
258 | |||
259 | new_value = kmemdup(data, device->report_size, GFP_ATOMIC); | ||
259 | if (!new_value) | 260 | if (!new_value) |
260 | return -ENOMEM; | 261 | return -ENOMEM; |
261 | 262 | ||
262 | device = devices[minor]; | ||
263 | |||
264 | report = &device->cbuf[device->cbuf_end]; | 263 | report = &device->cbuf[device->cbuf_end]; |
265 | 264 | ||
266 | /* passing NULL is safe */ | 265 | /* passing NULL is safe */ |
267 | kfree(report->value); | 266 | kfree(report->value); |
268 | 267 | ||
269 | report->value = new_value; | 268 | report->value = new_value; |
270 | report->len = len; | ||
271 | device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE; | 269 | device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE; |
272 | 270 | ||
273 | list_for_each_entry(reader, &device->readers, node) { | 271 | list_for_each_entry(reader, &device->readers, node) { |
@@ -295,7 +293,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event); | |||
295 | * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on | 293 | * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on |
296 | * success, a negative error code on failure. | 294 | * success, a negative error code on failure. |
297 | */ | 295 | */ |
298 | int roccat_connect(struct class *klass, struct hid_device *hid) | 296 | int roccat_connect(struct class *klass, struct hid_device *hid, int report_size) |
299 | { | 297 | { |
300 | unsigned int minor; | 298 | unsigned int minor; |
301 | struct roccat_device *device; | 299 | struct roccat_device *device; |
@@ -343,6 +341,7 @@ int roccat_connect(struct class *klass, struct hid_device *hid) | |||
343 | device->hid = hid; | 341 | device->hid = hid; |
344 | device->exist = 1; | 342 | device->exist = 1; |
345 | device->cbuf_end = 0; | 343 | device->cbuf_end = 0; |
344 | device->report_size = report_size; | ||
346 | 345 | ||
347 | return minor; | 346 | return minor; |
348 | } | 347 | } |
@@ -357,13 +356,16 @@ void roccat_disconnect(int minor) | |||
357 | 356 | ||
358 | mutex_lock(&devices_lock); | 357 | mutex_lock(&devices_lock); |
359 | device = devices[minor]; | 358 | device = devices[minor]; |
360 | devices[minor] = NULL; | ||
361 | mutex_unlock(&devices_lock); | 359 | mutex_unlock(&devices_lock); |
362 | 360 | ||
363 | device->exist = 0; /* TODO exist maybe not needed */ | 361 | device->exist = 0; /* TODO exist maybe not needed */ |
364 | 362 | ||
365 | device_destroy(device->dev->class, MKDEV(roccat_major, minor)); | 363 | device_destroy(device->dev->class, MKDEV(roccat_major, minor)); |
366 | 364 | ||
365 | mutex_lock(&devices_lock); | ||
366 | devices[minor] = NULL; | ||
367 | mutex_unlock(&devices_lock); | ||
368 | |||
367 | if (device->open) { | 369 | if (device->open) { |
368 | hid_hw_close(device->hid); | 370 | hid_hw_close(device->hid); |
369 | wake_up_interruptible(&device->wait); | 371 | wake_up_interruptible(&device->wait); |
@@ -373,6 +375,34 @@ void roccat_disconnect(int minor) | |||
373 | } | 375 | } |
374 | EXPORT_SYMBOL_GPL(roccat_disconnect); | 376 | EXPORT_SYMBOL_GPL(roccat_disconnect); |
375 | 377 | ||
378 | static long roccat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
379 | { | ||
380 | struct inode *inode = file->f_path.dentry->d_inode; | ||
381 | struct roccat_device *device; | ||
382 | unsigned int minor = iminor(inode); | ||
383 | long retval = 0; | ||
384 | |||
385 | mutex_lock(&devices_lock); | ||
386 | |||
387 | device = devices[minor]; | ||
388 | if (!device) { | ||
389 | retval = -ENODEV; | ||
390 | goto out; | ||
391 | } | ||
392 | |||
393 | switch (cmd) { | ||
394 | case ROCCATIOCGREPSIZE: | ||
395 | if (put_user(device->report_size, (int __user *)arg)) | ||
396 | retval = -EFAULT; | ||
397 | break; | ||
398 | default: | ||
399 | retval = -ENOTTY; | ||
400 | } | ||
401 | out: | ||
402 | mutex_unlock(&devices_lock); | ||
403 | return retval; | ||
404 | } | ||
405 | |||
376 | static const struct file_operations roccat_ops = { | 406 | static const struct file_operations roccat_ops = { |
377 | .owner = THIS_MODULE, | 407 | .owner = THIS_MODULE, |
378 | .read = roccat_read, | 408 | .read = roccat_read, |
@@ -380,6 +410,7 @@ static const struct file_operations roccat_ops = { | |||
380 | .open = roccat_open, | 410 | .open = roccat_open, |
381 | .release = roccat_release, | 411 | .release = roccat_release, |
382 | .llseek = noop_llseek, | 412 | .llseek = noop_llseek, |
413 | .unlocked_ioctl = roccat_ioctl, | ||
383 | }; | 414 | }; |
384 | 415 | ||
385 | static int __init roccat_init(void) | 416 | static int __init roccat_init(void) |