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