linux/drivers/hid/hid-roccat-kovaplus.c
<<
>>
Prefs
   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
  28static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  29
  30static struct class *kovaplus_class;
  31
  32static uint kovaplus_convert_event_cpi(uint value)
  33{
  34        return (value == 7 ? 4 : (value == 4 ? 3 : value));
  35}
  36
  37static 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
  46static 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
  67static 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
  99static 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
 113static 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
 119static 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
 126static 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
 140static 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
 147static 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
 161static 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 */
 169static 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
 180static 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
 193static 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
 215static 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
 252static 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
 274static 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
 311static 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
 319static 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_profile_activated(kovaplus, profile);
 341        mutex_unlock(&kovaplus->kovaplus_lock);
 342        if (retval)
 343                return retval;
 344
 345        return size;
 346}
 347
 348static 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
 356static 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
 364static 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
 372static 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
 380static 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
 395static 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
 469static 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
 504static 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;
 541exit_free:
 542        kfree(kovaplus);
 543        return retval;
 544}
 545
 546static 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
 560static 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
 585exit_stop:
 586        hid_hw_stop(hdev);
 587exit:
 588        return retval;
 589}
 590
 591static void kovaplus_remove(struct hid_device *hdev)
 592{
 593        kovaplus_remove_specials(hdev);
 594        hid_hw_stop(hdev);
 595}
 596
 597static 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
 619static 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
 655static 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        if (kovaplus == NULL)
 666                return 0;
 667
 668        kovaplus_keep_values_up_to_date(kovaplus, data);
 669
 670        if (kovaplus->roccat_claimed)
 671                kovaplus_report_to_chrdev(kovaplus, data);
 672
 673        return 0;
 674}
 675
 676static const struct hid_device_id kovaplus_devices[] = {
 677        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
 678        { }
 679};
 680
 681MODULE_DEVICE_TABLE(hid, kovaplus_devices);
 682
 683static struct hid_driver kovaplus_driver = {
 684                .name = "kovaplus",
 685                .id_table = kovaplus_devices,
 686                .probe = kovaplus_probe,
 687                .remove = kovaplus_remove,
 688                .raw_event = kovaplus_raw_event
 689};
 690
 691static int __init kovaplus_init(void)
 692{
 693        int retval;
 694
 695        kovaplus_class = class_create(THIS_MODULE, "kovaplus");
 696        if (IS_ERR(kovaplus_class))
 697                return PTR_ERR(kovaplus_class);
 698        kovaplus_class->dev_attrs = kovaplus_attributes;
 699        kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
 700
 701        retval = hid_register_driver(&kovaplus_driver);
 702        if (retval)
 703                class_destroy(kovaplus_class);
 704        return retval;
 705}
 706
 707static void __exit kovaplus_exit(void)
 708{
 709        hid_unregister_driver(&kovaplus_driver);
 710        class_destroy(kovaplus_class);
 711}
 712
 713module_init(kovaplus_init);
 714module_exit(kovaplus_exit);
 715
 716MODULE_AUTHOR("Stefan Achatz");
 717MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
 718MODULE_LICENSE("GPL v2");
 719