linux/drivers/hid/hid-roccat-koneplus.c
<<
>>
Prefs
   1/*
   2 * Roccat Kone[+] 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 Kone[+] is an updated/improved version of the Kone with more memory
  16 * and functionality and without the non-standard behaviours the Kone had.
  17 */
  18
  19#include <linux/device.h>
  20#include <linux/input.h>
  21#include <linux/hid.h>
  22#include <linux/module.h>
  23#include <linux/slab.h>
  24#include <linux/hid-roccat.h>
  25#include "hid-ids.h"
  26#include "hid-roccat-common.h"
  27#include "hid-roccat-koneplus.h"
  28
  29static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  30
  31static struct class *koneplus_class;
  32
  33static void koneplus_profile_activated(struct koneplus_device *koneplus,
  34                uint new_profile)
  35{
  36        koneplus->actual_profile = new_profile;
  37}
  38
  39static int koneplus_send_control(struct usb_device *usb_dev, uint value,
  40                enum koneplus_control_requests request)
  41{
  42        struct roccat_common2_control control;
  43
  44        if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
  45                        request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
  46                        value > 4)
  47                return -EINVAL;
  48
  49        control.command = ROCCAT_COMMON_COMMAND_CONTROL;
  50        control.value = value;
  51        control.request = request;
  52
  53        return roccat_common2_send_with_status(usb_dev,
  54                        ROCCAT_COMMON_COMMAND_CONTROL,
  55                        &control, sizeof(struct roccat_common2_control));
  56}
  57
  58static int koneplus_get_info(struct usb_device *usb_dev,
  59                struct koneplus_info *buf)
  60{
  61        return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO,
  62                        buf, sizeof(struct koneplus_info));
  63}
  64
  65static int koneplus_get_profile_settings(struct usb_device *usb_dev,
  66                struct koneplus_profile_settings *buf, uint number)
  67{
  68        int retval;
  69
  70        retval = koneplus_send_control(usb_dev, number,
  71                        KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
  72        if (retval)
  73                return retval;
  74
  75        return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS,
  76                        buf, sizeof(struct koneplus_profile_settings));
  77}
  78
  79static int koneplus_set_profile_settings(struct usb_device *usb_dev,
  80                struct koneplus_profile_settings const *settings)
  81{
  82        return roccat_common2_send_with_status(usb_dev,
  83                        KONEPLUS_COMMAND_PROFILE_SETTINGS,
  84                        settings, sizeof(struct koneplus_profile_settings));
  85}
  86
  87static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
  88                struct koneplus_profile_buttons *buf, int number)
  89{
  90        int retval;
  91
  92        retval = koneplus_send_control(usb_dev, number,
  93                        KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
  94        if (retval)
  95                return retval;
  96
  97        return roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS,
  98                        buf, sizeof(struct koneplus_profile_buttons));
  99}
 100
 101static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
 102                struct koneplus_profile_buttons const *buttons)
 103{
 104        return roccat_common2_send_with_status(usb_dev,
 105                        KONEPLUS_COMMAND_PROFILE_BUTTONS,
 106                        buttons, sizeof(struct koneplus_profile_buttons));
 107}
 108
 109/* retval is 0-4 on success, < 0 on error */
 110static int koneplus_get_actual_profile(struct usb_device *usb_dev)
 111{
 112        struct koneplus_actual_profile buf;
 113        int retval;
 114
 115        retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
 116                        &buf, sizeof(struct koneplus_actual_profile));
 117
 118        return retval ? retval : buf.actual_profile;
 119}
 120
 121static int koneplus_set_actual_profile(struct usb_device *usb_dev,
 122                int new_profile)
 123{
 124        struct koneplus_actual_profile buf;
 125
 126        buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
 127        buf.size = sizeof(struct koneplus_actual_profile);
 128        buf.actual_profile = new_profile;
 129
 130        return roccat_common2_send_with_status(usb_dev,
 131                        KONEPLUS_COMMAND_ACTUAL_PROFILE,
 132                        &buf, sizeof(struct koneplus_actual_profile));
 133}
 134
 135static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
 136                char *buf, loff_t off, size_t count,
 137                size_t real_size, uint command)
 138{
 139        struct device *dev =
 140                        container_of(kobj, struct device, kobj)->parent->parent;
 141        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 142        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 143        int retval;
 144
 145        if (off >= real_size)
 146                return 0;
 147
 148        if (off != 0 || count != real_size)
 149                return -EINVAL;
 150
 151        mutex_lock(&koneplus->koneplus_lock);
 152        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 153        mutex_unlock(&koneplus->koneplus_lock);
 154
 155        if (retval)
 156                return retval;
 157
 158        return real_size;
 159}
 160
 161static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
 162                void const *buf, loff_t off, size_t count,
 163                size_t real_size, uint command)
 164{
 165        struct device *dev =
 166                        container_of(kobj, struct device, kobj)->parent->parent;
 167        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 168        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 169        int retval;
 170
 171        if (off != 0 || count != real_size)
 172                return -EINVAL;
 173
 174        mutex_lock(&koneplus->koneplus_lock);
 175        retval = roccat_common2_send_with_status(usb_dev, command,
 176                        buf, real_size);
 177        mutex_unlock(&koneplus->koneplus_lock);
 178
 179        if (retval)
 180                return retval;
 181
 182        return real_size;
 183}
 184
 185static ssize_t koneplus_sysfs_write_talk(struct file *fp,
 186                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 187                loff_t off, size_t count)
 188{
 189        return koneplus_sysfs_write(fp, kobj, buf, off, count,
 190                        sizeof(struct koneplus_talk), KONEPLUS_COMMAND_TALK);
 191}
 192
 193static ssize_t koneplus_sysfs_write_macro(struct file *fp,
 194                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 195                loff_t off, size_t count)
 196{
 197        return koneplus_sysfs_write(fp, kobj, buf, off, count,
 198                        sizeof(struct koneplus_macro), KONEPLUS_COMMAND_MACRO);
 199}
 200
 201static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
 202                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 203                loff_t off, size_t count)
 204{
 205        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 206                        sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR);
 207}
 208
 209static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
 210                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 211                loff_t off, size_t count)
 212{
 213        return koneplus_sysfs_write(fp, kobj, buf, off, count,
 214                        sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR);
 215}
 216
 217static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
 218                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 219                loff_t off, size_t count)
 220{
 221        return koneplus_sysfs_write(fp, kobj, buf, off, count,
 222                        sizeof(struct koneplus_tcu), KONEPLUS_COMMAND_TCU);
 223}
 224
 225static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
 226                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 227                loff_t off, size_t count)
 228{
 229        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 230                        sizeof(struct koneplus_tcu_image), KONEPLUS_COMMAND_TCU);
 231}
 232
 233static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
 234                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 235                loff_t off, size_t count)
 236{
 237        struct device *dev =
 238                        container_of(kobj, struct device, kobj)->parent->parent;
 239        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 240
 241        if (off >= sizeof(struct koneplus_profile_settings))
 242                return 0;
 243
 244        if (off + count > sizeof(struct koneplus_profile_settings))
 245                count = sizeof(struct koneplus_profile_settings) - off;
 246
 247        mutex_lock(&koneplus->koneplus_lock);
 248        memcpy(buf, ((char const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
 249                        count);
 250        mutex_unlock(&koneplus->koneplus_lock);
 251
 252        return count;
 253}
 254
 255static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
 256                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 257                loff_t off, size_t count)
 258{
 259        struct device *dev =
 260                        container_of(kobj, struct device, kobj)->parent->parent;
 261        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 262        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 263        int retval = 0;
 264        int difference;
 265        int profile_number;
 266        struct koneplus_profile_settings *profile_settings;
 267
 268        if (off != 0 || count != sizeof(struct koneplus_profile_settings))
 269                return -EINVAL;
 270
 271        profile_number = ((struct koneplus_profile_settings const *)buf)->number;
 272        profile_settings = &koneplus->profile_settings[profile_number];
 273
 274        mutex_lock(&koneplus->koneplus_lock);
 275        difference = memcmp(buf, profile_settings,
 276                        sizeof(struct koneplus_profile_settings));
 277        if (difference) {
 278                retval = koneplus_set_profile_settings(usb_dev,
 279                                (struct koneplus_profile_settings const *)buf);
 280                if (!retval)
 281                        memcpy(profile_settings, buf,
 282                                        sizeof(struct koneplus_profile_settings));
 283        }
 284        mutex_unlock(&koneplus->koneplus_lock);
 285
 286        if (retval)
 287                return retval;
 288
 289        return sizeof(struct koneplus_profile_settings);
 290}
 291
 292static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
 293                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 294                loff_t off, size_t count)
 295{
 296        struct device *dev =
 297                        container_of(kobj, struct device, kobj)->parent->parent;
 298        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 299
 300        if (off >= sizeof(struct koneplus_profile_buttons))
 301                return 0;
 302
 303        if (off + count > sizeof(struct koneplus_profile_buttons))
 304                count = sizeof(struct koneplus_profile_buttons) - off;
 305
 306        mutex_lock(&koneplus->koneplus_lock);
 307        memcpy(buf, ((char const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
 308                        count);
 309        mutex_unlock(&koneplus->koneplus_lock);
 310
 311        return count;
 312}
 313
 314static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
 315                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 316                loff_t off, size_t count)
 317{
 318        struct device *dev =
 319                        container_of(kobj, struct device, kobj)->parent->parent;
 320        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 321        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 322        int retval = 0;
 323        int difference;
 324        uint profile_number;
 325        struct koneplus_profile_buttons *profile_buttons;
 326
 327        if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
 328                return -EINVAL;
 329
 330        profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
 331        profile_buttons = &koneplus->profile_buttons[profile_number];
 332
 333        mutex_lock(&koneplus->koneplus_lock);
 334        difference = memcmp(buf, profile_buttons,
 335                        sizeof(struct koneplus_profile_buttons));
 336        if (difference) {
 337                retval = koneplus_set_profile_buttons(usb_dev,
 338                                (struct koneplus_profile_buttons const *)buf);
 339                if (!retval)
 340                        memcpy(profile_buttons, buf,
 341                                        sizeof(struct koneplus_profile_buttons));
 342        }
 343        mutex_unlock(&koneplus->koneplus_lock);
 344
 345        if (retval)
 346                return retval;
 347
 348        return sizeof(struct koneplus_profile_buttons);
 349}
 350
 351static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
 352                struct device_attribute *attr, char *buf)
 353{
 354        struct koneplus_device *koneplus =
 355                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 356        return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
 357}
 358
 359static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
 360                struct device_attribute *attr, char const *buf, size_t size)
 361{
 362        struct koneplus_device *koneplus;
 363        struct usb_device *usb_dev;
 364        unsigned long profile;
 365        int retval;
 366        struct koneplus_roccat_report roccat_report;
 367
 368        dev = dev->parent->parent;
 369        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 370        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 371
 372        retval = strict_strtoul(buf, 10, &profile);
 373        if (retval)
 374                return retval;
 375
 376        if (profile > 4)
 377                return -EINVAL;
 378
 379        mutex_lock(&koneplus->koneplus_lock);
 380
 381        retval = koneplus_set_actual_profile(usb_dev, profile);
 382        if (retval) {
 383                mutex_unlock(&koneplus->koneplus_lock);
 384                return retval;
 385        }
 386
 387        koneplus_profile_activated(koneplus, profile);
 388
 389        roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
 390        roccat_report.data1 = profile + 1;
 391        roccat_report.data2 = 0;
 392        roccat_report.profile = profile + 1;
 393        roccat_report_event(koneplus->chrdev_minor,
 394                        (uint8_t const *)&roccat_report);
 395
 396        mutex_unlock(&koneplus->koneplus_lock);
 397
 398        return size;
 399}
 400
 401static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
 402                struct device_attribute *attr, char *buf)
 403{
 404        struct koneplus_device *koneplus =
 405                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 406        return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version);
 407}
 408
 409static struct device_attribute koneplus_attributes[] = {
 410        __ATTR(actual_profile, 0660,
 411                        koneplus_sysfs_show_actual_profile,
 412                        koneplus_sysfs_set_actual_profile),
 413        __ATTR(startup_profile, 0660,
 414                        koneplus_sysfs_show_actual_profile,
 415                        koneplus_sysfs_set_actual_profile),
 416        __ATTR(firmware_version, 0440,
 417                        koneplus_sysfs_show_firmware_version, NULL),
 418        __ATTR_NULL
 419};
 420
 421static struct bin_attribute koneplus_bin_attributes[] = {
 422        {
 423                .attr = { .name = "sensor", .mode = 0660 },
 424                .size = sizeof(struct koneplus_sensor),
 425                .read = koneplus_sysfs_read_sensor,
 426                .write = koneplus_sysfs_write_sensor
 427        },
 428        {
 429                .attr = { .name = "tcu", .mode = 0220 },
 430                .size = sizeof(struct koneplus_tcu),
 431                .write = koneplus_sysfs_write_tcu
 432        },
 433        {
 434                .attr = { .name = "tcu_image", .mode = 0440 },
 435                .size = sizeof(struct koneplus_tcu_image),
 436                .read = koneplus_sysfs_read_tcu_image
 437        },
 438        {
 439                .attr = { .name = "profile_settings", .mode = 0220 },
 440                .size = sizeof(struct koneplus_profile_settings),
 441                .write = koneplus_sysfs_write_profile_settings
 442        },
 443        {
 444                .attr = { .name = "profile1_settings", .mode = 0440 },
 445                .size = sizeof(struct koneplus_profile_settings),
 446                .read = koneplus_sysfs_read_profilex_settings,
 447                .private = &profile_numbers[0]
 448        },
 449        {
 450                .attr = { .name = "profile2_settings", .mode = 0440 },
 451                .size = sizeof(struct koneplus_profile_settings),
 452                .read = koneplus_sysfs_read_profilex_settings,
 453                .private = &profile_numbers[1]
 454        },
 455        {
 456                .attr = { .name = "profile3_settings", .mode = 0440 },
 457                .size = sizeof(struct koneplus_profile_settings),
 458                .read = koneplus_sysfs_read_profilex_settings,
 459                .private = &profile_numbers[2]
 460        },
 461        {
 462                .attr = { .name = "profile4_settings", .mode = 0440 },
 463                .size = sizeof(struct koneplus_profile_settings),
 464                .read = koneplus_sysfs_read_profilex_settings,
 465                .private = &profile_numbers[3]
 466        },
 467        {
 468                .attr = { .name = "profile5_settings", .mode = 0440 },
 469                .size = sizeof(struct koneplus_profile_settings),
 470                .read = koneplus_sysfs_read_profilex_settings,
 471                .private = &profile_numbers[4]
 472        },
 473        {
 474                .attr = { .name = "profile_buttons", .mode = 0220 },
 475                .size = sizeof(struct koneplus_profile_buttons),
 476                .write = koneplus_sysfs_write_profile_buttons
 477        },
 478        {
 479                .attr = { .name = "profile1_buttons", .mode = 0440 },
 480                .size = sizeof(struct koneplus_profile_buttons),
 481                .read = koneplus_sysfs_read_profilex_buttons,
 482                .private = &profile_numbers[0]
 483        },
 484        {
 485                .attr = { .name = "profile2_buttons", .mode = 0440 },
 486                .size = sizeof(struct koneplus_profile_buttons),
 487                .read = koneplus_sysfs_read_profilex_buttons,
 488                .private = &profile_numbers[1]
 489        },
 490        {
 491                .attr = { .name = "profile3_buttons", .mode = 0440 },
 492                .size = sizeof(struct koneplus_profile_buttons),
 493                .read = koneplus_sysfs_read_profilex_buttons,
 494                .private = &profile_numbers[2]
 495        },
 496        {
 497                .attr = { .name = "profile4_buttons", .mode = 0440 },
 498                .size = sizeof(struct koneplus_profile_buttons),
 499                .read = koneplus_sysfs_read_profilex_buttons,
 500                .private = &profile_numbers[3]
 501        },
 502        {
 503                .attr = { .name = "profile5_buttons", .mode = 0440 },
 504                .size = sizeof(struct koneplus_profile_buttons),
 505                .read = koneplus_sysfs_read_profilex_buttons,
 506                .private = &profile_numbers[4]
 507        },
 508        {
 509                .attr = { .name = "macro", .mode = 0220 },
 510                .size = sizeof(struct koneplus_macro),
 511                .write = koneplus_sysfs_write_macro
 512        },
 513        {
 514                .attr = { .name = "talk", .mode = 0220 },
 515                .size = sizeof(struct koneplus_talk),
 516                .write = koneplus_sysfs_write_talk
 517        },
 518        __ATTR_NULL
 519};
 520
 521static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
 522                struct koneplus_device *koneplus)
 523{
 524        int retval, i;
 525        static uint wait = 200;
 526
 527        mutex_init(&koneplus->koneplus_lock);
 528
 529        retval = koneplus_get_info(usb_dev, &koneplus->info);
 530        if (retval)
 531                return retval;
 532
 533        for (i = 0; i < 5; ++i) {
 534                msleep(wait);
 535                retval = koneplus_get_profile_settings(usb_dev,
 536                                &koneplus->profile_settings[i], i);
 537                if (retval)
 538                        return retval;
 539
 540                msleep(wait);
 541                retval = koneplus_get_profile_buttons(usb_dev,
 542                                &koneplus->profile_buttons[i], i);
 543                if (retval)
 544                        return retval;
 545        }
 546
 547        msleep(wait);
 548        retval = koneplus_get_actual_profile(usb_dev);
 549        if (retval < 0)
 550                return retval;
 551        koneplus_profile_activated(koneplus, retval);
 552
 553        return 0;
 554}
 555
 556static int koneplus_init_specials(struct hid_device *hdev)
 557{
 558        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 559        struct usb_device *usb_dev = interface_to_usbdev(intf);
 560        struct koneplus_device *koneplus;
 561        int retval;
 562
 563        if (intf->cur_altsetting->desc.bInterfaceProtocol
 564                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 565
 566                koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
 567                if (!koneplus) {
 568                        hid_err(hdev, "can't alloc device descriptor\n");
 569                        return -ENOMEM;
 570                }
 571                hid_set_drvdata(hdev, koneplus);
 572
 573                retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
 574                if (retval) {
 575                        hid_err(hdev, "couldn't init struct koneplus_device\n");
 576                        goto exit_free;
 577                }
 578
 579                retval = roccat_connect(koneplus_class, hdev,
 580                                sizeof(struct koneplus_roccat_report));
 581                if (retval < 0) {
 582                        hid_err(hdev, "couldn't init char dev\n");
 583                } else {
 584                        koneplus->chrdev_minor = retval;
 585                        koneplus->roccat_claimed = 1;
 586                }
 587        } else {
 588                hid_set_drvdata(hdev, NULL);
 589        }
 590
 591        return 0;
 592exit_free:
 593        kfree(koneplus);
 594        return retval;
 595}
 596
 597static void koneplus_remove_specials(struct hid_device *hdev)
 598{
 599        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 600        struct koneplus_device *koneplus;
 601
 602        if (intf->cur_altsetting->desc.bInterfaceProtocol
 603                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 604                koneplus = hid_get_drvdata(hdev);
 605                if (koneplus->roccat_claimed)
 606                        roccat_disconnect(koneplus->chrdev_minor);
 607                kfree(koneplus);
 608        }
 609}
 610
 611static int koneplus_probe(struct hid_device *hdev,
 612                const struct hid_device_id *id)
 613{
 614        int retval;
 615
 616        retval = hid_parse(hdev);
 617        if (retval) {
 618                hid_err(hdev, "parse failed\n");
 619                goto exit;
 620        }
 621
 622        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 623        if (retval) {
 624                hid_err(hdev, "hw start failed\n");
 625                goto exit;
 626        }
 627
 628        retval = koneplus_init_specials(hdev);
 629        if (retval) {
 630                hid_err(hdev, "couldn't install mouse\n");
 631                goto exit_stop;
 632        }
 633
 634        return 0;
 635
 636exit_stop:
 637        hid_hw_stop(hdev);
 638exit:
 639        return retval;
 640}
 641
 642static void koneplus_remove(struct hid_device *hdev)
 643{
 644        koneplus_remove_specials(hdev);
 645        hid_hw_stop(hdev);
 646}
 647
 648static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
 649                u8 const *data)
 650{
 651        struct koneplus_mouse_report_button const *button_report;
 652
 653        switch (data[0]) {
 654        case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
 655                button_report = (struct koneplus_mouse_report_button const *)data;
 656                switch (button_report->type) {
 657                case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
 658                        koneplus_profile_activated(koneplus, button_report->data1 - 1);
 659                        break;
 660                }
 661                break;
 662        }
 663}
 664
 665static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
 666                u8 const *data)
 667{
 668        struct koneplus_roccat_report roccat_report;
 669        struct koneplus_mouse_report_button const *button_report;
 670
 671        if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 672                return;
 673
 674        button_report = (struct koneplus_mouse_report_button const *)data;
 675
 676        if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
 677                        button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
 678                        button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
 679                return;
 680
 681        roccat_report.type = button_report->type;
 682        roccat_report.data1 = button_report->data1;
 683        roccat_report.data2 = button_report->data2;
 684        roccat_report.profile = koneplus->actual_profile + 1;
 685        roccat_report_event(koneplus->chrdev_minor,
 686                        (uint8_t const *)&roccat_report);
 687}
 688
 689static int koneplus_raw_event(struct hid_device *hdev,
 690                struct hid_report *report, u8 *data, int size)
 691{
 692        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 693        struct koneplus_device *koneplus = hid_get_drvdata(hdev);
 694
 695        if (intf->cur_altsetting->desc.bInterfaceProtocol
 696                        != USB_INTERFACE_PROTOCOL_MOUSE)
 697                return 0;
 698
 699        if (koneplus == NULL)
 700                return 0;
 701
 702        koneplus_keep_values_up_to_date(koneplus, data);
 703
 704        if (koneplus->roccat_claimed)
 705                koneplus_report_to_chrdev(koneplus, data);
 706
 707        return 0;
 708}
 709
 710static const struct hid_device_id koneplus_devices[] = {
 711        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
 712        { }
 713};
 714
 715MODULE_DEVICE_TABLE(hid, koneplus_devices);
 716
 717static struct hid_driver koneplus_driver = {
 718                .name = "koneplus",
 719                .id_table = koneplus_devices,
 720                .probe = koneplus_probe,
 721                .remove = koneplus_remove,
 722                .raw_event = koneplus_raw_event
 723};
 724
 725static int __init koneplus_init(void)
 726{
 727        int retval;
 728
 729        /* class name has to be same as driver name */
 730        koneplus_class = class_create(THIS_MODULE, "koneplus");
 731        if (IS_ERR(koneplus_class))
 732                return PTR_ERR(koneplus_class);
 733        koneplus_class->dev_attrs = koneplus_attributes;
 734        koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
 735
 736        retval = hid_register_driver(&koneplus_driver);
 737        if (retval)
 738                class_destroy(koneplus_class);
 739        return retval;
 740}
 741
 742static void __exit koneplus_exit(void)
 743{
 744        hid_unregister_driver(&koneplus_driver);
 745        class_destroy(koneplus_class);
 746}
 747
 748module_init(koneplus_init);
 749module_exit(koneplus_exit);
 750
 751MODULE_AUTHOR("Stefan Achatz");
 752MODULE_DESCRIPTION("USB Roccat Kone[+] driver");
 753MODULE_LICENSE("GPL v2");
 754
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.