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 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; 44 } 45 46 static int kovaplus_send_control(struct usb_device *usb_dev, uint value, 47 enum kovaplus_control_requests request) 48 { 49 int retval; 50 struct roccat_common2_control control; 51 52 if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || 53 request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && 54 value > 4) 55 return -EINVAL; 56 57 control.command = ROCCAT_COMMON_COMMAND_CONTROL; 58 control.value = value; 59 control.request = request; 60 61 retval = roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL, 62 &control, sizeof(struct roccat_common2_control)); 63 64 return retval; 65 } 66 67 static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, 68 enum kovaplus_control_requests request) 69 { 70 return kovaplus_send_control(usb_dev, number, request); 71 } 72 73 static int kovaplus_get_profile_settings(struct usb_device *usb_dev, 74 struct kovaplus_profile_settings *buf, uint number) 75 { 76 int retval; 77 78 retval = kovaplus_select_profile(usb_dev, number, 79 KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); 80 if (retval) 81 return retval; 82 83 return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, 84 buf, KOVAPLUS_SIZE_PROFILE_SETTINGS); 85 } 86 87 static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, 88 struct kovaplus_profile_buttons *buf, int number) 89 { 90 int retval; 91 92 retval = kovaplus_select_profile(usb_dev, number, 93 KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); 94 if (retval) 95 return retval; 96 97 return roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, 98 buf, KOVAPLUS_SIZE_PROFILE_BUTTONS); 99 } 100 101 /* retval is 0-4 on success, < 0 on error */ 102 static int kovaplus_get_actual_profile(struct usb_device *usb_dev) 103 { 104 struct kovaplus_actual_profile buf; 105 int retval; 106 107 retval = roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, 108 &buf, sizeof(struct kovaplus_actual_profile)); 109 110 return retval ? retval : buf.actual_profile; 111 } 112 113 static int kovaplus_set_actual_profile(struct usb_device *usb_dev, 114 int new_profile) 115 { 116 struct kovaplus_actual_profile buf; 117 118 buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE; 119 buf.size = sizeof(struct kovaplus_actual_profile); 120 buf.actual_profile = new_profile; 121 122 return roccat_common2_send_with_status(usb_dev, 123 KOVAPLUS_COMMAND_ACTUAL_PROFILE, 124 &buf, sizeof(struct kovaplus_actual_profile)); 125 } 126 127 static ssize_t kovaplus_sysfs_read(struct file *fp, struct kobject *kobj, 128 char *buf, loff_t off, size_t count, 129 size_t real_size, uint command) 130 { 131 struct device *dev = kobj_to_dev(kobj)->parent->parent; 132 struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 133 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 134 int retval; 135 136 if (off >= real_size) 137 return 0; 138 139 if (off != 0 || count != real_size) 140 return -EINVAL; 141 142 mutex_lock(&kovaplus->kovaplus_lock); 143 retval = roccat_common2_receive(usb_dev, command, buf, real_size); 144 mutex_unlock(&kovaplus->kovaplus_lock); 145 146 if (retval) 147 return retval; 148 149 return real_size; 150 } 151 152 static ssize_t kovaplus_sysfs_write(struct file *fp, struct kobject *kobj, 153 void const *buf, loff_t off, size_t count, 154 size_t real_size, uint command) 155 { 156 struct device *dev = kobj_to_dev(kobj)->parent->parent; 157 struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 158 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 159 int retval; 160 161 if (off != 0 || count != real_size) 162 return -EINVAL; 163 164 mutex_lock(&kovaplus->kovaplus_lock); 165 retval = roccat_common2_send_with_status(usb_dev, command, 166 buf, real_size); 167 mutex_unlock(&kovaplus->kovaplus_lock); 168 169 if (retval) 170 return retval; 171 172 return real_size; 173 } 174 175 #define KOVAPLUS_SYSFS_W(thingy, THINGY) \ 176 static ssize_t kovaplus_sysfs_write_ ## thingy(struct file *fp, \ 177 struct kobject *kobj, struct bin_attribute *attr, char *buf, \ 178 loff_t off, size_t count) \ 179 { \ 180 return kovaplus_sysfs_write(fp, kobj, buf, off, count, \ 181 KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \ 182 } 183 184 #define KOVAPLUS_SYSFS_R(thingy, THINGY) \ 185 static ssize_t kovaplus_sysfs_read_ ## thingy(struct file *fp, \ 186 struct kobject *kobj, struct bin_attribute *attr, char *buf, \ 187 loff_t off, size_t count) \ 188 { \ 189 return kovaplus_sysfs_read(fp, kobj, buf, off, count, \ 190 KOVAPLUS_SIZE_ ## THINGY, KOVAPLUS_COMMAND_ ## THINGY); \ 191 } 192 193 #define KOVAPLUS_SYSFS_RW(thingy, THINGY) \ 194 KOVAPLUS_SYSFS_W(thingy, THINGY) \ 195 KOVAPLUS_SYSFS_R(thingy, THINGY) 196 197 #define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \ 198 KOVAPLUS_SYSFS_RW(thingy, THINGY); \ 199 static struct bin_attribute bin_attr_##thingy = { \ 200 .attr = { .name = #thingy, .mode = 0660 }, \ 201 .size = KOVAPLUS_SIZE_ ## THINGY, \ 202 .read = kovaplus_sysfs_read_ ## thingy, \ 203 .write = kovaplus_sysfs_write_ ## thingy \ 204 } 205 206 #define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \ 207 KOVAPLUS_SYSFS_W(thingy, THINGY); \ 208 static struct bin_attribute bin_attr_##thingy = { \ 209 .attr = { .name = #thingy, .mode = 0220 }, \ 210 .size = KOVAPLUS_SIZE_ ## THINGY, \ 211 .write = kovaplus_sysfs_write_ ## thingy \ 212 } 213 KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL); 214 KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO); 215 KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS); 216 KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS); 217 218 static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp, 219 struct kobject *kobj, struct bin_attribute *attr, char *buf, 220 loff_t off, size_t count) 221 { 222 struct device *dev = kobj_to_dev(kobj)->parent->parent; 223 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 224 ssize_t retval; 225 226 retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private), 227 KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); 228 if (retval) 229 return retval; 230 231 return kovaplus_sysfs_read(fp, kobj, buf, off, count, 232 KOVAPLUS_SIZE_PROFILE_SETTINGS, 233 KOVAPLUS_COMMAND_PROFILE_SETTINGS); 234 } 235 236 static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp, 237 struct kobject *kobj, struct bin_attribute *attr, char *buf, 238 loff_t off, size_t count) 239 { 240 struct device *dev = kobj_to_dev(kobj)->parent->parent; 241 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 242 ssize_t retval; 243 244 retval = kovaplus_select_profile(usb_dev, *(uint *)(attr->private), 245 KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); 246 if (retval) 247 return retval; 248 249 return kovaplus_sysfs_read(fp, kobj, buf, off, count, 250 KOVAPLUS_SIZE_PROFILE_BUTTONS, 251 KOVAPLUS_COMMAND_PROFILE_BUTTONS); 252 } 253 254 #define PROFILE_ATTR(number) \ 255 static struct bin_attribute bin_attr_profile##number##_settings = { \ 256 .attr = { .name = "profile" #number "_settings", .mode = 0440 }, \ 257 .size = KOVAPLUS_SIZE_PROFILE_SETTINGS, \ 258 .read = kovaplus_sysfs_read_profilex_settings, \ 259 .private = &profile_numbers[number-1], \ 260 }; \ 261 static struct bin_attribute bin_attr_profile##number##_buttons = { \ 262 .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \ 263 .size = KOVAPLUS_SIZE_PROFILE_BUTTONS, \ 264 .read = kovaplus_sysfs_read_profilex_buttons, \ 265 .private = &profile_numbers[number-1], \ 266 }; 267 PROFILE_ATTR(1); 268 PROFILE_ATTR(2); 269 PROFILE_ATTR(3); 270 PROFILE_ATTR(4); 271 PROFILE_ATTR(5); 272 273 static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev, 274 struct device_attribute *attr, char *buf) 275 { 276 struct kovaplus_device *kovaplus = 277 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 278 return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile); 279 } 280 281 static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, 282 struct device_attribute *attr, char const *buf, size_t size) 283 { 284 struct kovaplus_device *kovaplus; 285 struct usb_device *usb_dev; 286 unsigned long profile; 287 int retval; 288 struct kovaplus_roccat_report roccat_report; 289 290 dev = dev->parent->parent; 291 kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 292 usb_dev = interface_to_usbdev(to_usb_interface(dev)); 293 294 retval = kstrtoul(buf, 10, &profile); 295 if (retval) 296 return retval; 297 298 if (profile >= 5) 299 return -EINVAL; 300 301 mutex_lock(&kovaplus->kovaplus_lock); 302 retval = kovaplus_set_actual_profile(usb_dev, profile); 303 if (retval) { 304 mutex_unlock(&kovaplus->kovaplus_lock); 305 return retval; 306 } 307 308 kovaplus_profile_activated(kovaplus, profile); 309 310 roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1; 311 roccat_report.profile = profile + 1; 312 roccat_report.button = 0; 313 roccat_report.data1 = profile + 1; 314 roccat_report.data2 = 0; 315 roccat_report_event(kovaplus->chrdev_minor, 316 (uint8_t const *)&roccat_report); 317 318 mutex_unlock(&kovaplus->kovaplus_lock); 319 320 return size; 321 } 322 static DEVICE_ATTR(actual_profile, 0660, 323 kovaplus_sysfs_show_actual_profile, 324 kovaplus_sysfs_set_actual_profile); 325 326 static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev, 327 struct device_attribute *attr, char *buf) 328 { 329 struct kovaplus_device *kovaplus = 330 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 331 return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi); 332 } 333 static DEVICE_ATTR(actual_cpi, 0440, kovaplus_sysfs_show_actual_cpi, NULL); 334 335 static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev, 336 struct device_attribute *attr, char *buf) 337 { 338 struct kovaplus_device *kovaplus = 339 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 340 return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity); 341 } 342 static DEVICE_ATTR(actual_sensitivity_x, 0440, 343 kovaplus_sysfs_show_actual_sensitivity_x, NULL); 344 345 static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev, 346 struct device_attribute *attr, char *buf) 347 { 348 struct kovaplus_device *kovaplus = 349 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 350 return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity); 351 } 352 static DEVICE_ATTR(actual_sensitivity_y, 0440, 353 kovaplus_sysfs_show_actual_sensitivity_y, NULL); 354 355 static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev, 356 struct device_attribute *attr, char *buf) 357 { 358 struct kovaplus_device *kovaplus; 359 struct usb_device *usb_dev; 360 struct kovaplus_info info; 361 362 dev = dev->parent->parent; 363 kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 364 usb_dev = interface_to_usbdev(to_usb_interface(dev)); 365 366 mutex_lock(&kovaplus->kovaplus_lock); 367 roccat_common2_receive(usb_dev, KOVAPLUS_COMMAND_INFO, 368 &info, KOVAPLUS_SIZE_INFO); 369 mutex_unlock(&kovaplus->kovaplus_lock); 370 371 return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version); 372 } 373 static DEVICE_ATTR(firmware_version, 0440, 374 kovaplus_sysfs_show_firmware_version, NULL); 375 376 static struct attribute *kovaplus_attrs[] = { 377 &dev_attr_actual_cpi.attr, 378 &dev_attr_firmware_version.attr, 379 &dev_attr_actual_profile.attr, 380 &dev_attr_actual_sensitivity_x.attr, 381 &dev_attr_actual_sensitivity_y.attr, 382 NULL, 383 }; 384 385 static struct bin_attribute *kovaplus_bin_attributes[] = { 386 &bin_attr_control, 387 &bin_attr_info, 388 &bin_attr_profile_settings, 389 &bin_attr_profile_buttons, 390 &bin_attr_profile1_settings, 391 &bin_attr_profile2_settings, 392 &bin_attr_profile3_settings, 393 &bin_attr_profile4_settings, 394 &bin_attr_profile5_settings, 395 &bin_attr_profile1_buttons, 396 &bin_attr_profile2_buttons, 397 &bin_attr_profile3_buttons, 398 &bin_attr_profile4_buttons, 399 &bin_attr_profile5_buttons, 400 NULL, 401 }; 402 403 static const struct attribute_group kovaplus_group = { 404 .attrs = kovaplus_attrs, 405 .bin_attrs = kovaplus_bin_attributes, 406 }; 407 408 static const struct attribute_group *kovaplus_groups[] = { 409 &kovaplus_group, 410 NULL, 411 }; 412 413 static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev, 414 struct kovaplus_device *kovaplus) 415 { 416 int retval, i; 417 static uint wait = 70; /* device will freeze with just 60 */ 418 419 mutex_init(&kovaplus->kovaplus_lock); 420 421 for (i = 0; i < 5; ++i) { 422 msleep(wait); 423 retval = kovaplus_get_profile_settings(usb_dev, 424 &kovaplus->profile_settings[i], i); 425 if (retval) 426 return retval; 427 428 msleep(wait); 429 retval = kovaplus_get_profile_buttons(usb_dev, 430 &kovaplus->profile_buttons[i], i); 431 if (retval) 432 return retval; 433 } 434 435 msleep(wait); 436 retval = kovaplus_get_actual_profile(usb_dev); 437 if (retval < 0) 438 return retval; 439 kovaplus_profile_activated(kovaplus, retval); 440 441 return 0; 442 } 443 444 static int kovaplus_init_specials(struct hid_device *hdev) 445 { 446 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 447 struct usb_device *usb_dev = interface_to_usbdev(intf); 448 struct kovaplus_device *kovaplus; 449 int retval; 450 451 if (intf->cur_altsetting->desc.bInterfaceProtocol 452 == USB_INTERFACE_PROTOCOL_MOUSE) { 453 454 kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL); 455 if (!kovaplus) { 456 hid_err(hdev, "can't alloc device descriptor\n"); 457 return -ENOMEM; 458 } 459 hid_set_drvdata(hdev, kovaplus); 460 461 retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus); 462 if (retval) { 463 hid_err(hdev, "couldn't init struct kovaplus_device\n"); 464 goto exit_free; 465 } 466 467 retval = roccat_connect(kovaplus_class, hdev, 468 sizeof(struct kovaplus_roccat_report)); 469 if (retval < 0) { 470 hid_err(hdev, "couldn't init char dev\n"); 471 } else { 472 kovaplus->chrdev_minor = retval; 473 kovaplus->roccat_claimed = 1; 474 } 475 476 } else { 477 hid_set_drvdata(hdev, NULL); 478 } 479 480 return 0; 481 exit_free: 482 kfree(kovaplus); 483 return retval; 484 } 485 486 static void kovaplus_remove_specials(struct hid_device *hdev) 487 { 488 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 489 struct kovaplus_device *kovaplus; 490 491 if (intf->cur_altsetting->desc.bInterfaceProtocol 492 == USB_INTERFACE_PROTOCOL_MOUSE) { 493 kovaplus = hid_get_drvdata(hdev); 494 if (kovaplus->roccat_claimed) 495 roccat_disconnect(kovaplus->chrdev_minor); 496 kfree(kovaplus); 497 } 498 } 499 500 static int kovaplus_probe(struct hid_device *hdev, 501 const struct hid_device_id *id) 502 { 503 int retval; 504 505 retval = hid_parse(hdev); 506 if (retval) { 507 hid_err(hdev, "parse failed\n"); 508 goto exit; 509 } 510 511 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 512 if (retval) { 513 hid_err(hdev, "hw start failed\n"); 514 goto exit; 515 } 516 517 retval = kovaplus_init_specials(hdev); 518 if (retval) { 519 hid_err(hdev, "couldn't install mouse\n"); 520 goto exit_stop; 521 } 522 523 return 0; 524 525 exit_stop: 526 hid_hw_stop(hdev); 527 exit: 528 return retval; 529 } 530 531 static void kovaplus_remove(struct hid_device *hdev) 532 { 533 kovaplus_remove_specials(hdev); 534 hid_hw_stop(hdev); 535 } 536 537 static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus, 538 u8 const *data) 539 { 540 struct kovaplus_mouse_report_button const *button_report; 541 542 if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 543 return; 544 545 button_report = (struct kovaplus_mouse_report_button const *)data; 546 547 switch (button_report->type) { 548 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1: 549 kovaplus_profile_activated(kovaplus, button_report->data1 - 1); 550 break; 551 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI: 552 kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1); 553 break; 554 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY: 555 kovaplus->actual_x_sensitivity = button_report->data1; 556 kovaplus->actual_y_sensitivity = button_report->data2; 557 break; 558 default: 559 break; 560 } 561 } 562 563 static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus, 564 u8 const *data) 565 { 566 struct kovaplus_roccat_report roccat_report; 567 struct kovaplus_mouse_report_button const *button_report; 568 569 if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 570 return; 571 572 button_report = (struct kovaplus_mouse_report_button const *)data; 573 574 if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2) 575 return; 576 577 roccat_report.type = button_report->type; 578 roccat_report.profile = kovaplus->actual_profile + 1; 579 580 if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO || 581 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT || 582 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH || 583 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) 584 roccat_report.button = button_report->data1; 585 else 586 roccat_report.button = 0; 587 588 if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI) 589 roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1); 590 else 591 roccat_report.data1 = button_report->data1; 592 593 roccat_report.data2 = button_report->data2; 594 595 roccat_report_event(kovaplus->chrdev_minor, 596 (uint8_t const *)&roccat_report); 597 } 598 599 static int kovaplus_raw_event(struct hid_device *hdev, 600 struct hid_report *report, u8 *data, int size) 601 { 602 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 603 struct kovaplus_device *kovaplus = hid_get_drvdata(hdev); 604 605 if (intf->cur_altsetting->desc.bInterfaceProtocol 606 != USB_INTERFACE_PROTOCOL_MOUSE) 607 return 0; 608 609 if (kovaplus == NULL) 610 return 0; 611 612 kovaplus_keep_values_up_to_date(kovaplus, data); 613 614 if (kovaplus->roccat_claimed) 615 kovaplus_report_to_chrdev(kovaplus, data); 616 617 return 0; 618 } 619 620 static const struct hid_device_id kovaplus_devices[] = { 621 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, 622 { } 623 }; 624 625 MODULE_DEVICE_TABLE(hid, kovaplus_devices); 626 627 static struct hid_driver kovaplus_driver = { 628 .name = "kovaplus", 629 .id_table = kovaplus_devices, 630 .probe = kovaplus_probe, 631 .remove = kovaplus_remove, 632 .raw_event = kovaplus_raw_event 633 }; 634 635 static int __init kovaplus_init(void) 636 { 637 int retval; 638 639 kovaplus_class = class_create(THIS_MODULE, "kovaplus"); 640 if (IS_ERR(kovaplus_class)) 641 return PTR_ERR(kovaplus_class); 642 kovaplus_class->dev_groups = kovaplus_groups; 643 644 retval = hid_register_driver(&kovaplus_driver); 645 if (retval) 646 class_destroy(kovaplus_class); 647 return retval; 648 } 649 650 static void __exit kovaplus_exit(void) 651 { 652 hid_unregister_driver(&kovaplus_driver); 653 class_destroy(kovaplus_class); 654 } 655 656 module_init(kovaplus_init); 657 module_exit(kovaplus_exit); 658 659 MODULE_AUTHOR("Stefan Achatz"); 660 MODULE_DESCRIPTION("USB Roccat Kova[+] driver"); 661 MODULE_LICENSE("GPL v2"); 662