1 /* 2 * Roccat Pyra driver for Linux 3 * 4 * Copyright (c) 2010 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 Pyra is a mobile gamer mouse which comes in wired and wireless 16 * variant. Wireless variant is not tested. 17 * Userland tools can be found at http://sourceforge.net/projects/roccat 18 */ 19 20 #include <linux/device.h> 21 #include <linux/input.h> 22 #include <linux/hid.h> 23 #include <linux/module.h> 24 #include <linux/slab.h> 25 #include <linux/hid-roccat.h> 26 #include "hid-ids.h" 27 #include "hid-roccat-common.h" 28 #include "hid-roccat-pyra.h" 29 30 static uint profile_numbers[5] = {0, 1, 2, 3, 4}; 31 32 /* pyra_class is used for creating sysfs attributes via roccat char device */ 33 static struct class *pyra_class; 34 35 static void profile_activated(struct pyra_device *pyra, 36 unsigned int new_profile) 37 { 38 pyra->actual_profile = new_profile; 39 pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi; 40 } 41 42 static int pyra_send_control(struct usb_device *usb_dev, int value, 43 enum pyra_control_requests request) 44 { 45 struct roccat_common2_control control; 46 47 if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || 48 request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) && 49 (value < 0 || value > 4)) 50 return -EINVAL; 51 52 control.command = ROCCAT_COMMON_COMMAND_CONTROL; 53 control.value = value; 54 control.request = request; 55 56 return roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL, 57 &control, sizeof(struct roccat_common2_control)); 58 } 59 60 static int pyra_get_profile_settings(struct usb_device *usb_dev, 61 struct pyra_profile_settings *buf, int number) 62 { 63 int retval; 64 retval = pyra_send_control(usb_dev, number, 65 PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); 66 if (retval) 67 return retval; 68 return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, 69 buf, sizeof(struct pyra_profile_settings)); 70 } 71 72 static int pyra_get_profile_buttons(struct usb_device *usb_dev, 73 struct pyra_profile_buttons *buf, int number) 74 { 75 int retval; 76 retval = pyra_send_control(usb_dev, number, 77 PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); 78 if (retval) 79 return retval; 80 return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, 81 buf, sizeof(struct pyra_profile_buttons)); 82 } 83 84 static int pyra_get_settings(struct usb_device *usb_dev, 85 struct pyra_settings *buf) 86 { 87 return roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS, 88 buf, sizeof(struct pyra_settings)); 89 } 90 91 static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) 92 { 93 return roccat_common2_receive(usb_dev, PYRA_COMMAND_INFO, 94 buf, sizeof(struct pyra_info)); 95 } 96 97 static int pyra_set_profile_settings(struct usb_device *usb_dev, 98 struct pyra_profile_settings const *settings) 99 { 100 return roccat_common2_send_with_status(usb_dev, 101 PYRA_COMMAND_PROFILE_SETTINGS, settings, 102 sizeof(struct pyra_profile_settings)); 103 } 104 105 static int pyra_set_profile_buttons(struct usb_device *usb_dev, 106 struct pyra_profile_buttons const *buttons) 107 { 108 return roccat_common2_send_with_status(usb_dev, 109 PYRA_COMMAND_PROFILE_BUTTONS, buttons, 110 sizeof(struct pyra_profile_buttons)); 111 } 112 113 static int pyra_set_settings(struct usb_device *usb_dev, 114 struct pyra_settings const *settings) 115 { 116 return roccat_common2_send_with_status(usb_dev, 117 PYRA_COMMAND_SETTINGS, settings, 118 sizeof(struct pyra_settings)); 119 } 120 121 static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, 122 struct kobject *kobj, struct bin_attribute *attr, char *buf, 123 loff_t off, size_t count) 124 { 125 struct device *dev = 126 container_of(kobj, struct device, kobj)->parent->parent; 127 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 128 129 if (off >= sizeof(struct pyra_profile_settings)) 130 return 0; 131 132 if (off + count > sizeof(struct pyra_profile_settings)) 133 count = sizeof(struct pyra_profile_settings) - off; 134 135 mutex_lock(&pyra->pyra_lock); 136 memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off, 137 count); 138 mutex_unlock(&pyra->pyra_lock); 139 140 return count; 141 } 142 143 static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, 144 struct kobject *kobj, struct bin_attribute *attr, char *buf, 145 loff_t off, size_t count) 146 { 147 struct device *dev = 148 container_of(kobj, struct device, kobj)->parent->parent; 149 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 150 151 if (off >= sizeof(struct pyra_profile_buttons)) 152 return 0; 153 154 if (off + count > sizeof(struct pyra_profile_buttons)) 155 count = sizeof(struct pyra_profile_buttons) - off; 156 157 mutex_lock(&pyra->pyra_lock); 158 memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off, 159 count); 160 mutex_unlock(&pyra->pyra_lock); 161 162 return count; 163 } 164 165 static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, 166 struct kobject *kobj, struct bin_attribute *attr, char *buf, 167 loff_t off, size_t count) 168 { 169 struct device *dev = 170 container_of(kobj, struct device, kobj)->parent->parent; 171 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 172 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 173 int retval = 0; 174 int difference; 175 int profile_number; 176 struct pyra_profile_settings *profile_settings; 177 178 if (off != 0 || count != sizeof(struct pyra_profile_settings)) 179 return -EINVAL; 180 181 profile_number = ((struct pyra_profile_settings const *)buf)->number; 182 profile_settings = &pyra->profile_settings[profile_number]; 183 184 mutex_lock(&pyra->pyra_lock); 185 difference = memcmp(buf, profile_settings, 186 sizeof(struct pyra_profile_settings)); 187 if (difference) { 188 retval = pyra_set_profile_settings(usb_dev, 189 (struct pyra_profile_settings const *)buf); 190 if (!retval) 191 memcpy(profile_settings, buf, 192 sizeof(struct pyra_profile_settings)); 193 } 194 mutex_unlock(&pyra->pyra_lock); 195 196 if (retval) 197 return retval; 198 199 return sizeof(struct pyra_profile_settings); 200 } 201 202 static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp, 203 struct kobject *kobj, struct bin_attribute *attr, char *buf, 204 loff_t off, size_t count) 205 { 206 struct device *dev = 207 container_of(kobj, struct device, kobj)->parent->parent; 208 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 209 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 210 int retval = 0; 211 int difference; 212 int profile_number; 213 struct pyra_profile_buttons *profile_buttons; 214 215 if (off != 0 || count != sizeof(struct pyra_profile_buttons)) 216 return -EINVAL; 217 218 profile_number = ((struct pyra_profile_buttons const *)buf)->number; 219 profile_buttons = &pyra->profile_buttons[profile_number]; 220 221 mutex_lock(&pyra->pyra_lock); 222 difference = memcmp(buf, profile_buttons, 223 sizeof(struct pyra_profile_buttons)); 224 if (difference) { 225 retval = pyra_set_profile_buttons(usb_dev, 226 (struct pyra_profile_buttons const *)buf); 227 if (!retval) 228 memcpy(profile_buttons, buf, 229 sizeof(struct pyra_profile_buttons)); 230 } 231 mutex_unlock(&pyra->pyra_lock); 232 233 if (retval) 234 return retval; 235 236 return sizeof(struct pyra_profile_buttons); 237 } 238 239 static ssize_t pyra_sysfs_read_settings(struct file *fp, 240 struct kobject *kobj, struct bin_attribute *attr, char *buf, 241 loff_t off, size_t count) 242 { 243 struct device *dev = 244 container_of(kobj, struct device, kobj)->parent->parent; 245 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 246 247 if (off >= sizeof(struct pyra_settings)) 248 return 0; 249 250 if (off + count > sizeof(struct pyra_settings)) 251 count = sizeof(struct pyra_settings) - off; 252 253 mutex_lock(&pyra->pyra_lock); 254 memcpy(buf, ((char const *)&pyra->settings) + off, count); 255 mutex_unlock(&pyra->pyra_lock); 256 257 return count; 258 } 259 260 static ssize_t pyra_sysfs_write_settings(struct file *fp, 261 struct kobject *kobj, struct bin_attribute *attr, char *buf, 262 loff_t off, size_t count) 263 { 264 struct device *dev = 265 container_of(kobj, struct device, kobj)->parent->parent; 266 struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 267 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 268 int retval = 0; 269 int difference; 270 struct pyra_roccat_report roccat_report; 271 272 if (off != 0 || count != sizeof(struct pyra_settings)) 273 return -EINVAL; 274 275 mutex_lock(&pyra->pyra_lock); 276 difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings)); 277 if (difference) { 278 retval = pyra_set_settings(usb_dev, 279 (struct pyra_settings const *)buf); 280 if (retval) { 281 mutex_unlock(&pyra->pyra_lock); 282 return retval; 283 } 284 285 memcpy(&pyra->settings, buf, 286 sizeof(struct pyra_settings)); 287 288 profile_activated(pyra, pyra->settings.startup_profile); 289 290 roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2; 291 roccat_report.value = pyra->settings.startup_profile + 1; 292 roccat_report.key = 0; 293 roccat_report_event(pyra->chrdev_minor, 294 (uint8_t const *)&roccat_report); 295 } 296 mutex_unlock(&pyra->pyra_lock); 297 return sizeof(struct pyra_settings); 298 } 299 300 301 static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev, 302 struct device_attribute *attr, char *buf) 303 { 304 struct pyra_device *pyra = 305 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 306 return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi); 307 } 308 309 static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, 310 struct device_attribute *attr, char *buf) 311 { 312 struct pyra_device *pyra = 313 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 314 return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile); 315 } 316 317 static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, 318 struct device_attribute *attr, char *buf) 319 { 320 struct pyra_device *pyra = 321 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 322 return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version); 323 } 324 325 static ssize_t pyra_sysfs_show_startup_profile(struct device *dev, 326 struct device_attribute *attr, char *buf) 327 { 328 struct pyra_device *pyra = 329 hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 330 return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile); 331 } 332 333 static struct device_attribute pyra_attributes[] = { 334 __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL), 335 __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL), 336 __ATTR(firmware_version, 0440, 337 pyra_sysfs_show_firmware_version, NULL), 338 __ATTR(startup_profile, 0440, 339 pyra_sysfs_show_startup_profile, NULL), 340 __ATTR_NULL 341 }; 342 343 static struct bin_attribute pyra_bin_attributes[] = { 344 { 345 .attr = { .name = "profile_settings", .mode = 0220 }, 346 .size = sizeof(struct pyra_profile_settings), 347 .write = pyra_sysfs_write_profile_settings 348 }, 349 { 350 .attr = { .name = "profile1_settings", .mode = 0440 }, 351 .size = sizeof(struct pyra_profile_settings), 352 .read = pyra_sysfs_read_profilex_settings, 353 .private = &profile_numbers[0] 354 }, 355 { 356 .attr = { .name = "profile2_settings", .mode = 0440 }, 357 .size = sizeof(struct pyra_profile_settings), 358 .read = pyra_sysfs_read_profilex_settings, 359 .private = &profile_numbers[1] 360 }, 361 { 362 .attr = { .name = "profile3_settings", .mode = 0440 }, 363 .size = sizeof(struct pyra_profile_settings), 364 .read = pyra_sysfs_read_profilex_settings, 365 .private = &profile_numbers[2] 366 }, 367 { 368 .attr = { .name = "profile4_settings", .mode = 0440 }, 369 .size = sizeof(struct pyra_profile_settings), 370 .read = pyra_sysfs_read_profilex_settings, 371 .private = &profile_numbers[3] 372 }, 373 { 374 .attr = { .name = "profile5_settings", .mode = 0440 }, 375 .size = sizeof(struct pyra_profile_settings), 376 .read = pyra_sysfs_read_profilex_settings, 377 .private = &profile_numbers[4] 378 }, 379 { 380 .attr = { .name = "profile_buttons", .mode = 0220 }, 381 .size = sizeof(struct pyra_profile_buttons), 382 .write = pyra_sysfs_write_profile_buttons 383 }, 384 { 385 .attr = { .name = "profile1_buttons", .mode = 0440 }, 386 .size = sizeof(struct pyra_profile_buttons), 387 .read = pyra_sysfs_read_profilex_buttons, 388 .private = &profile_numbers[0] 389 }, 390 { 391 .attr = { .name = "profile2_buttons", .mode = 0440 }, 392 .size = sizeof(struct pyra_profile_buttons), 393 .read = pyra_sysfs_read_profilex_buttons, 394 .private = &profile_numbers[1] 395 }, 396 { 397 .attr = { .name = "profile3_buttons", .mode = 0440 }, 398 .size = sizeof(struct pyra_profile_buttons), 399 .read = pyra_sysfs_read_profilex_buttons, 400 .private = &profile_numbers[2] 401 }, 402 { 403 .attr = { .name = "profile4_buttons", .mode = 0440 }, 404 .size = sizeof(struct pyra_profile_buttons), 405 .read = pyra_sysfs_read_profilex_buttons, 406 .private = &profile_numbers[3] 407 }, 408 { 409 .attr = { .name = "profile5_buttons", .mode = 0440 }, 410 .size = sizeof(struct pyra_profile_buttons), 411 .read = pyra_sysfs_read_profilex_buttons, 412 .private = &profile_numbers[4] 413 }, 414 { 415 .attr = { .name = "settings", .mode = 0660 }, 416 .size = sizeof(struct pyra_settings), 417 .read = pyra_sysfs_read_settings, 418 .write = pyra_sysfs_write_settings 419 }, 420 __ATTR_NULL 421 }; 422 423 static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, 424 struct pyra_device *pyra) 425 { 426 struct pyra_info info; 427 int retval, i; 428 429 mutex_init(&pyra->pyra_lock); 430 431 retval = pyra_get_info(usb_dev, &info); 432 if (retval) 433 return retval; 434 435 pyra->firmware_version = info.firmware_version; 436 437 retval = pyra_get_settings(usb_dev, &pyra->settings); 438 if (retval) 439 return retval; 440 441 for (i = 0; i < 5; ++i) { 442 retval = pyra_get_profile_settings(usb_dev, 443 &pyra->profile_settings[i], i); 444 if (retval) 445 return retval; 446 447 retval = pyra_get_profile_buttons(usb_dev, 448 &pyra->profile_buttons[i], i); 449 if (retval) 450 return retval; 451 } 452 453 profile_activated(pyra, pyra->settings.startup_profile); 454 455 return 0; 456 } 457 458 static int pyra_init_specials(struct hid_device *hdev) 459 { 460 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 461 struct usb_device *usb_dev = interface_to_usbdev(intf); 462 struct pyra_device *pyra; 463 int retval; 464 465 if (intf->cur_altsetting->desc.bInterfaceProtocol 466 == USB_INTERFACE_PROTOCOL_MOUSE) { 467 468 pyra = kzalloc(sizeof(*pyra), GFP_KERNEL); 469 if (!pyra) { 470 hid_err(hdev, "can't alloc device descriptor\n"); 471 return -ENOMEM; 472 } 473 hid_set_drvdata(hdev, pyra); 474 475 retval = pyra_init_pyra_device_struct(usb_dev, pyra); 476 if (retval) { 477 hid_err(hdev, "couldn't init struct pyra_device\n"); 478 goto exit_free; 479 } 480 481 retval = roccat_connect(pyra_class, hdev, 482 sizeof(struct pyra_roccat_report)); 483 if (retval < 0) { 484 hid_err(hdev, "couldn't init char dev\n"); 485 } else { 486 pyra->chrdev_minor = retval; 487 pyra->roccat_claimed = 1; 488 } 489 } else { 490 hid_set_drvdata(hdev, NULL); 491 } 492 493 return 0; 494 exit_free: 495 kfree(pyra); 496 return retval; 497 } 498 499 static void pyra_remove_specials(struct hid_device *hdev) 500 { 501 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 502 struct pyra_device *pyra; 503 504 if (intf->cur_altsetting->desc.bInterfaceProtocol 505 == USB_INTERFACE_PROTOCOL_MOUSE) { 506 pyra = hid_get_drvdata(hdev); 507 if (pyra->roccat_claimed) 508 roccat_disconnect(pyra->chrdev_minor); 509 kfree(hid_get_drvdata(hdev)); 510 } 511 } 512 513 static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id) 514 { 515 int retval; 516 517 retval = hid_parse(hdev); 518 if (retval) { 519 hid_err(hdev, "parse failed\n"); 520 goto exit; 521 } 522 523 retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 524 if (retval) { 525 hid_err(hdev, "hw start failed\n"); 526 goto exit; 527 } 528 529 retval = pyra_init_specials(hdev); 530 if (retval) { 531 hid_err(hdev, "couldn't install mouse\n"); 532 goto exit_stop; 533 } 534 return 0; 535 536 exit_stop: 537 hid_hw_stop(hdev); 538 exit: 539 return retval; 540 } 541 542 static void pyra_remove(struct hid_device *hdev) 543 { 544 pyra_remove_specials(hdev); 545 hid_hw_stop(hdev); 546 } 547 548 static void pyra_keep_values_up_to_date(struct pyra_device *pyra, 549 u8 const *data) 550 { 551 struct pyra_mouse_event_button const *button_event; 552 553 switch (data[0]) { 554 case PYRA_MOUSE_REPORT_NUMBER_BUTTON: 555 button_event = (struct pyra_mouse_event_button const *)data; 556 switch (button_event->type) { 557 case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: 558 profile_activated(pyra, button_event->data1 - 1); 559 break; 560 case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: 561 pyra->actual_cpi = button_event->data1; 562 break; 563 } 564 break; 565 } 566 } 567 568 static void pyra_report_to_chrdev(struct pyra_device const *pyra, 569 u8 const *data) 570 { 571 struct pyra_roccat_report roccat_report; 572 struct pyra_mouse_event_button const *button_event; 573 574 if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON) 575 return; 576 577 button_event = (struct pyra_mouse_event_button const *)data; 578 579 switch (button_event->type) { 580 case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: 581 case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: 582 roccat_report.type = button_event->type; 583 roccat_report.value = button_event->data1; 584 roccat_report.key = 0; 585 roccat_report_event(pyra->chrdev_minor, 586 (uint8_t const *)&roccat_report); 587 break; 588 case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO: 589 case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT: 590 case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH: 591 if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) { 592 roccat_report.type = button_event->type; 593 roccat_report.key = button_event->data1; 594 /* 595 * pyra reports profile numbers with range 1-5. 596 * Keeping this behaviour. 597 */ 598 roccat_report.value = pyra->actual_profile + 1; 599 roccat_report_event(pyra->chrdev_minor, 600 (uint8_t const *)&roccat_report); 601 } 602 break; 603 } 604 } 605 606 static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, 607 u8 *data, int size) 608 { 609 struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 610 struct pyra_device *pyra = hid_get_drvdata(hdev); 611 612 if (intf->cur_altsetting->desc.bInterfaceProtocol 613 != USB_INTERFACE_PROTOCOL_MOUSE) 614 return 0; 615 616 if (pyra == NULL) 617 return 0; 618 619 pyra_keep_values_up_to_date(pyra, data); 620 621 if (pyra->roccat_claimed) 622 pyra_report_to_chrdev(pyra, data); 623 624 return 0; 625 } 626 627 static const struct hid_device_id pyra_devices[] = { 628 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, 629 USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, 630 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, 631 USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, 632 { } 633 }; 634 635 MODULE_DEVICE_TABLE(hid, pyra_devices); 636 637 static struct hid_driver pyra_driver = { 638 .name = "pyra", 639 .id_table = pyra_devices, 640 .probe = pyra_probe, 641 .remove = pyra_remove, 642 .raw_event = pyra_raw_event 643 }; 644 645 static int __init pyra_init(void) 646 { 647 int retval; 648 649 /* class name has to be same as driver name */ 650 pyra_class = class_create(THIS_MODULE, "pyra"); 651 if (IS_ERR(pyra_class)) 652 return PTR_ERR(pyra_class); 653 pyra_class->dev_attrs = pyra_attributes; 654 pyra_class->dev_bin_attrs = pyra_bin_attributes; 655 656 retval = hid_register_driver(&pyra_driver); 657 if (retval) 658 class_destroy(pyra_class); 659 return retval; 660 } 661 662 static void __exit pyra_exit(void) 663 { 664 hid_unregister_driver(&pyra_driver); 665 class_destroy(pyra_class); 666 } 667 668 module_init(pyra_init); 669 module_exit(pyra_exit); 670 671 MODULE_AUTHOR("Stefan Achatz"); 672 MODULE_DESCRIPTION("USB Roccat Pyra driver"); 673 MODULE_LICENSE("GPL v2"); 674