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 * KoneXTD has same capabilities but updated sensor.
  18 */
  19
  20#include <linux/device.h>
  21#include <linux/input.h>
  22#include <linux/hid.h>
  23#include <linux/module.h>
  24#include <linux/slab.h>
  25#include <linux/hid-roccat.h>
  26#include "hid-ids.h"
  27#include "hid-roccat-common.h"
  28#include "hid-roccat-koneplus.h"
  29
  30static uint profile_numbers[5] = {0, 1, 2, 3, 4};
  31
  32static struct class *koneplus_class;
  33
  34static void koneplus_profile_activated(struct koneplus_device *koneplus,
  35                uint new_profile)
  36{
  37        koneplus->actual_profile = new_profile;
  38}
  39
  40static int koneplus_send_control(struct usb_device *usb_dev, uint value,
  41                enum koneplus_control_requests request)
  42{
  43        struct roccat_common2_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.command = ROCCAT_COMMON_COMMAND_CONTROL;
  51        control.value = value;
  52        control.request = request;
  53
  54        return roccat_common2_send_with_status(usb_dev,
  55                        ROCCAT_COMMON_COMMAND_CONTROL,
  56                        &control, sizeof(struct roccat_common2_control));
  57}
  58
  59
  60/* retval is 0-4 on success, < 0 on error */
  61static int koneplus_get_actual_profile(struct usb_device *usb_dev)
  62{
  63        struct koneplus_actual_profile buf;
  64        int retval;
  65
  66        retval = roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE,
  67                        &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
  68
  69        return retval ? retval : buf.actual_profile;
  70}
  71
  72static int koneplus_set_actual_profile(struct usb_device *usb_dev,
  73                int new_profile)
  74{
  75        struct koneplus_actual_profile buf;
  76
  77        buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
  78        buf.size = KONEPLUS_SIZE_ACTUAL_PROFILE;
  79        buf.actual_profile = new_profile;
  80
  81        return roccat_common2_send_with_status(usb_dev,
  82                        KONEPLUS_COMMAND_ACTUAL_PROFILE,
  83                        &buf, KONEPLUS_SIZE_ACTUAL_PROFILE);
  84}
  85
  86static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
  87                char *buf, loff_t off, size_t count,
  88                size_t real_size, uint command)
  89{
  90        struct device *dev =
  91                        container_of(kobj, struct device, kobj)->parent->parent;
  92        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
  93        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  94        int retval;
  95
  96        if (off >= real_size)
  97                return 0;
  98
  99        if (off != 0 || count != real_size)
 100                return -EINVAL;
 101
 102        mutex_lock(&koneplus->koneplus_lock);
 103        retval = roccat_common2_receive(usb_dev, command, buf, real_size);
 104        mutex_unlock(&koneplus->koneplus_lock);
 105
 106        if (retval)
 107                return retval;
 108
 109        return real_size;
 110}
 111
 112static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
 113                void const *buf, loff_t off, size_t count,
 114                size_t real_size, uint command)
 115{
 116        struct device *dev =
 117                        container_of(kobj, struct device, kobj)->parent->parent;
 118        struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 119        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 120        int retval;
 121
 122        if (off != 0 || count != real_size)
 123                return -EINVAL;
 124
 125        mutex_lock(&koneplus->koneplus_lock);
 126        retval = roccat_common2_send_with_status(usb_dev, command,
 127                        buf, real_size);
 128        mutex_unlock(&koneplus->koneplus_lock);
 129
 130        if (retval)
 131                return retval;
 132
 133        return real_size;
 134}
 135
 136#define KONEPLUS_SYSFS_W(thingy, THINGY) \
 137static ssize_t koneplus_sysfs_write_ ## thingy(struct file *fp, \
 138                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 139                loff_t off, size_t count) \
 140{ \
 141        return koneplus_sysfs_write(fp, kobj, buf, off, count, \
 142                        KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
 143}
 144
 145#define KONEPLUS_SYSFS_R(thingy, THINGY) \
 146static ssize_t koneplus_sysfs_read_ ## thingy(struct file *fp, \
 147                struct kobject *kobj, struct bin_attribute *attr, char *buf, \
 148                loff_t off, size_t count) \
 149{ \
 150        return koneplus_sysfs_read(fp, kobj, buf, off, count, \
 151                        KONEPLUS_SIZE_ ## THINGY, KONEPLUS_COMMAND_ ## THINGY); \
 152}
 153
 154#define KONEPLUS_SYSFS_RW(thingy, THINGY) \
 155KONEPLUS_SYSFS_W(thingy, THINGY) \
 156KONEPLUS_SYSFS_R(thingy, THINGY)
 157
 158#define KONEPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
 159KONEPLUS_SYSFS_RW(thingy, THINGY); \
 160static struct bin_attribute bin_attr_##thingy = { \
 161        .attr = { .name = #thingy, .mode = 0660 }, \
 162        .size = KONEPLUS_SIZE_ ## THINGY, \
 163        .read = koneplus_sysfs_read_ ## thingy, \
 164        .write = koneplus_sysfs_write_ ## thingy \
 165}
 166
 167#define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
 168KONEPLUS_SYSFS_R(thingy, THINGY); \
 169static struct bin_attribute bin_attr_##thingy = { \
 170        .attr = { .name = #thingy, .mode = 0440 }, \
 171        .size = KONEPLUS_SIZE_ ## THINGY, \
 172        .read = koneplus_sysfs_read_ ## thingy, \
 173}
 174
 175#define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
 176KONEPLUS_SYSFS_W(thingy, THINGY); \
 177static struct bin_attribute bin_attr_##thingy = { \
 178        .attr = { .name = #thingy, .mode = 0220 }, \
 179        .size = KONEPLUS_SIZE_ ## THINGY, \
 180        .write = koneplus_sysfs_write_ ## thingy \
 181}
 182KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
 183KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK);
 184KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO);
 185KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
 186KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO);
 187KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR);
 188KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU);
 189KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
 190KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 191
 192static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
 193                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 194                loff_t off, size_t count)
 195{
 196        struct device *dev =
 197                        container_of(kobj, struct device, kobj)->parent->parent;
 198        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 199        ssize_t retval;
 200
 201        retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
 202                        KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
 203        if (retval)
 204                return retval;
 205
 206        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 207                        KONEPLUS_SIZE_PROFILE_SETTINGS,
 208                        KONEPLUS_COMMAND_PROFILE_SETTINGS);
 209}
 210
 211static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
 212                struct kobject *kobj, struct bin_attribute *attr, char *buf,
 213                loff_t off, size_t count)
 214{
 215        struct device *dev =
 216                        container_of(kobj, struct device, kobj)->parent->parent;
 217        struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 218        ssize_t retval;
 219
 220        retval = koneplus_send_control(usb_dev, *(uint *)(attr->private),
 221                        KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
 222        if (retval)
 223                return retval;
 224
 225        return koneplus_sysfs_read(fp, kobj, buf, off, count,
 226                        KONEPLUS_SIZE_PROFILE_BUTTONS,
 227                        KONEPLUS_COMMAND_PROFILE_BUTTONS);
 228}
 229
 230#define PROFILE_ATTR(number)                                            \
 231static struct bin_attribute bin_attr_profile##number##_settings = {     \
 232        .attr = { .name = "profile" #number "_settings", .mode = 0440 },        \
 233        .size = KONEPLUS_SIZE_PROFILE_SETTINGS,                         \
 234        .read = koneplus_sysfs_read_profilex_settings,                  \
 235        .private = &profile_numbers[number-1],                          \
 236};                                                                      \
 237static struct bin_attribute bin_attr_profile##number##_buttons = {      \
 238        .attr = { .name = "profile" #number "_buttons", .mode = 0440 }, \
 239        .size = KONEPLUS_SIZE_PROFILE_BUTTONS,                          \
 240        .read = koneplus_sysfs_read_profilex_buttons,                   \
 241        .private = &profile_numbers[number-1],                          \
 242};
 243PROFILE_ATTR(1);
 244PROFILE_ATTR(2);
 245PROFILE_ATTR(3);
 246PROFILE_ATTR(4);
 247PROFILE_ATTR(5);
 248
 249static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
 250                struct device_attribute *attr, char *buf)
 251{
 252        struct koneplus_device *koneplus =
 253                        hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 254        return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
 255}
 256
 257static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
 258                struct device_attribute *attr, char const *buf, size_t size)
 259{
 260        struct koneplus_device *koneplus;
 261        struct usb_device *usb_dev;
 262        unsigned long profile;
 263        int retval;
 264        struct koneplus_roccat_report roccat_report;
 265
 266        dev = dev->parent->parent;
 267        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 268        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 269
 270        retval = kstrtoul(buf, 10, &profile);
 271        if (retval)
 272                return retval;
 273
 274        if (profile > 4)
 275                return -EINVAL;
 276
 277        mutex_lock(&koneplus->koneplus_lock);
 278
 279        retval = koneplus_set_actual_profile(usb_dev, profile);
 280        if (retval) {
 281                mutex_unlock(&koneplus->koneplus_lock);
 282                return retval;
 283        }
 284
 285        koneplus_profile_activated(koneplus, profile);
 286
 287        roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
 288        roccat_report.data1 = profile + 1;
 289        roccat_report.data2 = 0;
 290        roccat_report.profile = profile + 1;
 291        roccat_report_event(koneplus->chrdev_minor,
 292                        (uint8_t const *)&roccat_report);
 293
 294        mutex_unlock(&koneplus->koneplus_lock);
 295
 296        return size;
 297}
 298static DEVICE_ATTR(actual_profile, 0660,
 299                   koneplus_sysfs_show_actual_profile,
 300                   koneplus_sysfs_set_actual_profile);
 301static DEVICE_ATTR(startup_profile, 0660,
 302                   koneplus_sysfs_show_actual_profile,
 303                   koneplus_sysfs_set_actual_profile);
 304
 305static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
 306                struct device_attribute *attr, char *buf)
 307{
 308        struct koneplus_device *koneplus;
 309        struct usb_device *usb_dev;
 310        struct koneplus_info info;
 311
 312        dev = dev->parent->parent;
 313        koneplus = hid_get_drvdata(dev_get_drvdata(dev));
 314        usb_dev = interface_to_usbdev(to_usb_interface(dev));
 315
 316        mutex_lock(&koneplus->koneplus_lock);
 317        roccat_common2_receive(usb_dev, KONEPLUS_COMMAND_INFO,
 318                        &info, KONEPLUS_SIZE_INFO);
 319        mutex_unlock(&koneplus->koneplus_lock);
 320
 321        return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 322}
 323static DEVICE_ATTR(firmware_version, 0440,
 324                   koneplus_sysfs_show_firmware_version, NULL);
 325
 326static struct attribute *koneplus_attrs[] = {
 327        &dev_attr_actual_profile.attr,
 328        &dev_attr_startup_profile.attr,
 329        &dev_attr_firmware_version.attr,
 330        NULL,
 331};
 332
 333static struct bin_attribute *koneplus_bin_attributes[] = {
 334        &bin_attr_control,
 335        &bin_attr_talk,
 336        &bin_attr_macro,
 337        &bin_attr_tcu_image,
 338        &bin_attr_info,
 339        &bin_attr_sensor,
 340        &bin_attr_tcu,
 341        &bin_attr_profile_settings,
 342        &bin_attr_profile_buttons,
 343        &bin_attr_profile1_settings,
 344        &bin_attr_profile2_settings,
 345        &bin_attr_profile3_settings,
 346        &bin_attr_profile4_settings,
 347        &bin_attr_profile5_settings,
 348        &bin_attr_profile1_buttons,
 349        &bin_attr_profile2_buttons,
 350        &bin_attr_profile3_buttons,
 351        &bin_attr_profile4_buttons,
 352        &bin_attr_profile5_buttons,
 353        NULL,
 354};
 355
 356static const struct attribute_group koneplus_group = {
 357        .attrs = koneplus_attrs,
 358        .bin_attrs = koneplus_bin_attributes,
 359};
 360
 361static const struct attribute_group *koneplus_groups[] = {
 362        &koneplus_group,
 363        NULL,
 364};
 365
 366static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
 367                struct koneplus_device *koneplus)
 368{
 369        int retval;
 370
 371        mutex_init(&koneplus->koneplus_lock);
 372
 373        retval = koneplus_get_actual_profile(usb_dev);
 374        if (retval < 0)
 375                return retval;
 376        koneplus_profile_activated(koneplus, retval);
 377
 378        return 0;
 379}
 380
 381static int koneplus_init_specials(struct hid_device *hdev)
 382{
 383        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 384        struct usb_device *usb_dev = interface_to_usbdev(intf);
 385        struct koneplus_device *koneplus;
 386        int retval;
 387
 388        if (intf->cur_altsetting->desc.bInterfaceProtocol
 389                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 390
 391                koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
 392                if (!koneplus) {
 393                        hid_err(hdev, "can't alloc device descriptor\n");
 394                        return -ENOMEM;
 395                }
 396                hid_set_drvdata(hdev, koneplus);
 397
 398                retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
 399                if (retval) {
 400                        hid_err(hdev, "couldn't init struct koneplus_device\n");
 401                        goto exit_free;
 402                }
 403
 404                retval = roccat_connect(koneplus_class, hdev,
 405                                sizeof(struct koneplus_roccat_report));
 406                if (retval < 0) {
 407                        hid_err(hdev, "couldn't init char dev\n");
 408                } else {
 409                        koneplus->chrdev_minor = retval;
 410                        koneplus->roccat_claimed = 1;
 411                }
 412        } else {
 413                hid_set_drvdata(hdev, NULL);
 414        }
 415
 416        return 0;
 417exit_free:
 418        kfree(koneplus);
 419        return retval;
 420}
 421
 422static void koneplus_remove_specials(struct hid_device *hdev)
 423{
 424        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 425        struct koneplus_device *koneplus;
 426
 427        if (intf->cur_altsetting->desc.bInterfaceProtocol
 428                        == USB_INTERFACE_PROTOCOL_MOUSE) {
 429                koneplus = hid_get_drvdata(hdev);
 430                if (koneplus->roccat_claimed)
 431                        roccat_disconnect(koneplus->chrdev_minor);
 432                kfree(koneplus);
 433        }
 434}
 435
 436static int koneplus_probe(struct hid_device *hdev,
 437                const struct hid_device_id *id)
 438{
 439        int retval;
 440
 441        retval = hid_parse(hdev);
 442        if (retval) {
 443                hid_err(hdev, "parse failed\n");
 444                goto exit;
 445        }
 446
 447        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 448        if (retval) {
 449                hid_err(hdev, "hw start failed\n");
 450                goto exit;
 451        }
 452
 453        retval = koneplus_init_specials(hdev);
 454        if (retval) {
 455                hid_err(hdev, "couldn't install mouse\n");
 456                goto exit_stop;
 457        }
 458
 459        return 0;
 460
 461exit_stop:
 462        hid_hw_stop(hdev);
 463exit:
 464        return retval;
 465}
 466
 467static void koneplus_remove(struct hid_device *hdev)
 468{
 469        koneplus_remove_specials(hdev);
 470        hid_hw_stop(hdev);
 471}
 472
 473static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
 474                u8 const *data)
 475{
 476        struct koneplus_mouse_report_button const *button_report;
 477
 478        switch (data[0]) {
 479        case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
 480                button_report = (struct koneplus_mouse_report_button const *)data;
 481                switch (button_report->type) {
 482                case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
 483                        koneplus_profile_activated(koneplus, button_report->data1 - 1);
 484                        break;
 485                }
 486                break;
 487        }
 488}
 489
 490static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
 491                u8 const *data)
 492{
 493        struct koneplus_roccat_report roccat_report;
 494        struct koneplus_mouse_report_button const *button_report;
 495
 496        if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
 497                return;
 498
 499        button_report = (struct koneplus_mouse_report_button const *)data;
 500
 501        if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
 502                        button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
 503                        button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
 504                return;
 505
 506        roccat_report.type = button_report->type;
 507        roccat_report.data1 = button_report->data1;
 508        roccat_report.data2 = button_report->data2;
 509        roccat_report.profile = koneplus->actual_profile + 1;
 510        roccat_report_event(koneplus->chrdev_minor,
 511                        (uint8_t const *)&roccat_report);
 512}
 513
 514static int koneplus_raw_event(struct hid_device *hdev,
 515                struct hid_report *report, u8 *data, int size)
 516{
 517        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 518        struct koneplus_device *koneplus = hid_get_drvdata(hdev);
 519
 520        if (intf->cur_altsetting->desc.bInterfaceProtocol
 521                        != USB_INTERFACE_PROTOCOL_MOUSE)
 522                return 0;
 523
 524        if (koneplus == NULL)
 525                return 0;
 526
 527        koneplus_keep_values_up_to_date(koneplus, data);
 528
 529        if (koneplus->roccat_claimed)
 530                koneplus_report_to_chrdev(koneplus, data);
 531
 532        return 0;
 533}
 534
 535static const struct hid_device_id koneplus_devices[] = {
 536        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
 537        { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) },
 538        { }
 539};
 540
 541MODULE_DEVICE_TABLE(hid, koneplus_devices);
 542
 543static struct hid_driver koneplus_driver = {
 544                .name = "koneplus",
 545                .id_table = koneplus_devices,
 546                .probe = koneplus_probe,
 547                .remove = koneplus_remove,
 548                .raw_event = koneplus_raw_event
 549};
 550
 551static int __init koneplus_init(void)
 552{
 553        int retval;
 554
 555        /* class name has to be same as driver name */
 556        koneplus_class = class_create(THIS_MODULE, "koneplus");
 557        if (IS_ERR(koneplus_class))
 558                return PTR_ERR(koneplus_class);
 559        koneplus_class->dev_groups = koneplus_groups;
 560
 561        retval = hid_register_driver(&koneplus_driver);
 562        if (retval)
 563                class_destroy(koneplus_class);
 564        return retval;
 565}
 566
 567static void __exit koneplus_exit(void)
 568{
 569        hid_unregister_driver(&koneplus_driver);
 570        class_destroy(koneplus_class);
 571}
 572
 573module_init(koneplus_init);
 574module_exit(koneplus_exit);
 575
 576MODULE_AUTHOR("Stefan Achatz");
 577MODULE_DESCRIPTION("USB Roccat Kone[+]/XTD driver");
 578MODULE_LICENSE("GPL v2");
 579
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.