RDMA/ucma: Ensure that CM_ID exists prior to access it
[pandora-kernel.git] / drivers / hid / hid-roccat-kovaplus.c
1 /*
2  * Roccat Kova[+] driver for Linux
3  *
4  * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
5  */
6
7 /*
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  */
13
14 /*
15  * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons.
16  */
17
18 #include <linux/device.h>
19 #include <linux/input.h>
20 #include <linux/hid.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/hid-roccat.h>
24 #include "hid-ids.h"
25 #include "hid-roccat-common.h"
26 #include "hid-roccat-kovaplus.h"
27
28 static uint profile_numbers[5] = {0, 1, 2, 3, 4};
29
30 static struct class *kovaplus_class;
31
32 static uint kovaplus_convert_event_cpi(uint value)
33 {
34         return (value == 7 ? 4 : (value == 4 ? 3 : value));
35 }
36
37 static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
38                 uint new_profile_index)
39 {
40         if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings))
41                 return;
42         kovaplus->actual_profile = new_profile_index;
43         kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
44         kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
45         kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y;
46 }
47
48 static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
49                 enum kovaplus_control_requests request)
50 {
51         int retval;
52         struct kovaplus_control control;
53
54         if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
55                         request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
56                         value > 4)
57                 return -EINVAL;
58
59         control.command = KOVAPLUS_COMMAND_CONTROL;
60         control.value = value;
61         control.request = request;
62
63         retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL,
64                         &control, sizeof(struct kovaplus_control));
65
66         return retval;
67 }
68
69 static int kovaplus_receive_control_status(struct usb_device *usb_dev)
70 {
71         int retval;
72         struct kovaplus_control control;
73
74         do {
75                 retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL,
76                                 &control, sizeof(struct kovaplus_control));
77
78                 /* check if we get a completely wrong answer */
79                 if (retval)
80                         return retval;
81
82                 if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK)
83                         return 0;
84
85                 /* indicates that hardware needs some more time to complete action */
86                 if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) {
87                         msleep(500); /* windows driver uses 1000 */
88                         continue;
89                 }
90
91                 /* seems to be critical - replug necessary */
92                 if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
93                         return -EINVAL;
94
95                 hid_err(usb_dev, "roccat_common_receive_control_status: "
96                                 "unknown response value 0x%x\n", control.value);
97                 return -EINVAL;
98         } while (1);
99 }
100
101 static int kovaplus_send(struct usb_device *usb_dev, uint command,
102                 void const *buf, uint size)
103 {
104         int retval;
105
106         retval = roccat_common_send(usb_dev, command, buf, size);
107         if (retval)
108                 return retval;
109
110         msleep(100);
111
112         return kovaplus_receive_control_status(usb_dev);
113 }
114
115 static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
116                 enum kovaplus_control_requests request)
117 {
118         return kovaplus_send_control(usb_dev, number, request);
119 }
120
121 static int kovaplus_get_info(struct usb_device *usb_dev,
122                 struct kovaplus_info *buf)
123 {
124         return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO,
125                         buf, sizeof(struct kovaplus_info));
126 }
127
128 static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
129                 struct kovaplus_profile_settings *buf, uint number)
130 {
131         int retval;
132
133         retval = kovaplus_select_profile(usb_dev, number,
134                         KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
135         if (retval)
136                 return retval;
137
138         return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
139                         buf, sizeof(struct kovaplus_profile_settings));
140 }
141
142 static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
143                 struct kovaplus_profile_settings const *settings)
144 {
145         return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS,
146                         settings, sizeof(struct kovaplus_profile_settings));
147 }
148
149 static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
150                 struct kovaplus_profile_buttons *buf, int number)
151 {
152         int retval;
153
154         retval = kovaplus_select_profile(usb_dev, number,
155                         KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
156         if (retval)
157                 return retval;
158
159         return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
160                         buf, sizeof(struct kovaplus_profile_buttons));
161 }
162
163 static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
164                 struct kovaplus_profile_buttons const *buttons)
165 {
166         return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS,
167                         buttons, sizeof(struct kovaplus_profile_buttons));
168 }
169
170 /* retval is 0-4 on success, < 0 on error */
171 static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
172 {
173         struct kovaplus_actual_profile buf;
174         int retval;
175
176         retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE,
177                         &buf, sizeof(struct kovaplus_actual_profile));
178
179         return retval ? retval : buf.actual_profile;
180 }
181
182 static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
183                 int new_profile)
184 {
185         struct kovaplus_actual_profile buf;
186
187         buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE;
188         buf.size = sizeof(struct kovaplus_actual_profile);
189         buf.actual_profile = new_profile;
190
191         return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE,
192                         &buf, sizeof(struct kovaplus_actual_profile));
193 }
194
195 static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
196                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
197                 loff_t off, size_t count)
198 {
199         struct device *dev =
200                         container_of(kobj, struct device, kobj)->parent->parent;
201         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
202
203         if (off >= sizeof(struct kovaplus_profile_settings))
204                 return 0;
205
206         if (off + count > sizeof(struct kovaplus_profile_settings))
207                 count = sizeof(struct kovaplus_profile_settings) - off;
208
209         mutex_lock(&kovaplus->kovaplus_lock);
210         memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off,
211                         count);
212         mutex_unlock(&kovaplus->kovaplus_lock);
213
214         return count;
215 }
216
217 static ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp,
218                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
219                 loff_t off, size_t count)
220 {
221         struct device *dev =
222                         container_of(kobj, struct device, kobj)->parent->parent;
223         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
224         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
225         int retval = 0;
226         int difference;
227         int profile_index;
228         struct kovaplus_profile_settings *profile_settings;
229
230         if (off != 0 || count != sizeof(struct kovaplus_profile_settings))
231                 return -EINVAL;
232
233         profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index;
234         profile_settings = &kovaplus->profile_settings[profile_index];
235
236         mutex_lock(&kovaplus->kovaplus_lock);
237         difference = memcmp(buf, profile_settings,
238                         sizeof(struct kovaplus_profile_settings));
239         if (difference) {
240                 retval = kovaplus_set_profile_settings(usb_dev,
241                                 (struct kovaplus_profile_settings const *)buf);
242                 if (!retval)
243                         memcpy(profile_settings, buf,
244                                         sizeof(struct kovaplus_profile_settings));
245         }
246         mutex_unlock(&kovaplus->kovaplus_lock);
247
248         if (retval)
249                 return retval;
250
251         return sizeof(struct kovaplus_profile_settings);
252 }
253
254 static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
255                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
256                 loff_t off, size_t count)
257 {
258         struct device *dev =
259                         container_of(kobj, struct device, kobj)->parent->parent;
260         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
261
262         if (off >= sizeof(struct kovaplus_profile_buttons))
263                 return 0;
264
265         if (off + count > sizeof(struct kovaplus_profile_buttons))
266                 count = sizeof(struct kovaplus_profile_buttons) - off;
267
268         mutex_lock(&kovaplus->kovaplus_lock);
269         memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off,
270                         count);
271         mutex_unlock(&kovaplus->kovaplus_lock);
272
273         return count;
274 }
275
276 static ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp,
277                 struct kobject *kobj, struct bin_attribute *attr, char *buf,
278                 loff_t off, size_t count)
279 {
280         struct device *dev =
281                         container_of(kobj, struct device, kobj)->parent->parent;
282         struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
283         struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
284         int retval = 0;
285         int difference;
286         uint profile_index;
287         struct kovaplus_profile_buttons *profile_buttons;
288
289         if (off != 0 || count != sizeof(struct kovaplus_profile_buttons))
290                 return -EINVAL;
291
292         profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index;
293         profile_buttons = &kovaplus->profile_buttons[profile_index];
294
295         mutex_lock(&kovaplus->kovaplus_lock);
296         difference = memcmp(buf, profile_buttons,
297                         sizeof(struct kovaplus_profile_buttons));
298         if (difference) {
299                 retval = kovaplus_set_profile_buttons(usb_dev,
300                                 (struct kovaplus_profile_buttons const *)buf);
301                 if (!retval)
302                         memcpy(profile_buttons, buf,
303                                         sizeof(struct kovaplus_profile_buttons));
304         }
305         mutex_unlock(&kovaplus->kovaplus_lock);
306
307         if (retval)
308                 return retval;
309
310         return sizeof(struct kovaplus_profile_buttons);
311 }
312
313 static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
314                 struct device_attribute *attr, char *buf)
315 {
316         struct kovaplus_device *kovaplus =
317                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
318         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile);
319 }
320
321 static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
322                 struct device_attribute *attr, char const *buf, size_t size)
323 {
324         struct kovaplus_device *kovaplus;
325         struct usb_device *usb_dev;
326         unsigned long profile;
327         int retval;
328         struct kovaplus_roccat_report roccat_report;
329
330         dev = dev->parent->parent;
331         kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
332         usb_dev = interface_to_usbdev(to_usb_interface(dev));
333
334         retval = strict_strtoul(buf, 10, &profile);
335         if (retval)
336                 return retval;
337
338         if (profile >= 5)
339                 return -EINVAL;
340
341         mutex_lock(&kovaplus->kovaplus_lock);
342         retval = kovaplus_set_actual_profile(usb_dev, profile);
343         if (retval) {
344                 mutex_unlock(&kovaplus->kovaplus_lock);
345                 return retval;
346         }
347
348         kovaplus_profile_activated(kovaplus, profile);
349
350         roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1;
351         roccat_report.profile = profile + 1;
352         roccat_report.button = 0;
353         roccat_report.data1 = profile + 1;
354         roccat_report.data2 = 0;
355         roccat_report_event(kovaplus->chrdev_minor,
356                         (uint8_t const *)&roccat_report);
357
358         mutex_unlock(&kovaplus->kovaplus_lock);
359
360         return size;
361 }
362
363 static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
364                 struct device_attribute *attr, char *buf)
365 {
366         struct kovaplus_device *kovaplus =
367                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
368         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
369 }
370
371 static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
372                 struct device_attribute *attr, char *buf)
373 {
374         struct kovaplus_device *kovaplus =
375                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
376         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
377 }
378
379 static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
380                 struct device_attribute *attr, char *buf)
381 {
382         struct kovaplus_device *kovaplus =
383                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
384         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
385 }
386
387 static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
388                 struct device_attribute *attr, char *buf)
389 {
390         struct kovaplus_device *kovaplus =
391                         hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
392         return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version);
393 }
394
395 static struct device_attribute kovaplus_attributes[] = {
396         __ATTR(actual_cpi, 0440,
397                 kovaplus_sysfs_show_actual_cpi, NULL),
398         __ATTR(firmware_version, 0440,
399                 kovaplus_sysfs_show_firmware_version, NULL),
400         __ATTR(actual_profile, 0660,
401                 kovaplus_sysfs_show_actual_profile,
402                 kovaplus_sysfs_set_actual_profile),
403         __ATTR(actual_sensitivity_x, 0440,
404                 kovaplus_sysfs_show_actual_sensitivity_x, NULL),
405         __ATTR(actual_sensitivity_y, 0440,
406                 kovaplus_sysfs_show_actual_sensitivity_y, NULL),
407         __ATTR_NULL
408 };
409
410 static struct bin_attribute kovaplus_bin_attributes[] = {
411         {
412                 .attr = { .name = "profile_settings", .mode = 0220 },
413                 .size = sizeof(struct kovaplus_profile_settings),
414                 .write = kovaplus_sysfs_write_profile_settings
415         },
416         {
417                 .attr = { .name = "profile1_settings", .mode = 0440 },
418                 .size = sizeof(struct kovaplus_profile_settings),
419                 .read = kovaplus_sysfs_read_profilex_settings,
420                 .private = &profile_numbers[0]
421         },
422         {
423                 .attr = { .name = "profile2_settings", .mode = 0440 },
424                 .size = sizeof(struct kovaplus_profile_settings),
425                 .read = kovaplus_sysfs_read_profilex_settings,
426                 .private = &profile_numbers[1]
427         },
428         {
429                 .attr = { .name = "profile3_settings", .mode = 0440 },
430                 .size = sizeof(struct kovaplus_profile_settings),
431                 .read = kovaplus_sysfs_read_profilex_settings,
432                 .private = &profile_numbers[2]
433         },
434         {
435                 .attr = { .name = "profile4_settings", .mode = 0440 },
436                 .size = sizeof(struct kovaplus_profile_settings),
437                 .read = kovaplus_sysfs_read_profilex_settings,
438                 .private = &profile_numbers[3]
439         },
440         {
441                 .attr = { .name = "profile5_settings", .mode = 0440 },
442                 .size = sizeof(struct kovaplus_profile_settings),
443                 .read = kovaplus_sysfs_read_profilex_settings,
444                 .private = &profile_numbers[4]
445         },
446         {
447                 .attr = { .name = "profile_buttons", .mode = 0220 },
448                 .size = sizeof(struct kovaplus_profile_buttons),
449                 .write = kovaplus_sysfs_write_profile_buttons
450         },
451         {
452                 .attr = { .name = "profile1_buttons", .mode = 0440 },
453                 .size = sizeof(struct kovaplus_profile_buttons),
454                 .read = kovaplus_sysfs_read_profilex_buttons,
455                 .private = &profile_numbers[0]
456         },
457         {
458                 .attr = { .name = "profile2_buttons", .mode = 0440 },
459                 .size = sizeof(struct kovaplus_profile_buttons),
460                 .read = kovaplus_sysfs_read_profilex_buttons,
461                 .private = &profile_numbers[1]
462         },
463         {
464                 .attr = { .name = "profile3_buttons", .mode = 0440 },
465                 .size = sizeof(struct kovaplus_profile_buttons),
466                 .read = kovaplus_sysfs_read_profilex_buttons,
467                 .private = &profile_numbers[2]
468         },
469         {
470                 .attr = { .name = "profile4_buttons", .mode = 0440 },
471                 .size = sizeof(struct kovaplus_profile_buttons),
472                 .read = kovaplus_sysfs_read_profilex_buttons,
473                 .private = &profile_numbers[3]
474         },
475         {
476                 .attr = { .name = "profile5_buttons", .mode = 0440 },
477                 .size = sizeof(struct kovaplus_profile_buttons),
478                 .read = kovaplus_sysfs_read_profilex_buttons,
479                 .private = &profile_numbers[4]
480         },
481         __ATTR_NULL
482 };
483
484 static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
485                 struct kovaplus_device *kovaplus)
486 {
487         int retval, i;
488         static uint wait = 70; /* device will freeze with just 60 */
489
490         mutex_init(&kovaplus->kovaplus_lock);
491
492         retval = kovaplus_get_info(usb_dev, &kovaplus->info);
493         if (retval)
494                 return retval;
495
496         for (i = 0; i < 5; ++i) {
497                 msleep(wait);
498                 retval = kovaplus_get_profile_settings(usb_dev,
499                                 &kovaplus->profile_settings[i], i);
500                 if (retval)
501                         return retval;
502
503                 msleep(wait);
504                 retval = kovaplus_get_profile_buttons(usb_dev,
505                                 &kovaplus->profile_buttons[i], i);
506                 if (retval)
507                         return retval;
508         }
509
510         msleep(wait);
511         retval = kovaplus_get_actual_profile(usb_dev);
512         if (retval < 0)
513                 return retval;
514         kovaplus_profile_activated(kovaplus, retval);
515
516         return 0;
517 }
518
519 static int kovaplus_init_specials(struct hid_device *hdev)
520 {
521         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
522         struct usb_device *usb_dev = interface_to_usbdev(intf);
523         struct kovaplus_device *kovaplus;
524         int retval;
525
526         if (intf->cur_altsetting->desc.bInterfaceProtocol
527                         == USB_INTERFACE_PROTOCOL_MOUSE) {
528
529                 kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL);
530                 if (!kovaplus) {
531                         hid_err(hdev, "can't alloc device descriptor\n");
532                         return -ENOMEM;
533                 }
534                 hid_set_drvdata(hdev, kovaplus);
535
536                 retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus);
537                 if (retval) {
538                         hid_err(hdev, "couldn't init struct kovaplus_device\n");
539                         goto exit_free;
540                 }
541
542                 retval = roccat_connect(kovaplus_class, hdev,
543                                 sizeof(struct kovaplus_roccat_report));
544                 if (retval < 0) {
545                         hid_err(hdev, "couldn't init char dev\n");
546                 } else {
547                         kovaplus->chrdev_minor = retval;
548                         kovaplus->roccat_claimed = 1;
549                 }
550
551         } else {
552                 hid_set_drvdata(hdev, NULL);
553         }
554
555         return 0;
556 exit_free:
557         kfree(kovaplus);
558         return retval;
559 }
560
561 static void kovaplus_remove_specials(struct hid_device *hdev)
562 {
563         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
564         struct kovaplus_device *kovaplus;
565
566         if (intf->cur_altsetting->desc.bInterfaceProtocol
567                         == USB_INTERFACE_PROTOCOL_MOUSE) {
568                 kovaplus = hid_get_drvdata(hdev);
569                 if (kovaplus->roccat_claimed)
570                         roccat_disconnect(kovaplus->chrdev_minor);
571                 kfree(kovaplus);
572         }
573 }
574
575 static int kovaplus_probe(struct hid_device *hdev,
576                 const struct hid_device_id *id)
577 {
578         int retval;
579
580         retval = hid_parse(hdev);
581         if (retval) {
582                 hid_err(hdev, "parse failed\n");
583                 goto exit;
584         }
585
586         retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
587         if (retval) {
588                 hid_err(hdev, "hw start failed\n");
589                 goto exit;
590         }
591
592         retval = kovaplus_init_specials(hdev);
593         if (retval) {
594                 hid_err(hdev, "couldn't install mouse\n");
595                 goto exit_stop;
596         }
597
598         return 0;
599
600 exit_stop:
601         hid_hw_stop(hdev);
602 exit:
603         return retval;
604 }
605
606 static void kovaplus_remove(struct hid_device *hdev)
607 {
608         kovaplus_remove_specials(hdev);
609         hid_hw_stop(hdev);
610 }
611
612 static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
613                 u8 const *data)
614 {
615         struct kovaplus_mouse_report_button const *button_report;
616
617         if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
618                 return;
619
620         button_report = (struct kovaplus_mouse_report_button const *)data;
621
622         switch (button_report->type) {
623         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1:
624                 kovaplus_profile_activated(kovaplus, button_report->data1 - 1);
625                 break;
626         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
627                 kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
628         case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
629                 kovaplus->actual_x_sensitivity = button_report->data1;
630                 kovaplus->actual_y_sensitivity = button_report->data2;
631         }
632 }
633
634 static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus,
635                 u8 const *data)
636 {
637         struct kovaplus_roccat_report roccat_report;
638         struct kovaplus_mouse_report_button const *button_report;
639
640         if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
641                 return;
642
643         button_report = (struct kovaplus_mouse_report_button const *)data;
644
645         if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2)
646                 return;
647
648         roccat_report.type = button_report->type;
649         roccat_report.profile = kovaplus->actual_profile + 1;
650
651         if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO ||
652                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT ||
653                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
654                         roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER)
655                 roccat_report.button = button_report->data1;
656         else
657                 roccat_report.button = 0;
658
659         if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI)
660                 roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1);
661         else
662                 roccat_report.data1 = button_report->data1;
663
664         roccat_report.data2 = button_report->data2;
665
666         roccat_report_event(kovaplus->chrdev_minor,
667                         (uint8_t const *)&roccat_report);
668 }
669
670 static int kovaplus_raw_event(struct hid_device *hdev,
671                 struct hid_report *report, u8 *data, int size)
672 {
673         struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
674         struct kovaplus_device *kovaplus = hid_get_drvdata(hdev);
675
676         if (intf->cur_altsetting->desc.bInterfaceProtocol
677                         != USB_INTERFACE_PROTOCOL_MOUSE)
678                 return 0;
679
680         if (kovaplus == NULL)
681                 return 0;
682
683         kovaplus_keep_values_up_to_date(kovaplus, data);
684
685         if (kovaplus->roccat_claimed)
686                 kovaplus_report_to_chrdev(kovaplus, data);
687
688         return 0;
689 }
690
691 static const struct hid_device_id kovaplus_devices[] = {
692         { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
693         { }
694 };
695
696 MODULE_DEVICE_TABLE(hid, kovaplus_devices);
697
698 static struct hid_driver kovaplus_driver = {
699                 .name = "kovaplus",
700                 .id_table = kovaplus_devices,
701                 .probe = kovaplus_probe,
702                 .remove = kovaplus_remove,
703                 .raw_event = kovaplus_raw_event
704 };
705
706 static int __init kovaplus_init(void)
707 {
708         int retval;
709
710         kovaplus_class = class_create(THIS_MODULE, "kovaplus");
711         if (IS_ERR(kovaplus_class))
712                 return PTR_ERR(kovaplus_class);
713         kovaplus_class->dev_attrs = kovaplus_attributes;
714         kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
715
716         retval = hid_register_driver(&kovaplus_driver);
717         if (retval)
718                 class_destroy(kovaplus_class);
719         return retval;
720 }
721
722 static void __exit kovaplus_exit(void)
723 {
724         hid_unregister_driver(&kovaplus_driver);
725         class_destroy(kovaplus_class);
726 }
727
728 module_init(kovaplus_init);
729 module_exit(kovaplus_exit);
730
731 MODULE_AUTHOR("Stefan Achatz");
732 MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
733 MODULE_LICENSE("GPL v2");