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