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_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_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, "roccat_common_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_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_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_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_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_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_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_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 struct kovaplus_roccat_report roccat_report; 327 328 dev = dev->parent->parent; 329 kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 330 usb_dev = interface_to_usbdev(to_usb_interface(dev)); 331 332 retval = strict_strtoul(buf, 10, &profile); 333 if (retval) 334 return retval; 335 336 if (profile >= 5) 337 return -EINVAL; 338 339 mutex_lock(&kovaplus->kovaplus_lock); 340 retval = kovaplus_set_actual_profile(usb_dev, profile); 341 if (retval) { 342 mutex_unlock(&kovaplus->kovaplus_lock); 343 return retval; 344 } 345 346 kovaplus_profile_activated(kovaplus, profile); 347 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); 355 356 mutex_unlock(&kovaplus->kovaplus_lock); 357 358 return size; 359 } 360 361 static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev, 362 struct device_attribute *attr, char *buf) 363 { 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); 367 } 368 369 static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev, 370 struct device_attribute *attr, char *buf) 371 { 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); 375 } 376 377 static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev, 378 struct device_attribute *attr, char *buf) 379 { 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); 383 } 384 385 static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev, 386 struct device_attribute *attr, char *buf) 387 { 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); 391 } 392 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), 405 __ATTR_NULL 406 }; 407 408 static struct bin_attribute kovaplus_bin_attributes[] = { 409 { 410 .attr = { .name = "profile_settings", .mode = 0220 }, 411 .size = sizeof(struct kovaplus_profile_settings), 412 .write = kovaplus_sysfs_write_profile_settings 413 }, 414 { 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] 419 }, 420 { 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] 425 }, 426 { 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] 431 }, 432 { 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] 437 }, 438 { 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] 443 }, 444 { 445 .attr = { .name = "profile_buttons", .mode = 0220 }, 446 .size = sizeof(struct kovaplus_profile_buttons), 447 .write = kovaplus_sysfs_write_profile_buttons 448 }, 449 { 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] 454 }, 455 { 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] 460 }, 461 { 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] 466 }, 467 { 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] 472 }, 473 { 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] 478 }, 479 __ATTR_NULL 480 }; 481 482 static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev, 483 struct kovaplus_device *kovaplus) 484 { 485 int retval, i; 486 static uint wait = 70; /* device will freeze with just 60 */ 487 488 mutex_init(&kovaplus->kovaplus_lock); 489 490 retval = kovaplus_get_info(usb_dev, &kovaplus->info); 491 if (retval) 492 return retval; 493 494 for (i = 0; i < 5; ++i) { 495 msleep(wait); 496 retval = kovaplus_get_profile_settings(usb_dev, 497 &kovaplus->profile_settings[i], i); 498 if (retval) 499 return retval; 500 501 msleep(wait); 502 retval = kovaplus_get_profile_buttons(usb_dev, 503 &kovaplus->profile_buttons[i], i); 504 if (retval) 505 return retval; 506 } 507 508 msleep(wait); 509 retval = kovaplus_get_actual_profile(usb_dev); 510 if (retval < 0) 511 return retval; 512 kovaplus_profile_activated(kovaplus, retval); 513 514 return 0; 515 } 516 517 static int kovaplus_init_specials(struct hid_device *hdev) 518 { 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; 522 int retval; 523 524 if (intf->cur_altsetting->desc.bInterfaceProtocol 525 == USB_INTERFACE_PROTOCOL_MOUSE) { 526 527 kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL); 528 if (!kovaplus) { 529 hid_err(hdev, "can't alloc device descriptor\n"); 530 return -ENOMEM; 531 } 532 hid_set_drvdata(hdev, kovaplus); 533 534 retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus); 535 if (retval) { 536 hid_err(hdev, "couldn't init struct kovaplus_device\n"); 537 goto exit_free; 538 } 539 540 retval = roccat_connect(kovaplus_class, hdev, 541 sizeof(struct kovaplus_roccat_report)); 542 if (retval < 0) { 543 hid_err(hdev, "couldn't init char dev\n"); 544 } else { 545 kovaplus->chrdev_minor = retval; 546 kovaplus->roccat_claimed = 1; 547 } 548 549 } else { 550 hid_set_drvdata(hdev, NULL); 551 } 552 553 return 0; 554 exit_free: 555 kfree(kovaplus); 556 return retval; 557 } 558 559 static void kovaplus_remove_specials(struct hid_device *hdev) 560 { 561 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 562 struct kovaplus_device *kovaplus; 563 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); 569 kfree(kovaplus); 570 } 571 } 572 573 static int kovaplus_probe(struct hid_device *hdev, 574 const struct hid_device_id *id) 575 { 576 int retval; 577 578 retval = hid_parse(hdev); 579 if (retval) { 580 hid_err(hdev, "parse failed\n"); 581 goto exit; 582 } 583 584 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 585 if (retval) { 586 hid_err(hdev, "hw start failed\n"); 587 goto exit; 588 } 589 590 retval = kovaplus_init_specials(hdev); 591 if (retval) { 592 hid_err(hdev, "couldn't install mouse\n"); 593 goto exit_stop; 594 } 595 596 return 0; 597 598 exit_stop: 599 hid_hw_stop(hdev); 600 exit: 601 return retval; 602 } 603 604 static void kovaplus_remove(struct hid_device *hdev) 605 { 606 kovaplus_remove_specials(hdev); 607 hid_hw_stop(hdev); 608 } 609 610 static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus, 611 u8 const *data) 612 { 613 struct kovaplus_mouse_report_button const *button_report; 614 615 if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 616 return; 617 618 button_report = (struct kovaplus_mouse_report_button const *)data; 619 620 switch (button_report->type) { 621 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1: 622 kovaplus_profile_activated(kovaplus, button_report->data1 - 1); 623 break; 624 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI: 625 kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1); 626 case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY: 627 kovaplus->actual_x_sensitivity = button_report->data1; 628 kovaplus->actual_y_sensitivity = button_report->data2; 629 } 630 } 631 632 static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus, 633 u8 const *data) 634 { 635 struct kovaplus_roccat_report roccat_report; 636 struct kovaplus_mouse_report_button const *button_report; 637 638 if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 639 return; 640 641 button_report = (struct kovaplus_mouse_report_button const *)data; 642 643 if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2) 644 return; 645 646 roccat_report.type = button_report->type; 647 roccat_report.profile = kovaplus->actual_profile + 1; 648 649 if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO || 650 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT || 651 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH || 652 roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) 653 roccat_report.button = button_report->data1; 654 else 655 roccat_report.button = 0; 656 657 if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI) 658 roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1); 659 else 660 roccat_report.data1 = button_report->data1; 661 662 roccat_report.data2 = button_report->data2; 663 664 roccat_report_event(kovaplus->chrdev_minor, 665 (uint8_t const *)&roccat_report); 666 } 667 668 static int kovaplus_raw_event(struct hid_device *hdev, 669 struct hid_report *report, u8 *data, int size) 670 { 671 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 672 struct kovaplus_device *kovaplus = hid_get_drvdata(hdev); 673 674 if (intf->cur_altsetting->desc.bInterfaceProtocol 675 != USB_INTERFACE_PROTOCOL_MOUSE) 676 return 0; 677 678 if (kovaplus == NULL) 679 return 0; 680 681 kovaplus_keep_values_up_to_date(kovaplus, data); 682 683 if (kovaplus->roccat_claimed) 684 kovaplus_report_to_chrdev(kovaplus, data); 685 686 return 0; 687 } 688 689 static const struct hid_device_id kovaplus_devices[] = { 690 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, 691 { } 692 }; 693 694 MODULE_DEVICE_TABLE(hid, kovaplus_devices); 695 696 static struct hid_driver kovaplus_driver = { 697 .name = "kovaplus", 698 .id_table = kovaplus_devices, 699 .probe = kovaplus_probe, 700 .remove = kovaplus_remove, 701 .raw_event = kovaplus_raw_event 702 }; 703 704 static int __init kovaplus_init(void) 705 { 706 int retval; 707 708 kovaplus_class = class_create(THIS_MODULE, "kovaplus"); 709 if (IS_ERR(kovaplus_class)) 710 return PTR_ERR(kovaplus_class); 711 kovaplus_class->dev_attrs = kovaplus_attributes; 712 kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes; 713 714 retval = hid_register_driver(&kovaplus_driver); 715 if (retval) 716 class_destroy(kovaplus_class); 717 return retval; 718 } 719 720 static void __exit kovaplus_exit(void) 721 { 722 hid_unregister_driver(&kovaplus_driver); 723 class_destroy(kovaplus_class); 724 } 725 726 module_init(kovaplus_init); 727 module_exit(kovaplus_exit); 728 729 MODULE_AUTHOR("Stefan Achatz"); 730 MODULE_DESCRIPTION("USB Roccat Kova[+] driver"); 731 MODULE_LICENSE("GPL v2"); 732