2 * Roccat Kova[+] driver for Linux
4 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
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)
15 * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons.
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>
25 #include "hid-roccat-common.h"
26 #include "hid-roccat-kovaplus.h"
28 static uint profile_numbers
[5] = {0, 1, 2, 3, 4};
30 static struct class *kovaplus_class
;
32 static uint
kovaplus_convert_event_cpi(uint value
)
34 return (value
== 7 ? 4 : (value
== 4 ? 3 : value
));
37 static void kovaplus_profile_activated(struct kovaplus_device
*kovaplus
,
38 uint new_profile_index
)
40 kovaplus
->actual_profile
= new_profile_index
;
41 kovaplus
->actual_cpi
= kovaplus
->profile_settings
[new_profile_index
].cpi_startup_level
;
42 kovaplus
->actual_x_sensitivity
= kovaplus
->profile_settings
[new_profile_index
].sensitivity_x
;
43 kovaplus
->actual_y_sensitivity
= kovaplus
->profile_settings
[new_profile_index
].sensitivity_y
;
46 static int kovaplus_send_control(struct usb_device
*usb_dev
, uint value
,
47 enum kovaplus_control_requests request
)
50 struct kovaplus_control control
;
52 if ((request
== KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS
||
53 request
== KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS
) &&
57 control
.command
= KOVAPLUS_COMMAND_CONTROL
;
58 control
.value
= value
;
59 control
.request
= request
;
61 retval
= roccat_common_send(usb_dev
, KOVAPLUS_COMMAND_CONTROL
,
62 &control
, sizeof(struct kovaplus_control
));
67 static int kovaplus_receive_control_status(struct usb_device
*usb_dev
)
70 struct kovaplus_control control
;
73 retval
= roccat_common_receive(usb_dev
, KOVAPLUS_COMMAND_CONTROL
,
74 &control
, sizeof(struct kovaplus_control
));
76 /* check if we get a completely wrong answer */
80 if (control
.value
== KOVAPLUS_CONTROL_REQUEST_STATUS_OK
)
83 /* indicates that hardware needs some more time to complete action */
84 if (control
.value
== KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT
) {
85 msleep(500); /* windows driver uses 1000 */
89 /* seems to be critical - replug necessary */
90 if (control
.value
== KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD
)
93 hid_err(usb_dev
, "roccat_common_receive_control_status: "
94 "unknown response value 0x%x\n", control
.value
);
99 static int kovaplus_send(struct usb_device
*usb_dev
, uint command
,
100 void const *buf
, uint size
)
104 retval
= roccat_common_send(usb_dev
, command
, buf
, size
);
110 return kovaplus_receive_control_status(usb_dev
);
113 static int kovaplus_select_profile(struct usb_device
*usb_dev
, uint number
,
114 enum kovaplus_control_requests request
)
116 return kovaplus_send_control(usb_dev
, number
, request
);
119 static int kovaplus_get_info(struct usb_device
*usb_dev
,
120 struct kovaplus_info
*buf
)
122 return roccat_common_receive(usb_dev
, KOVAPLUS_COMMAND_INFO
,
123 buf
, sizeof(struct kovaplus_info
));
126 static int kovaplus_get_profile_settings(struct usb_device
*usb_dev
,
127 struct kovaplus_profile_settings
*buf
, uint number
)
131 retval
= kovaplus_select_profile(usb_dev
, number
,
132 KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS
);
136 return roccat_common_receive(usb_dev
, KOVAPLUS_COMMAND_PROFILE_SETTINGS
,
137 buf
, sizeof(struct kovaplus_profile_settings
));
140 static int kovaplus_set_profile_settings(struct usb_device
*usb_dev
,
141 struct kovaplus_profile_settings
const *settings
)
143 return kovaplus_send(usb_dev
, KOVAPLUS_COMMAND_PROFILE_SETTINGS
,
144 settings
, sizeof(struct kovaplus_profile_settings
));
147 static int kovaplus_get_profile_buttons(struct usb_device
*usb_dev
,
148 struct kovaplus_profile_buttons
*buf
, int number
)
152 retval
= kovaplus_select_profile(usb_dev
, number
,
153 KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS
);
157 return roccat_common_receive(usb_dev
, KOVAPLUS_COMMAND_PROFILE_BUTTONS
,
158 buf
, sizeof(struct kovaplus_profile_buttons
));
161 static int kovaplus_set_profile_buttons(struct usb_device
*usb_dev
,
162 struct kovaplus_profile_buttons
const *buttons
)
164 return kovaplus_send(usb_dev
, KOVAPLUS_COMMAND_PROFILE_BUTTONS
,
165 buttons
, sizeof(struct kovaplus_profile_buttons
));
168 /* retval is 0-4 on success, < 0 on error */
169 static int kovaplus_get_actual_profile(struct usb_device
*usb_dev
)
171 struct kovaplus_actual_profile buf
;
174 retval
= roccat_common_receive(usb_dev
, KOVAPLUS_COMMAND_ACTUAL_PROFILE
,
175 &buf
, sizeof(struct kovaplus_actual_profile
));
177 return retval
? retval
: buf
.actual_profile
;
180 static int kovaplus_set_actual_profile(struct usb_device
*usb_dev
,
183 struct kovaplus_actual_profile buf
;
185 buf
.command
= KOVAPLUS_COMMAND_ACTUAL_PROFILE
;
186 buf
.size
= sizeof(struct kovaplus_actual_profile
);
187 buf
.actual_profile
= new_profile
;
189 return kovaplus_send(usb_dev
, KOVAPLUS_COMMAND_ACTUAL_PROFILE
,
190 &buf
, sizeof(struct kovaplus_actual_profile
));
193 static ssize_t
kovaplus_sysfs_read_profilex_settings(struct file
*fp
,
194 struct kobject
*kobj
, struct bin_attribute
*attr
, char *buf
,
195 loff_t off
, size_t count
)
198 container_of(kobj
, struct device
, kobj
)->parent
->parent
;
199 struct kovaplus_device
*kovaplus
= hid_get_drvdata(dev_get_drvdata(dev
));
201 if (off
>= sizeof(struct kovaplus_profile_settings
))
204 if (off
+ count
> sizeof(struct kovaplus_profile_settings
))
205 count
= sizeof(struct kovaplus_profile_settings
) - off
;
207 mutex_lock(&kovaplus
->kovaplus_lock
);
208 memcpy(buf
, ((char const *)&kovaplus
->profile_settings
[*(uint
*)(attr
->private)]) + off
,
210 mutex_unlock(&kovaplus
->kovaplus_lock
);
215 static ssize_t
kovaplus_sysfs_write_profile_settings(struct file
*fp
,
216 struct kobject
*kobj
, struct bin_attribute
*attr
, char *buf
,
217 loff_t off
, size_t count
)
220 container_of(kobj
, struct device
, kobj
)->parent
->parent
;
221 struct kovaplus_device
*kovaplus
= hid_get_drvdata(dev_get_drvdata(dev
));
222 struct usb_device
*usb_dev
= interface_to_usbdev(to_usb_interface(dev
));
226 struct kovaplus_profile_settings
*profile_settings
;
228 if (off
!= 0 || count
!= sizeof(struct kovaplus_profile_settings
))
231 profile_index
= ((struct kovaplus_profile_settings
const *)buf
)->profile_index
;
232 profile_settings
= &kovaplus
->profile_settings
[profile_index
];
234 mutex_lock(&kovaplus
->kovaplus_lock
);
235 difference
= memcmp(buf
, profile_settings
,
236 sizeof(struct kovaplus_profile_settings
));
238 retval
= kovaplus_set_profile_settings(usb_dev
,
239 (struct kovaplus_profile_settings
const *)buf
);
241 memcpy(profile_settings
, buf
,
242 sizeof(struct kovaplus_profile_settings
));
244 mutex_unlock(&kovaplus
->kovaplus_lock
);
249 return sizeof(struct kovaplus_profile_settings
);
252 static ssize_t
kovaplus_sysfs_read_profilex_buttons(struct file
*fp
,
253 struct kobject
*kobj
, struct bin_attribute
*attr
, char *buf
,
254 loff_t off
, size_t count
)
257 container_of(kobj
, struct device
, kobj
)->parent
->parent
;
258 struct kovaplus_device
*kovaplus
= hid_get_drvdata(dev_get_drvdata(dev
));
260 if (off
>= sizeof(struct kovaplus_profile_buttons
))
263 if (off
+ count
> sizeof(struct kovaplus_profile_buttons
))
264 count
= sizeof(struct kovaplus_profile_buttons
) - off
;
266 mutex_lock(&kovaplus
->kovaplus_lock
);
267 memcpy(buf
, ((char const *)&kovaplus
->profile_buttons
[*(uint
*)(attr
->private)]) + off
,
269 mutex_unlock(&kovaplus
->kovaplus_lock
);
274 static ssize_t
kovaplus_sysfs_write_profile_buttons(struct file
*fp
,
275 struct kobject
*kobj
, struct bin_attribute
*attr
, char *buf
,
276 loff_t off
, size_t count
)
279 container_of(kobj
, struct device
, kobj
)->parent
->parent
;
280 struct kovaplus_device
*kovaplus
= hid_get_drvdata(dev_get_drvdata(dev
));
281 struct usb_device
*usb_dev
= interface_to_usbdev(to_usb_interface(dev
));
285 struct kovaplus_profile_buttons
*profile_buttons
;
287 if (off
!= 0 || count
!= sizeof(struct kovaplus_profile_buttons
))
290 profile_index
= ((struct kovaplus_profile_buttons
const *)buf
)->profile_index
;
291 profile_buttons
= &kovaplus
->profile_buttons
[profile_index
];
293 mutex_lock(&kovaplus
->kovaplus_lock
);
294 difference
= memcmp(buf
, profile_buttons
,
295 sizeof(struct kovaplus_profile_buttons
));
297 retval
= kovaplus_set_profile_buttons(usb_dev
,
298 (struct kovaplus_profile_buttons
const *)buf
);
300 memcpy(profile_buttons
, buf
,
301 sizeof(struct kovaplus_profile_buttons
));
303 mutex_unlock(&kovaplus
->kovaplus_lock
);
308 return sizeof(struct kovaplus_profile_buttons
);
311 static ssize_t
kovaplus_sysfs_show_actual_profile(struct device
*dev
,
312 struct device_attribute
*attr
, char *buf
)
314 struct kovaplus_device
*kovaplus
=
315 hid_get_drvdata(dev_get_drvdata(dev
->parent
->parent
));
316 return snprintf(buf
, PAGE_SIZE
, "%d\n", kovaplus
->actual_profile
);
319 static ssize_t
kovaplus_sysfs_set_actual_profile(struct device
*dev
,
320 struct device_attribute
*attr
, char const *buf
, size_t size
)
322 struct kovaplus_device
*kovaplus
;
323 struct usb_device
*usb_dev
;
324 unsigned long profile
;
326 struct kovaplus_roccat_report roccat_report
;
328 dev
= dev
->parent
->parent
;
329 kovaplus
= hid_get_drvdata(dev_get_drvdata(dev
));
330 usb_dev
= interface_to_usbdev(to_usb_interface(dev
));
332 retval
= strict_strtoul(buf
, 10, &profile
);
339 mutex_lock(&kovaplus
->kovaplus_lock
);
340 retval
= kovaplus_set_actual_profile(usb_dev
, profile
);
342 mutex_unlock(&kovaplus
->kovaplus_lock
);
346 kovaplus_profile_activated(kovaplus
, profile
);
348 roccat_report
.type
= KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1
;
349 roccat_report
.profile
= profile
+ 1;
350 roccat_report
.button
= 0;
351 roccat_report
.data1
= profile
+ 1;
352 roccat_report
.data2
= 0;
353 roccat_report_event(kovaplus
->chrdev_minor
,
354 (uint8_t const *)&roccat_report
);
356 mutex_unlock(&kovaplus
->kovaplus_lock
);
361 static ssize_t
kovaplus_sysfs_show_actual_cpi(struct device
*dev
,
362 struct device_attribute
*attr
, char *buf
)
364 struct kovaplus_device
*kovaplus
=
365 hid_get_drvdata(dev_get_drvdata(dev
->parent
->parent
));
366 return snprintf(buf
, PAGE_SIZE
, "%d\n", kovaplus
->actual_cpi
);
369 static ssize_t
kovaplus_sysfs_show_actual_sensitivity_x(struct device
*dev
,
370 struct device_attribute
*attr
, char *buf
)
372 struct kovaplus_device
*kovaplus
=
373 hid_get_drvdata(dev_get_drvdata(dev
->parent
->parent
));
374 return snprintf(buf
, PAGE_SIZE
, "%d\n", kovaplus
->actual_x_sensitivity
);
377 static ssize_t
kovaplus_sysfs_show_actual_sensitivity_y(struct device
*dev
,
378 struct device_attribute
*attr
, char *buf
)
380 struct kovaplus_device
*kovaplus
=
381 hid_get_drvdata(dev_get_drvdata(dev
->parent
->parent
));
382 return snprintf(buf
, PAGE_SIZE
, "%d\n", kovaplus
->actual_y_sensitivity
);
385 static ssize_t
kovaplus_sysfs_show_firmware_version(struct device
*dev
,
386 struct device_attribute
*attr
, char *buf
)
388 struct kovaplus_device
*kovaplus
=
389 hid_get_drvdata(dev_get_drvdata(dev
->parent
->parent
));
390 return snprintf(buf
, PAGE_SIZE
, "%d\n", kovaplus
->info
.firmware_version
);
393 static struct device_attribute kovaplus_attributes
[] = {
394 __ATTR(actual_cpi
, 0440,
395 kovaplus_sysfs_show_actual_cpi
, NULL
),
396 __ATTR(firmware_version
, 0440,
397 kovaplus_sysfs_show_firmware_version
, NULL
),
398 __ATTR(actual_profile
, 0660,
399 kovaplus_sysfs_show_actual_profile
,
400 kovaplus_sysfs_set_actual_profile
),
401 __ATTR(actual_sensitivity_x
, 0440,
402 kovaplus_sysfs_show_actual_sensitivity_x
, NULL
),
403 __ATTR(actual_sensitivity_y
, 0440,
404 kovaplus_sysfs_show_actual_sensitivity_y
, NULL
),
408 static struct bin_attribute kovaplus_bin_attributes
[] = {
410 .attr
= { .name
= "profile_settings", .mode
= 0220 },
411 .size
= sizeof(struct kovaplus_profile_settings
),
412 .write
= kovaplus_sysfs_write_profile_settings
415 .attr
= { .name
= "profile1_settings", .mode
= 0440 },
416 .size
= sizeof(struct kovaplus_profile_settings
),
417 .read
= kovaplus_sysfs_read_profilex_settings
,
418 .private = &profile_numbers
[0]
421 .attr
= { .name
= "profile2_settings", .mode
= 0440 },
422 .size
= sizeof(struct kovaplus_profile_settings
),
423 .read
= kovaplus_sysfs_read_profilex_settings
,
424 .private = &profile_numbers
[1]
427 .attr
= { .name
= "profile3_settings", .mode
= 0440 },
428 .size
= sizeof(struct kovaplus_profile_settings
),
429 .read
= kovaplus_sysfs_read_profilex_settings
,
430 .private = &profile_numbers
[2]
433 .attr
= { .name
= "profile4_settings", .mode
= 0440 },
434 .size
= sizeof(struct kovaplus_profile_settings
),
435 .read
= kovaplus_sysfs_read_profilex_settings
,
436 .private = &profile_numbers
[3]
439 .attr
= { .name
= "profile5_settings", .mode
= 0440 },
440 .size
= sizeof(struct kovaplus_profile_settings
),
441 .read
= kovaplus_sysfs_read_profilex_settings
,
442 .private = &profile_numbers
[4]
445 .attr
= { .name
= "profile_buttons", .mode
= 0220 },
446 .size
= sizeof(struct kovaplus_profile_buttons
),
447 .write
= kovaplus_sysfs_write_profile_buttons
450 .attr
= { .name
= "profile1_buttons", .mode
= 0440 },
451 .size
= sizeof(struct kovaplus_profile_buttons
),
452 .read
= kovaplus_sysfs_read_profilex_buttons
,
453 .private = &profile_numbers
[0]
456 .attr
= { .name
= "profile2_buttons", .mode
= 0440 },
457 .size
= sizeof(struct kovaplus_profile_buttons
),
458 .read
= kovaplus_sysfs_read_profilex_buttons
,
459 .private = &profile_numbers
[1]
462 .attr
= { .name
= "profile3_buttons", .mode
= 0440 },
463 .size
= sizeof(struct kovaplus_profile_buttons
),
464 .read
= kovaplus_sysfs_read_profilex_buttons
,
465 .private = &profile_numbers
[2]
468 .attr
= { .name
= "profile4_buttons", .mode
= 0440 },
469 .size
= sizeof(struct kovaplus_profile_buttons
),
470 .read
= kovaplus_sysfs_read_profilex_buttons
,
471 .private = &profile_numbers
[3]
474 .attr
= { .name
= "profile5_buttons", .mode
= 0440 },
475 .size
= sizeof(struct kovaplus_profile_buttons
),
476 .read
= kovaplus_sysfs_read_profilex_buttons
,
477 .private = &profile_numbers
[4]
482 static int kovaplus_init_kovaplus_device_struct(struct usb_device
*usb_dev
,
483 struct kovaplus_device
*kovaplus
)
486 static uint wait
= 70; /* device will freeze with just 60 */
488 mutex_init(&kovaplus
->kovaplus_lock
);
490 retval
= kovaplus_get_info(usb_dev
, &kovaplus
->info
);
494 for (i
= 0; i
< 5; ++i
) {
496 retval
= kovaplus_get_profile_settings(usb_dev
,
497 &kovaplus
->profile_settings
[i
], i
);
502 retval
= kovaplus_get_profile_buttons(usb_dev
,
503 &kovaplus
->profile_buttons
[i
], i
);
509 retval
= kovaplus_get_actual_profile(usb_dev
);
512 kovaplus_profile_activated(kovaplus
, retval
);
517 static int kovaplus_init_specials(struct hid_device
*hdev
)
519 struct usb_interface
*intf
= to_usb_interface(hdev
->dev
.parent
);
520 struct usb_device
*usb_dev
= interface_to_usbdev(intf
);
521 struct kovaplus_device
*kovaplus
;
524 if (intf
->cur_altsetting
->desc
.bInterfaceProtocol
525 == USB_INTERFACE_PROTOCOL_MOUSE
) {
527 kovaplus
= kzalloc(sizeof(*kovaplus
), GFP_KERNEL
);
529 hid_err(hdev
, "can't alloc device descriptor\n");
532 hid_set_drvdata(hdev
, kovaplus
);
534 retval
= kovaplus_init_kovaplus_device_struct(usb_dev
, kovaplus
);
536 hid_err(hdev
, "couldn't init struct kovaplus_device\n");
540 retval
= roccat_connect(kovaplus_class
, hdev
,
541 sizeof(struct kovaplus_roccat_report
));
543 hid_err(hdev
, "couldn't init char dev\n");
545 kovaplus
->chrdev_minor
= retval
;
546 kovaplus
->roccat_claimed
= 1;
550 hid_set_drvdata(hdev
, NULL
);
559 static void kovaplus_remove_specials(struct hid_device
*hdev
)
561 struct usb_interface
*intf
= to_usb_interface(hdev
->dev
.parent
);
562 struct kovaplus_device
*kovaplus
;
564 if (intf
->cur_altsetting
->desc
.bInterfaceProtocol
565 == USB_INTERFACE_PROTOCOL_MOUSE
) {
566 kovaplus
= hid_get_drvdata(hdev
);
567 if (kovaplus
->roccat_claimed
)
568 roccat_disconnect(kovaplus
->chrdev_minor
);
573 static int kovaplus_probe(struct hid_device
*hdev
,
574 const struct hid_device_id
*id
)
578 retval
= hid_parse(hdev
);
580 hid_err(hdev
, "parse failed\n");
584 retval
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
586 hid_err(hdev
, "hw start failed\n");
590 retval
= kovaplus_init_specials(hdev
);
592 hid_err(hdev
, "couldn't install mouse\n");
604 static void kovaplus_remove(struct hid_device
*hdev
)
606 kovaplus_remove_specials(hdev
);
610 static void kovaplus_keep_values_up_to_date(struct kovaplus_device
*kovaplus
,
613 struct kovaplus_mouse_report_button
const *button_report
;
615 if (data
[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON
)
618 button_report
= (struct kovaplus_mouse_report_button
const *)data
;
620 switch (button_report
->type
) {
621 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1
:
622 kovaplus_profile_activated(kovaplus
, button_report
->data1
- 1);
624 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI
:
625 kovaplus
->actual_cpi
= kovaplus_convert_event_cpi(button_report
->data1
);
627 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY
:
628 kovaplus
->actual_x_sensitivity
= button_report
->data1
;
629 kovaplus
->actual_y_sensitivity
= button_report
->data2
;
636 static void kovaplus_report_to_chrdev(struct kovaplus_device
const *kovaplus
,
639 struct kovaplus_roccat_report roccat_report
;
640 struct kovaplus_mouse_report_button
const *button_report
;
642 if (data
[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON
)
645 button_report
= (struct kovaplus_mouse_report_button
const *)data
;
647 if (button_report
->type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2
)
650 roccat_report
.type
= button_report
->type
;
651 roccat_report
.profile
= kovaplus
->actual_profile
+ 1;
653 if (roccat_report
.type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO
||
654 roccat_report
.type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT
||
655 roccat_report
.type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH
||
656 roccat_report
.type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER
)
657 roccat_report
.button
= button_report
->data1
;
659 roccat_report
.button
= 0;
661 if (roccat_report
.type
== KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI
)
662 roccat_report
.data1
= kovaplus_convert_event_cpi(button_report
->data1
);
664 roccat_report
.data1
= button_report
->data1
;
666 roccat_report
.data2
= button_report
->data2
;
668 roccat_report_event(kovaplus
->chrdev_minor
,
669 (uint8_t const *)&roccat_report
);
672 static int kovaplus_raw_event(struct hid_device
*hdev
,
673 struct hid_report
*report
, u8
*data
, int size
)
675 struct usb_interface
*intf
= to_usb_interface(hdev
->dev
.parent
);
676 struct kovaplus_device
*kovaplus
= hid_get_drvdata(hdev
);
678 if (intf
->cur_altsetting
->desc
.bInterfaceProtocol
679 != USB_INTERFACE_PROTOCOL_MOUSE
)
682 if (kovaplus
== NULL
)
685 kovaplus_keep_values_up_to_date(kovaplus
, data
);
687 if (kovaplus
->roccat_claimed
)
688 kovaplus_report_to_chrdev(kovaplus
, data
);
693 static const struct hid_device_id kovaplus_devices
[] = {
694 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT
, USB_DEVICE_ID_ROCCAT_KOVAPLUS
) },
698 MODULE_DEVICE_TABLE(hid
, kovaplus_devices
);
700 static struct hid_driver kovaplus_driver
= {
702 .id_table
= kovaplus_devices
,
703 .probe
= kovaplus_probe
,
704 .remove
= kovaplus_remove
,
705 .raw_event
= kovaplus_raw_event
708 static int __init
kovaplus_init(void)
712 kovaplus_class
= class_create(THIS_MODULE
, "kovaplus");
713 if (IS_ERR(kovaplus_class
))
714 return PTR_ERR(kovaplus_class
);
715 kovaplus_class
->dev_attrs
= kovaplus_attributes
;
716 kovaplus_class
->dev_bin_attrs
= kovaplus_bin_attributes
;
718 retval
= hid_register_driver(&kovaplus_driver
);
720 class_destroy(kovaplus_class
);
724 static void __exit
kovaplus_exit(void)
726 hid_unregister_driver(&kovaplus_driver
);
727 class_destroy(kovaplus_class
);
730 module_init(kovaplus_init
);
731 module_exit(kovaplus_exit
);
733 MODULE_AUTHOR("Stefan Achatz");
734 MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
735 MODULE_LICENSE("GPL v2");