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