aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-roccat.c
diff options
context:
space:
mode:
authorStefan Achatz <erazor_de@users.sourceforge.net>2011-01-30 07:38:25 -0500
committerJiri Kosina <jkosina@suse.cz>2011-02-03 10:37:28 -0500
commit8211e46004518c977f70f2661da961d5ba617399 (patch)
treeb2ae1cdc75fad9dbdece7b1dd5fc23ce0624f3c2 /drivers/hid/hid-roccat.c
parent432762e28b8146d0feff61cc8063b26c517acf26 (diff)
HID: roccat: Add ioctl command to retreive report size from chardev
Roccat chardev was reworked to support only a defined report size per device and this can be retreived by an ioctl now to enable future changes in report definitions. Header was moved/renamed from drivers/hid to include/linux for accessibility. Signed-off-by: Stefan Achatz <erazor_de@users.sourceforge.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-roccat.c')
-rw-r--r--drivers/hid/hid-roccat.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index a14c579ea781..0fa23dead5e1 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/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
38struct roccat_report { 37struct roccat_report {
39 uint8_t *value; 38 uint8_t *value;
40 int len;
41}; 39};
42 40
43struct roccat_device { 41struct 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 */
251int roccat_report_event(int minor, u8 const *data, int len) 250int 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 */
298int roccat_connect(struct class *klass, struct hid_device *hid) 296int 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}
@@ -373,6 +372,34 @@ void roccat_disconnect(int minor)
373} 372}
374EXPORT_SYMBOL_GPL(roccat_disconnect); 373EXPORT_SYMBOL_GPL(roccat_disconnect);
375 374
375static long roccat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
376{
377 struct inode *inode = file->f_path.dentry->d_inode;
378 struct roccat_device *device;
379 unsigned int minor = iminor(inode);
380 long retval = 0;
381
382 mutex_lock(&devices_lock);
383
384 device = devices[minor];
385 if (!device) {
386 retval = -ENODEV;
387 goto out;
388 }
389
390 switch (cmd) {
391 case ROCCATIOCGREPSIZE:
392 if (put_user(device->report_size, (int __user *)arg))
393 retval = -EFAULT;
394 break;
395 default:
396 retval = -ENOTTY;
397 }
398out:
399 mutex_unlock(&devices_lock);
400 return retval;
401}
402
376static const struct file_operations roccat_ops = { 403static const struct file_operations roccat_ops = {
377 .owner = THIS_MODULE, 404 .owner = THIS_MODULE,
378 .read = roccat_read, 405 .read = roccat_read,
@@ -380,6 +407,7 @@ static const struct file_operations roccat_ops = {
380 .open = roccat_open, 407 .open = roccat_open,
381 .release = roccat_release, 408 .release = roccat_release,
382 .llseek = noop_llseek, 409 .llseek = noop_llseek,
410 .unlocked_ioctl = roccat_ioctl,
383}; 411};
384 412
385static int __init roccat_init(void) 413static int __init roccat_init(void)