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