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