linux/drivers/hid/hid-roccat-pyra.c
<<
>>
Prefs
   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
  30static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  31
  32/* pyra_class is used for creating sysfs attributes via roccat char device */
  33static struct class *pyra_class;
  34
  35static void profile_activated(struct pyra_device *pyra,
  36                unsigned int new_profile)
  37{
  38        if (new_profile >= ARRAY_SIZE(pyra->profile_settings))
  39                return;
  40        pyra->actual_profile = new_profile;
  41        pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi;
  42}
  43
  44static int pyra_send_control(struct usb_device *usb_dev, int value,
  45                enum pyra_control_requests request)
  46{
  47        struct roccat_common2_control control;
  48
  49        if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
  50                        request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) &&
  51                        (value < 0 || value > 4))
  52                return -EINVAL;
  53
  54        control.command = ROCCAT_COMMON_COMMAND_CONTROL;
  55        control.value = value;
  56        control.request = request;
  57
  58        return roccat_common2_send(usb_dev, ROCCAT_COMMON_COMMAND_CONTROL,
  59                        &control, sizeof(struct roccat_common2_control));
  60}
  61
  62static int pyra_get_profile_settings(struct usb_device *usb_dev,
  63                struct pyra_profile_settings *buf, int number)
  64{
  65        int retval;
  66        retval = pyra_send_control(usb_dev, number,
  67                        PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
  68        if (retval)
  69                return retval;
  70        return roccat_common2_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS,
  71                        buf, PYRA_SIZE_PROFILE_SETTINGS);
  72}
  73
  74static int pyra_get_settings(struct usb_device *usb_dev,
  75                struct pyra_settings *buf)
  76{
  77        return roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS,
  78                        buf, PYRA_SIZE_SETTINGS);
  79}
  80
  81static int pyra_set_settings(struct usb_device *usb_dev,
  82                struct pyra_settings const *settings)
  83{
  84        return roccat_common2_send_with_status(usb_dev,
  85                        PYRA_COMMAND_SETTINGS, settings,
  86                        PYRA_SIZE_SETTINGS);
  87}
  88
  89static ssize_t pyra_sysfs_read(struct file *fp, struct kobject *kobj,
  90                char *buf, loff_t off, size_t count,
  91                size_t real_size, uint command)
  92{
  93        struct device *dev = kobj_to_dev(kobj)->parent->parent;
  94        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
  95        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  96        int retval;
  97
  98        if (off >= real_size)
  99                return 0;
 100
 101        if (off != 0 || count != real_size)
 102                return -EINVAL;
 103
 104        mutex_lock(&pyra->pyra_lock);
 105        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 106        mutex_unlock(&pyra->pyra_lock);
 107
 108        if (retval)
 109                return retval;
 110
 111        return real_size;
 112}
 113
 114static ssize_t pyra_sysfs_write(struct file *fp, struct kobject *kobj,
 115                void const *buf, loff_t off, size_t count,
 116                size_t real_size, uint command)
 117{
 118        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 119        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
 120        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 121        int retval;
 122
 123        if (off != 0 || count != real_size)
 124                return -EINVAL;
 125
 126        mutex_lock(&pyra->pyra_lock);
 127        retval = roccat_common2_send_with_status(usb_dev, command, (void *)buf, real_size);
 128        mutex_unlock(&pyra->pyra_lock);
 129
 130        if (retval)
 131                return retval;
 132
 133        return real_size;
 134}
 135
 136#define PYRA_SYSFS_W(thingy, THINGY) \
 137static ssize_t pyra_sysfs_write_ ## thingy(struct file *fp, \
 138                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 139                loff_t off, size_t count) \
 140{ \
 141        return pyra_sysfs_write(fp, kobj, buf, off, count, \
 142                        PYRA_SIZE_ ## THINGY, PYRA_COMMAND_ ## THINGY); \
 143}
 144
 145#define PYRA_SYSFS_R(thingy, THINGY) \
 146static ssize_t pyra_sysfs_read_ ## thingy(struct file *fp, \
 147                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 148                loff_t off, size_t count) \
 149{ \
 150        return pyra_sysfs_read(fp, kobj, buf, off, count, \
 151                        PYRA_SIZE_ ## THINGY, PYRA_COMMAND_ ## THINGY); \
 152}
 153
 154#define PYRA_SYSFS_RW(thingy, THINGY) \
 155PYRA_SYSFS_W(thingy, THINGY) \
 156PYRA_SYSFS_R(thingy, THINGY)
 157
 158#define PYRA_BIN_ATTRIBUTE_RW(thingy, THINGY) \
 159PYRA_SYSFS_RW(thingy, THINGY); \
 160static struct bin_attribute bin_attr_##thingy = { \
 161        .attr = { .name = #thingy, .mode = 0660 }, \
 162        .size = PYRA_SIZE_ ## THINGY, \
 163        .read = pyra_sysfs_read_ ## thingy, \
 164        .write = pyra_sysfs_write_ ## thingy \
 165}
 166
 167#define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \
 168PYRA_SYSFS_R(thingy, THINGY); \
 169static struct bin_attribute bin_attr_##thingy = { \
 170        .attr = { .name = #thingy, .mode = 0440 }, \
 171        .size = PYRA_SIZE_ ## THINGY, \
 172        .read = pyra_sysfs_read_ ## thingy, \
 173}
 174
 175#define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \
 176PYRA_SYSFS_W(thingy, THINGY); \
 177static struct bin_attribute bin_attr_##thingy = { \
 178        .attr = { .name = #thingy, .mode = 0220 }, \
 179        .size = PYRA_SIZE_ ## THINGY, \
 180        .write = pyra_sysfs_write_ ## thingy \
 181}
 182
 183PYRA_BIN_ATTRIBUTE_W(control, CONTROL);
 184PYRA_BIN_ATTRIBUTE_RW(info, INFO);
 185PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
 186PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 187
 188static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
 189                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 190                loff_t off, size_t count)
 191{
 192        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 193        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 194        ssize_t retval;
 195
 196        retval = pyra_send_control(usb_dev, *(uint *)(attr->private),
 197                        PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
 198        if (retval)
 199                return retval;
 200
 201        return pyra_sysfs_read(fp, kobj, buf, off, count,
 202                        PYRA_SIZE_PROFILE_SETTINGS,
 203                        PYRA_COMMAND_PROFILE_SETTINGS);
 204}
 205
 206static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
 207                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 208                loff_t off, size_t count)
 209{
 210        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 211        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 212        ssize_t retval;
 213
 214        retval = pyra_send_control(usb_dev, *(uint *)(attr->private),
 215                        PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
 216        if (retval)
 217                return retval;
 218
 219        return pyra_sysfs_read(fp, kobj, buf, off, count,
 220                        PYRA_SIZE_PROFILE_BUTTONS,
 221                        PYRA_COMMAND_PROFILE_BUTTONS);
 222}
 223
 224#define PROFILE_ATTR(number)                                            \
 225static struct bin_attribute bin_attr_profile##number##_settings = {     \
 226        .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
 227        .size = PYRA_SIZE_PROFILE_SETTINGS,                             \
 228        .read = pyra_sysfs_read_profilex_settings,                      \
 229        .private = &profile_numbers[number-1],                          \
 230};                                                                      \
 231static struct bin_attribute bin_attr_profile##number##_buttons = {      \
 232        .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
 233        .size = PYRA_SIZE_PROFILE_BUTTONS,                              \
 234        .read = pyra_sysfs_read_profilex_buttons,                       \
 235        .private = &profile_numbers[number-1],                          \
 236};
 237PROFILE_ATTR(1);
 238PROFILE_ATTR(2);
 239PROFILE_ATTR(3);
 240PROFILE_ATTR(4);
 241PROFILE_ATTR(5);
 242
 243static ssize_t pyra_sysfs_write_settings(struct file *fp,
 244                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 245                loff_t off, size_t count)
 246{
 247        struct device *dev = kobj_to_dev(kobj)->parent->parent;
 248        struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
 249        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 250        int retval = 0;
 251        struct pyra_roccat_report roccat_report;
 252        struct pyra_settings const *settings;
 253
 254        if (off != 0 || count != PYRA_SIZE_SETTINGS)
 255                return -EINVAL;
 256
 257        settings = (struct pyra_settings const *)buf;
 258        if (settings->startup_profile >= ARRAY_SIZE(pyra->profile_settings))
 259                return -EINVAL;
 260
 261        mutex_lock(&pyra->pyra_lock);
 262
 263        retval = pyra_set_settings(usb_dev, settings);
 264        if (retval) {
 265                mutex_unlock(&pyra->pyra_lock);
 266                return retval;
 267        }
 268
 269        profile_activated(pyra, settings->startup_profile);
 270
 271        roccat_report.type = PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2;
 272        roccat_report.value = settings->startup_profile + 1;
 273        roccat_report.key = 0;
 274        roccat_report_event(pyra->chrdev_minor,
 275                        (uint8_t const *)&roccat_report);
 276
 277        mutex_unlock(&pyra->pyra_lock);
 278        return PYRA_SIZE_SETTINGS;
 279}
 280
 281PYRA_SYSFS_R(settings, SETTINGS);
 282static struct bin_attribute bin_attr_settings =
 283        __BIN_ATTR(settings, (S_IWUSR | S_IRUGO),
 284                   pyra_sysfs_read_settings, pyra_sysfs_write_settings,
 285                   PYRA_SIZE_SETTINGS);
 286
 287static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
 288                struct device_attribute *attr, char *buf)
 289{
 290        struct pyra_device *pyra =
 291                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 292        return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
 293}
 294static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
 295
 296static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
 297                struct device_attribute *attr, char *buf)
 298{
 299        struct pyra_device *pyra =
 300                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 301        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 302        struct pyra_settings settings;
 303
 304        mutex_lock(&pyra->pyra_lock);
 305        roccat_common2_receive(usb_dev, PYRA_COMMAND_SETTINGS,
 306                        &settings, PYRA_SIZE_SETTINGS);
 307        mutex_unlock(&pyra->pyra_lock);
 308
 309        return snprintf(buf, PAGE_SIZE, "%d\n", settings.startup_profile);
 310}
 311static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
 312static DEVICE_ATTR(startup_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
 313
 314static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
 315                struct device_attribute *attr, char *buf)
 316{
 317        struct pyra_device *pyra;
 318        struct usb_device *usb_dev;
 319        struct pyra_info info;
 320
 321        dev = dev->parent->parent;
 322        pyra = hid_get_drvdata(dev_get_drvdata(dev));
 323        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 324
 325        mutex_lock(&pyra->pyra_lock);
 326        roccat_common2_receive(usb_dev, PYRA_COMMAND_INFO,
 327                        &info, PYRA_SIZE_INFO);
 328        mutex_unlock(&pyra->pyra_lock);
 329
 330        return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 331}
 332static DEVICE_ATTR(firmware_version, 0440, pyra_sysfs_show_firmware_version,
 333                   NULL);
 334
 335static struct attribute *pyra_attrs[] = {
 336        &dev_attr_actual_cpi.attr,
 337        &dev_attr_actual_profile.attr,
 338        &dev_attr_firmware_version.attr,
 339        &dev_attr_startup_profile.attr,
 340        NULL,
 341};
 342
 343static struct bin_attribute *pyra_bin_attributes[] = {
 344        &bin_attr_control,
 345        &bin_attr_info,
 346        &bin_attr_profile_settings,
 347        &bin_attr_profile_buttons,
 348        &bin_attr_settings,
 349        &bin_attr_profile1_settings,
 350        &bin_attr_profile2_settings,
 351        &bin_attr_profile3_settings,
 352        &bin_attr_profile4_settings,
 353        &bin_attr_profile5_settings,
 354        &bin_attr_profile1_buttons,
 355        &bin_attr_profile2_buttons,
 356        &bin_attr_profile3_buttons,
 357        &bin_attr_profile4_buttons,
 358        &bin_attr_profile5_buttons,
 359        NULL,
 360};
 361
 362static const struct attribute_group pyra_group = {
 363        .attrs = pyra_attrs,
 364        .bin_attrs = pyra_bin_attributes,
 365};
 366
 367static const struct attribute_group *pyra_groups[] = {
 368        &pyra_group,
 369        NULL,
 370};
 371
 372static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
 373                struct pyra_device *pyra)
 374{
 375        struct pyra_settings settings;
 376        int retval, i;
 377
 378        mutex_init(&pyra->pyra_lock);
 379
 380        retval = pyra_get_settings(usb_dev, &settings);
 381        if (retval)
 382                return retval;
 383
 384        for (i = 0; i < 5; ++i) {
 385                retval = pyra_get_profile_settings(usb_dev,
 386                                &pyra->profile_settings[i], i);
 387                if (retval)
 388                        return retval;
 389        }
 390
 391        profile_activated(pyra, settings.startup_profile);
 392
 393        return 0;
 394}
 395
 396static int pyra_init_specials(struct hid_device *hdev)
 397{
 398        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 399        struct usb_device *usb_dev = interface_to_usbdev(intf);
 400        struct pyra_device *pyra;
 401        int retval;
 402
 403        if (intf->cur_altsetting->desc.bInterfaceProtocol
 404                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 405
 406                pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
 407                if (!pyra) {
 408                        hid_err(hdev, "can't alloc device descriptor\n");
 409                        return -ENOMEM;
 410                }
 411                hid_set_drvdata(hdev, pyra);
 412
 413                retval = pyra_init_pyra_device_struct(usb_dev, pyra);
 414                if (retval) {
 415                        hid_err(hdev, "couldn't init struct pyra_device\n");
 416                        goto exit_free;
 417                }
 418
 419                retval = roccat_connect(pyra_class, hdev,
 420                                sizeof(struct pyra_roccat_report));
 421                if (retval < 0) {
 422                        hid_err(hdev, "couldn't init char dev\n");
 423                } else {
 424                        pyra->chrdev_minor = retval;
 425                        pyra->roccat_claimed = 1;
 426                }
 427        } else {
 428                hid_set_drvdata(hdev, NULL);
 429        }
 430
 431        return 0;
 432exit_free:
 433        kfree(pyra);
 434        return retval;
 435}
 436
 437static void pyra_remove_specials(struct hid_device *hdev)
 438{
 439        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 440        struct pyra_device *pyra;
 441
 442        if (intf->cur_altsetting->desc.bInterfaceProtocol
 443                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 444                pyra = hid_get_drvdata(hdev);
 445                if (pyra->roccat_claimed)
 446                        roccat_disconnect(pyra->chrdev_minor);
 447                kfree(hid_get_drvdata(hdev));
 448        }
 449}
 450
 451static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
 452{
 453        int retval;
 454
 455        retval = hid_parse(hdev);
 456        if (retval) {
 457                hid_err(hdev, "parse failed\n");
 458                goto exit;
 459        }
 460
 461        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 462        if (retval) {
 463                hid_err(hdev, "hw start failed\n");
 464                goto exit;
 465        }
 466
 467        retval = pyra_init_specials(hdev);
 468        if (retval) {
 469                hid_err(hdev, "couldn't install mouse\n");
 470                goto exit_stop;
 471        }
 472        return 0;
 473
 474exit_stop:
 475        hid_hw_stop(hdev);
 476exit:
 477        return retval;
 478}
 479
 480static void pyra_remove(struct hid_device *hdev)
 481{
 482        pyra_remove_specials(hdev);
 483        hid_hw_stop(hdev);
 484}
 485
 486static void pyra_keep_values_up_to_date(struct pyra_device *pyra,
 487                u8 const *data)
 488{
 489        struct pyra_mouse_event_button const *button_event;
 490
 491        switch (data[0]) {
 492        case PYRA_MOUSE_REPORT_NUMBER_BUTTON:
 493                button_event = (struct pyra_mouse_event_button const *)data;
 494                switch (button_event->type) {
 495                case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
 496                        profile_activated(pyra, button_event->data1 - 1);
 497                        break;
 498                case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
 499                        pyra->actual_cpi = button_event->data1;
 500                        break;
 501                }
 502                break;
 503        }
 504}
 505
 506static void pyra_report_to_chrdev(struct pyra_device const *pyra,
 507                u8 const *data)
 508{
 509        struct pyra_roccat_report roccat_report;
 510        struct pyra_mouse_event_button const *button_event;
 511
 512        if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON)
 513                return;
 514
 515        button_event = (struct pyra_mouse_event_button const *)data;
 516
 517        switch (button_event->type) {
 518        case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
 519        case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
 520                roccat_report.type = button_event->type;
 521                roccat_report.value = button_event->data1;
 522                roccat_report.key = 0;
 523                roccat_report_event(pyra->chrdev_minor,
 524                                (uint8_t const *)&roccat_report);
 525                break;
 526        case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
 527        case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
 528        case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH:
 529                if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) {
 530                        roccat_report.type = button_event->type;
 531                        roccat_report.key = button_event->data1;
 532                        /*
 533                         * pyra reports profile numbers with range 1-5.
 534                         * Keeping this behaviour.
 535                         */
 536                        roccat_report.value = pyra->actual_profile + 1;
 537                        roccat_report_event(pyra->chrdev_minor,
 538                                        (uint8_t const *)&roccat_report);
 539                }
 540                break;
 541        }
 542}
 543
 544static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report,
 545                u8 *data, int size)
 546{
 547        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 548        struct pyra_device *pyra = hid_get_drvdata(hdev);
 549
 550        if (intf->cur_altsetting->desc.bInterfaceProtocol
 551                        != USB_INTERFACE_PROTOCOL_MOUSE)
 552                return 0;
 553
 554        if (pyra == NULL)
 555                return 0;
 556
 557        pyra_keep_values_up_to_date(pyra, data);
 558
 559        if (pyra->roccat_claimed)
 560                pyra_report_to_chrdev(pyra, data);
 561
 562        return 0;
 563}
 564
 565static const struct hid_device_id pyra_devices[] = {
 566        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT,
 567                        USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
 568        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT,
 569                        USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
 570        { }
 571};
 572
 573MODULE_DEVICE_TABLE(hid, pyra_devices);
 574
 575static struct hid_driver pyra_driver = {
 576                .name = "pyra",
 577                .id_table = pyra_devices,
 578                .probe = pyra_probe,
 579                .remove = pyra_remove,
 580                .raw_event = pyra_raw_event
 581};
 582
 583static int __init pyra_init(void)
 584{
 585        int retval;
 586
 587        /* class name has to be same as driver name */
 588        pyra_class = class_create(THIS_MODULE, "pyra");
 589        if (IS_ERR(pyra_class))
 590                return PTR_ERR(pyra_class);
 591        pyra_class->dev_groups = pyra_groups;
 592
 593        retval = hid_register_driver(&pyra_driver);
 594        if (retval)
 595                class_destroy(pyra_class);
 596        return retval;
 597}
 598
 599static void __exit pyra_exit(void)
 600{
 601        hid_unregister_driver(&pyra_driver);
 602        class_destroy(pyra_class);
 603}
 604
 605module_init(pyra_init);
 606module_exit(pyra_exit);
 607
 608MODULE_AUTHOR("Stefan Achatz");
 609MODULE_DESCRIPTION("USB Roccat Pyra driver");
 610MODULE_LICENSE("GPL v2");
 611
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.