Commit d41c2a7011dffc60571eab8dc4e2a297ef106f44

Authored by Stefan Achatz
Committed by Jiri Kosina
1 parent 8e8da023f5

HID: roccat: Add support for Isku keyboard

This patch adds support for Roccat Isku keyboard.
Userland tools can be found at http://sourceforge.net/projects/roccat

Signed-off-by: Stefan Achatz <erazor_de@users.sourceforge.net>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

Showing 7 changed files with 779 additions and 0 deletions Side-by-side Diff

Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
  1 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/actual_profile
  2 +Date: June 2011
  3 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  4 +Description: The integer value of this attribute ranges from 0-4.
  5 + When read, this attribute returns the number of the actual
  6 + profile. This value is persistent, so its equivalent to the
  7 + profile that's active when the device is powered on next time.
  8 + When written, this file sets the number of the startup profile
  9 + and the device activates this profile immediately.
  10 +Users: http://roccat.sourceforge.net
  11 +
  12 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/info
  13 +Date: June 2011
  14 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  15 +Description: When read, this file returns general data like firmware version.
  16 + The data is 6 bytes long.
  17 + This file is readonly.
  18 +Users: http://roccat.sourceforge.net
  19 +
  20 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/key_mask
  21 +Date: June 2011
  22 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  23 +Description: When written, this file lets one deactivate certain keys like
  24 + windows and application keys, to prevent accidental presses.
  25 + Profile number for which this settings occur is included in
  26 + written data. The data has to be 6 bytes long.
  27 + Before reading this file, control has to be written to select
  28 + which profile to read.
  29 +Users: http://roccat.sourceforge.net
  30 +
  31 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_capslock
  32 +Date: June 2011
  33 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  34 +Description: When written, this file lets one set the function of the
  35 + capslock key for a specific profile. Profile number is included
  36 + in written data. The data has to be 6 bytes long.
  37 + Before reading this file, control has to be written to select
  38 + which profile to read.
  39 +Users: http://roccat.sourceforge.net
  40 +
  41 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_easyzone
  42 +Date: June 2011
  43 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  44 +Description: When written, this file lets one set the function of the
  45 + easyzone keys for a specific profile. Profile number is included
  46 + in written data. The data has to be 65 bytes long.
  47 + Before reading this file, control has to be written to select
  48 + which profile to read.
  49 +Users: http://roccat.sourceforge.net
  50 +
  51 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_function
  52 +Date: June 2011
  53 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  54 +Description: When written, this file lets one set the function of the
  55 + function keys for a specific profile. Profile number is included
  56 + in written data. The data has to be 41 bytes long.
  57 + Before reading this file, control has to be written to select
  58 + which profile to read.
  59 +Users: http://roccat.sourceforge.net
  60 +
  61 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_macro
  62 +Date: June 2011
  63 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  64 +Description: When written, this file lets one set the function of the macro
  65 + keys for a specific profile. Profile number is included in
  66 + written data. The data has to be 35 bytes long.
  67 + Before reading this file, control has to be written to select
  68 + which profile to read.
  69 +Users: http://roccat.sourceforge.net
  70 +
  71 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_media
  72 +Date: June 2011
  73 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  74 +Description: When written, this file lets one set the function of the media
  75 + keys for a specific profile. Profile number is included in
  76 + written data. The data has to be 29 bytes long.
  77 + Before reading this file, control has to be written to select
  78 + which profile to read.
  79 +Users: http://roccat.sourceforge.net
  80 +
  81 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/keys_thumbster
  82 +Date: June 2011
  83 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  84 +Description: When written, this file lets one set the function of the
  85 + thumbster keys for a specific profile. Profile number is included
  86 + in written data. The data has to be 23 bytes long.
  87 + Before reading this file, control has to be written to select
  88 + which profile to read.
  89 +Users: http://roccat.sourceforge.net
  90 +
  91 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/last_set
  92 +Date: June 2011
  93 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  94 +Description: When written, this file lets one set the time in secs since
  95 + epoch in which the last configuration took place.
  96 + The data has to be 20 bytes long.
  97 +Users: http://roccat.sourceforge.net
  98 +
  99 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/light
  100 +Date: June 2011
  101 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  102 +Description: When written, this file lets one set the backlight intensity for
  103 + a specific profile. Profile number is included in written data.
  104 + The data has to be 10 bytes long.
  105 + Before reading this file, control has to be written to select
  106 + which profile to read.
  107 +Users: http://roccat.sourceforge.net
  108 +
  109 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/macro
  110 +Date: June 2011
  111 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  112 +Description: When written, this file lets one store macros with max 500
  113 + keystrokes for a specific button for a specific profile.
  114 + Button and profile numbers are included in written data.
  115 + The data has to be 2083 bytes long.
  116 + Before reading this file, control has to be written to select
  117 + which profile and key to read.
  118 +Users: http://roccat.sourceforge.net
  119 +
  120 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/control
  121 +Date: June 2011
  122 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  123 +Description: When written, this file lets one select which data from which
  124 + profile will be read next. The data has to be 3 bytes long.
  125 + This file is writeonly.
  126 +Users: http://roccat.sourceforge.net
  127 +
  128 +What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talk
  129 +Date: June 2011
  130 +Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
  131 +Description: When written, this file lets one trigger easyshift functionality
  132 + from the host.
  133 + The data has to be 16 bytes long.
  134 + This file is writeonly.
  135 +Users: http://roccat.sourceforge.net
... ... @@ -492,6 +492,13 @@
492 492 ---help---
493 493 Support for Roccat Arvo keyboard.
494 494  
  495 +config HID_ROCCAT_ISKU
  496 + tristate "Roccat Isku keyboard support"
  497 + depends on USB_HID
  498 + depends on HID_ROCCAT
  499 + ---help---
  500 + Support for Roccat Isku keyboard.
  501 +
495 502 config HID_ROCCAT_KONE
496 503 tristate "Roccat Kone Mouse support"
497 504 depends on USB_HID
drivers/hid/Makefile
... ... @@ -59,6 +59,7 @@
59 59 obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
60 60 obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
61 61 obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
  62 +obj-$(CONFIG_HID_ROCCAT_ISKU) += hid-roccat-isku.o
62 63 obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
63 64 obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
64 65 obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
drivers/hid/hid-core.c
... ... @@ -1503,6 +1503,7 @@
1503 1503 { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
1504 1504 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
1505 1505 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
  1506 + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
1506 1507 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
1507 1508 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
1508 1509 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
drivers/hid/hid-ids.h
... ... @@ -586,6 +586,7 @@
586 586  
587 587 #define USB_VENDOR_ID_ROCCAT 0x1e7d
588 588 #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
  589 +#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
589 590 #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
590 591 #define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
591 592 #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
drivers/hid/hid-roccat-isku.c
  1 +/*
  2 + * Roccat Isku driver for Linux
  3 + *
  4 + * Copyright (c) 2011 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 Isku is a gamer keyboard with macro keys that can be configured in
  16 + * 5 profiles.
  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-isku.h"
  28 +
  29 +static struct class *isku_class;
  30 +
  31 +static void isku_profile_activated(struct isku_device *isku, uint new_profile)
  32 +{
  33 + isku->actual_profile = new_profile;
  34 +}
  35 +
  36 +static int isku_receive(struct usb_device *usb_dev, uint command,
  37 + void *buf, uint size)
  38 +{
  39 + return roccat_common_receive(usb_dev, command, buf, size);
  40 +}
  41 +
  42 +static int isku_receive_control_status(struct usb_device *usb_dev)
  43 +{
  44 + int retval;
  45 + struct isku_control control;
  46 +
  47 + do {
  48 + msleep(50);
  49 + retval = isku_receive(usb_dev, ISKU_COMMAND_CONTROL,
  50 + &control, sizeof(struct isku_control));
  51 +
  52 + if (retval)
  53 + return retval;
  54 +
  55 + switch (control.value) {
  56 + case ISKU_CONTROL_VALUE_STATUS_OK:
  57 + return 0;
  58 + case ISKU_CONTROL_VALUE_STATUS_WAIT:
  59 + continue;
  60 + case ISKU_CONTROL_VALUE_STATUS_INVALID:
  61 + /* seems to be critical - replug necessary */
  62 + case ISKU_CONTROL_VALUE_STATUS_OVERLOAD:
  63 + return -EINVAL;
  64 + default:
  65 + hid_err(usb_dev, "isku_receive_control_status: "
  66 + "unknown response value 0x%x\n",
  67 + control.value);
  68 + return -EINVAL;
  69 + }
  70 +
  71 + } while (1);
  72 +}
  73 +
  74 +static int isku_send(struct usb_device *usb_dev, uint command,
  75 + void const *buf, uint size)
  76 +{
  77 + int retval;
  78 +
  79 + retval = roccat_common_send(usb_dev, command, buf, size);
  80 + if (retval)
  81 + return retval;
  82 +
  83 + return isku_receive_control_status(usb_dev);
  84 +}
  85 +
  86 +static int isku_get_actual_profile(struct usb_device *usb_dev)
  87 +{
  88 + struct isku_actual_profile buf;
  89 + int retval;
  90 +
  91 + retval = isku_receive(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE,
  92 + &buf, sizeof(struct isku_actual_profile));
  93 + return retval ? retval : buf.actual_profile;
  94 +}
  95 +
  96 +static int isku_set_actual_profile(struct usb_device *usb_dev, int new_profile)
  97 +{
  98 + struct isku_actual_profile buf;
  99 +
  100 + buf.command = ISKU_COMMAND_ACTUAL_PROFILE;
  101 + buf.size = sizeof(struct isku_actual_profile);
  102 + buf.actual_profile = new_profile;
  103 + return isku_send(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, &buf,
  104 + sizeof(struct isku_actual_profile));
  105 +}
  106 +
  107 +static ssize_t isku_sysfs_show_actual_profile(struct device *dev,
  108 + struct device_attribute *attr, char *buf)
  109 +{
  110 + struct isku_device *isku =
  111 + hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
  112 + return snprintf(buf, PAGE_SIZE, "%d\n", isku->actual_profile);
  113 +}
  114 +
  115 +static ssize_t isku_sysfs_set_actual_profile(struct device *dev,
  116 + struct device_attribute *attr, char const *buf, size_t size)
  117 +{
  118 + struct isku_device *isku;
  119 + struct usb_device *usb_dev;
  120 + unsigned long profile;
  121 + int retval;
  122 + struct isku_roccat_report roccat_report;
  123 +
  124 + dev = dev->parent->parent;
  125 + isku = hid_get_drvdata(dev_get_drvdata(dev));
  126 + usb_dev = interface_to_usbdev(to_usb_interface(dev));
  127 +
  128 + retval = strict_strtoul(buf, 10, &profile);
  129 + if (retval)
  130 + return retval;
  131 +
  132 + if (profile > 4)
  133 + return -EINVAL;
  134 +
  135 + mutex_lock(&isku->isku_lock);
  136 +
  137 + retval = isku_set_actual_profile(usb_dev, profile);
  138 + if (retval) {
  139 + mutex_unlock(&isku->isku_lock);
  140 + return retval;
  141 + }
  142 +
  143 + isku_profile_activated(isku, profile);
  144 +
  145 + roccat_report.event = ISKU_REPORT_BUTTON_EVENT_PROFILE;
  146 + roccat_report.data1 = profile + 1;
  147 + roccat_report.data2 = 0;
  148 + roccat_report.profile = profile + 1;
  149 + roccat_report_event(isku->chrdev_minor, (uint8_t const *)&roccat_report);
  150 +
  151 + mutex_unlock(&isku->isku_lock);
  152 +
  153 + return size;
  154 +}
  155 +
  156 +static struct device_attribute isku_attributes[] = {
  157 + __ATTR(actual_profile, 0660,
  158 + isku_sysfs_show_actual_profile,
  159 + isku_sysfs_set_actual_profile),
  160 + __ATTR_NULL
  161 +};
  162 +
  163 +static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
  164 + char *buf, loff_t off, size_t count,
  165 + size_t real_size, uint command)
  166 +{
  167 + struct device *dev =
  168 + container_of(kobj, struct device, kobj)->parent->parent;
  169 + struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
  170 + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  171 + int retval;
  172 +
  173 + if (off >= real_size)
  174 + return 0;
  175 +
  176 + if (off != 0 || count != real_size)
  177 + return -EINVAL;
  178 +
  179 + mutex_lock(&isku->isku_lock);
  180 + retval = isku_receive(usb_dev, command, buf, real_size);
  181 + mutex_unlock(&isku->isku_lock);
  182 +
  183 + return retval ? retval : real_size;
  184 +}
  185 +
  186 +static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
  187 + void const *buf, loff_t off, size_t count,
  188 + size_t real_size, uint command)
  189 +{
  190 + struct device *dev =
  191 + container_of(kobj, struct device, kobj)->parent->parent;
  192 + struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev));
  193 + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
  194 + int retval;
  195 +
  196 + if (off != 0 || count != real_size)
  197 + return -EINVAL;
  198 +
  199 + mutex_lock(&isku->isku_lock);
  200 + retval = isku_send(usb_dev, command, (void *)buf, real_size);
  201 + mutex_unlock(&isku->isku_lock);
  202 +
  203 + return retval ? retval : real_size;
  204 +}
  205 +
  206 +#define ISKU_SYSFS_W(thingy, THINGY) \
  207 +static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj, \
  208 + struct bin_attribute *attr, char *buf, \
  209 + loff_t off, size_t count) \
  210 +{ \
  211 + return isku_sysfs_write(fp, kobj, buf, off, count, \
  212 + sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \
  213 +}
  214 +
  215 +#define ISKU_SYSFS_R(thingy, THINGY) \
  216 +static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj, \
  217 + struct bin_attribute *attr, char *buf, \
  218 + loff_t off, size_t count) \
  219 +{ \
  220 + return isku_sysfs_read(fp, kobj, buf, off, count, \
  221 + sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \
  222 +}
  223 +
  224 +#define ISKU_SYSFS_RW(thingy, THINGY) \
  225 +ISKU_SYSFS_R(thingy, THINGY) \
  226 +ISKU_SYSFS_W(thingy, THINGY)
  227 +
  228 +#define ISKU_BIN_ATTR_RW(thingy) \
  229 +{ \
  230 + .attr = { .name = #thingy, .mode = 0660 }, \
  231 + .size = sizeof(struct isku_ ## thingy), \
  232 + .read = isku_sysfs_read_ ## thingy, \
  233 + .write = isku_sysfs_write_ ## thingy \
  234 +}
  235 +
  236 +#define ISKU_BIN_ATTR_R(thingy) \
  237 +{ \
  238 + .attr = { .name = #thingy, .mode = 0440 }, \
  239 + .size = sizeof(struct isku_ ## thingy), \
  240 + .read = isku_sysfs_read_ ## thingy, \
  241 +}
  242 +
  243 +#define ISKU_BIN_ATTR_W(thingy) \
  244 +{ \
  245 + .attr = { .name = #thingy, .mode = 0220 }, \
  246 + .size = sizeof(struct isku_ ## thingy), \
  247 + .write = isku_sysfs_write_ ## thingy \
  248 +}
  249 +
  250 +ISKU_SYSFS_RW(macro, MACRO)
  251 +ISKU_SYSFS_RW(keys_function, KEYS_FUNCTION)
  252 +ISKU_SYSFS_RW(keys_easyzone, KEYS_EASYZONE)
  253 +ISKU_SYSFS_RW(keys_media, KEYS_MEDIA)
  254 +ISKU_SYSFS_RW(keys_thumbster, KEYS_THUMBSTER)
  255 +ISKU_SYSFS_RW(keys_macro, KEYS_MACRO)
  256 +ISKU_SYSFS_RW(keys_capslock, KEYS_CAPSLOCK)
  257 +ISKU_SYSFS_RW(light, LIGHT)
  258 +ISKU_SYSFS_RW(key_mask, KEY_MASK)
  259 +ISKU_SYSFS_RW(last_set, LAST_SET)
  260 +ISKU_SYSFS_W(talk, TALK)
  261 +ISKU_SYSFS_R(info, INFO)
  262 +ISKU_SYSFS_W(control, CONTROL)
  263 +
  264 +static struct bin_attribute isku_bin_attributes[] = {
  265 + ISKU_BIN_ATTR_RW(macro),
  266 + ISKU_BIN_ATTR_RW(keys_function),
  267 + ISKU_BIN_ATTR_RW(keys_easyzone),
  268 + ISKU_BIN_ATTR_RW(keys_media),
  269 + ISKU_BIN_ATTR_RW(keys_thumbster),
  270 + ISKU_BIN_ATTR_RW(keys_macro),
  271 + ISKU_BIN_ATTR_RW(keys_capslock),
  272 + ISKU_BIN_ATTR_RW(light),
  273 + ISKU_BIN_ATTR_RW(key_mask),
  274 + ISKU_BIN_ATTR_RW(last_set),
  275 + ISKU_BIN_ATTR_W(talk),
  276 + ISKU_BIN_ATTR_R(info),
  277 + ISKU_BIN_ATTR_W(control),
  278 + __ATTR_NULL
  279 +};
  280 +
  281 +static int isku_init_isku_device_struct(struct usb_device *usb_dev,
  282 + struct isku_device *isku)
  283 +{
  284 + int retval;
  285 +
  286 + mutex_init(&isku->isku_lock);
  287 +
  288 + retval = isku_get_actual_profile(usb_dev);
  289 + if (retval < 0)
  290 + return retval;
  291 + isku_profile_activated(isku, retval);
  292 +
  293 + return 0;
  294 +}
  295 +
  296 +static int isku_init_specials(struct hid_device *hdev)
  297 +{
  298 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  299 + struct usb_device *usb_dev = interface_to_usbdev(intf);
  300 + struct isku_device *isku;
  301 + int retval;
  302 +
  303 + if (intf->cur_altsetting->desc.bInterfaceProtocol
  304 + != ISKU_USB_INTERFACE_PROTOCOL) {
  305 + hid_set_drvdata(hdev, NULL);
  306 + return 0;
  307 + }
  308 +
  309 + isku = kzalloc(sizeof(*isku), GFP_KERNEL);
  310 + if (!isku) {
  311 + hid_err(hdev, "can't alloc device descriptor\n");
  312 + return -ENOMEM;
  313 + }
  314 + hid_set_drvdata(hdev, isku);
  315 +
  316 + retval = isku_init_isku_device_struct(usb_dev, isku);
  317 + if (retval) {
  318 + hid_err(hdev, "couldn't init struct isku_device\n");
  319 + goto exit_free;
  320 + }
  321 +
  322 + retval = roccat_connect(isku_class, hdev,
  323 + sizeof(struct isku_roccat_report));
  324 + if (retval < 0) {
  325 + hid_err(hdev, "couldn't init char dev\n");
  326 + } else {
  327 + isku->chrdev_minor = retval;
  328 + isku->roccat_claimed = 1;
  329 + }
  330 +
  331 + return 0;
  332 +exit_free:
  333 + kfree(isku);
  334 + return retval;
  335 +}
  336 +
  337 +static void isku_remove_specials(struct hid_device *hdev)
  338 +{
  339 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  340 + struct isku_device *isku;
  341 +
  342 + if (intf->cur_altsetting->desc.bInterfaceProtocol
  343 + != ISKU_USB_INTERFACE_PROTOCOL)
  344 + return;
  345 +
  346 + isku = hid_get_drvdata(hdev);
  347 + if (isku->roccat_claimed)
  348 + roccat_disconnect(isku->chrdev_minor);
  349 + kfree(isku);
  350 +}
  351 +
  352 +static int isku_probe(struct hid_device *hdev,
  353 + const struct hid_device_id *id)
  354 +{
  355 + int retval;
  356 +
  357 + retval = hid_parse(hdev);
  358 + if (retval) {
  359 + hid_err(hdev, "parse failed\n");
  360 + goto exit;
  361 + }
  362 +
  363 + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
  364 + if (retval) {
  365 + hid_err(hdev, "hw start failed\n");
  366 + goto exit;
  367 + }
  368 +
  369 + retval = isku_init_specials(hdev);
  370 + if (retval) {
  371 + hid_err(hdev, "couldn't install keyboard\n");
  372 + goto exit_stop;
  373 + }
  374 +
  375 + return 0;
  376 +
  377 +exit_stop:
  378 + hid_hw_stop(hdev);
  379 +exit:
  380 + return retval;
  381 +}
  382 +
  383 +static void isku_remove(struct hid_device *hdev)
  384 +{
  385 + isku_remove_specials(hdev);
  386 + hid_hw_stop(hdev);
  387 +}
  388 +
  389 +static void isku_keep_values_up_to_date(struct isku_device *isku,
  390 + u8 const *data)
  391 +{
  392 + struct isku_report_button const *button_report;
  393 +
  394 + switch (data[0]) {
  395 + case ISKU_REPORT_NUMBER_BUTTON:
  396 + button_report = (struct isku_report_button const *)data;
  397 + switch (button_report->event) {
  398 + case ISKU_REPORT_BUTTON_EVENT_PROFILE:
  399 + isku_profile_activated(isku, button_report->data1 - 1);
  400 + break;
  401 + }
  402 + break;
  403 + }
  404 +}
  405 +
  406 +static void isku_report_to_chrdev(struct isku_device const *isku,
  407 + u8 const *data)
  408 +{
  409 + struct isku_roccat_report roccat_report;
  410 + struct isku_report_button const *button_report;
  411 +
  412 + if (data[0] != ISKU_REPORT_NUMBER_BUTTON)
  413 + return;
  414 +
  415 + button_report = (struct isku_report_button const *)data;
  416 +
  417 + roccat_report.event = button_report->event;
  418 + roccat_report.data1 = button_report->data1;
  419 + roccat_report.data2 = button_report->data2;
  420 + roccat_report.profile = isku->actual_profile + 1;
  421 + roccat_report_event(isku->chrdev_minor,
  422 + (uint8_t const *)&roccat_report);
  423 +}
  424 +
  425 +static int isku_raw_event(struct hid_device *hdev,
  426 + struct hid_report *report, u8 *data, int size)
  427 +{
  428 + struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  429 + struct isku_device *isku = hid_get_drvdata(hdev);
  430 +
  431 + if (intf->cur_altsetting->desc.bInterfaceProtocol
  432 + != ISKU_USB_INTERFACE_PROTOCOL)
  433 + return 0;
  434 +
  435 + if (isku == NULL)
  436 + return 0;
  437 +
  438 + isku_keep_values_up_to_date(isku, data);
  439 +
  440 + if (isku->roccat_claimed)
  441 + isku_report_to_chrdev(isku, data);
  442 +
  443 + return 0;
  444 +}
  445 +
  446 +static const struct hid_device_id isku_devices[] = {
  447 + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
  448 + { }
  449 +};
  450 +
  451 +MODULE_DEVICE_TABLE(hid, isku_devices);
  452 +
  453 +static struct hid_driver isku_driver = {
  454 + .name = "isku",
  455 + .id_table = isku_devices,
  456 + .probe = isku_probe,
  457 + .remove = isku_remove,
  458 + .raw_event = isku_raw_event
  459 +};
  460 +
  461 +static int __init isku_init(void)
  462 +{
  463 + int retval;
  464 + isku_class = class_create(THIS_MODULE, "isku");
  465 + if (IS_ERR(isku_class))
  466 + return PTR_ERR(isku_class);
  467 + isku_class->dev_attrs = isku_attributes;
  468 + isku_class->dev_bin_attrs = isku_bin_attributes;
  469 +
  470 + retval = hid_register_driver(&isku_driver);
  471 + if (retval)
  472 + class_destroy(isku_class);
  473 + return retval;
  474 +}
  475 +
  476 +static void __exit isku_exit(void)
  477 +{
  478 + hid_unregister_driver(&isku_driver);
  479 + class_destroy(isku_class);
  480 +}
  481 +
  482 +module_init(isku_init);
  483 +module_exit(isku_exit);
  484 +
  485 +MODULE_AUTHOR("Stefan Achatz");
  486 +MODULE_DESCRIPTION("USB Roccat Isku driver");
  487 +MODULE_LICENSE("GPL v2");
drivers/hid/hid-roccat-isku.h
  1 +#ifndef __HID_ROCCAT_ISKU_H
  2 +#define __HID_ROCCAT_ISKU_H
  3 +
  4 +/*
  5 + * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
  6 + */
  7 +
  8 +/*
  9 + * This program is free software; you can redistribute it and/or modify it
  10 + * under the terms of the GNU General Public License as published by the Free
  11 + * Software Foundation; either version 2 of the License, or (at your option)
  12 + * any later version.
  13 + */
  14 +
  15 +#include <linux/types.h>
  16 +
  17 +enum {
  18 + ISKU_PROFILE_NUM = 5,
  19 + ISKU_USB_INTERFACE_PROTOCOL = 0,
  20 +};
  21 +
  22 +struct isku_control {
  23 + uint8_t command; /* ISKU_COMMAND_CONTROL */
  24 + uint8_t value;
  25 + uint8_t request;
  26 +} __packed;
  27 +
  28 +enum isku_control_values {
  29 + ISKU_CONTROL_VALUE_STATUS_OVERLOAD = 0,
  30 + ISKU_CONTROL_VALUE_STATUS_OK = 1,
  31 + ISKU_CONTROL_VALUE_STATUS_INVALID = 2,
  32 + ISKU_CONTROL_VALUE_STATUS_WAIT = 3,
  33 +};
  34 +
  35 +struct isku_actual_profile {
  36 + uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */
  37 + uint8_t size; /* always 3 */
  38 + uint8_t actual_profile;
  39 +} __packed;
  40 +
  41 +struct isku_key_mask {
  42 + uint8_t command; /* ISKU_COMMAND_KEY_MASK */
  43 + uint8_t size; /* 6 */
  44 + uint8_t profile_number; /* 0-4 */
  45 + uint8_t mask;
  46 + uint16_t checksum;
  47 +} __packed;
  48 +
  49 +struct isku_keys_function {
  50 + uint8_t data[0x29];
  51 +} __packed;
  52 +
  53 +struct isku_keys_easyzone {
  54 + uint8_t data[0x41];
  55 +} __packed;
  56 +
  57 +struct isku_keys_media {
  58 + uint8_t data[0x1d];
  59 +} __packed;
  60 +
  61 +struct isku_keys_thumbster {
  62 + uint8_t data[0x17];
  63 +} __packed;
  64 +
  65 +struct isku_keys_macro {
  66 + uint8_t data[0x23];
  67 +} __packed;
  68 +
  69 +struct isku_keys_capslock {
  70 + uint8_t data[0x6];
  71 +} __packed;
  72 +
  73 +struct isku_macro {
  74 + uint8_t data[0x823];
  75 +} __packed;
  76 +
  77 +struct isku_light {
  78 + uint8_t data[0xa];
  79 +} __packed;
  80 +
  81 +struct isku_info {
  82 + uint8_t data[2];
  83 + uint8_t firmware_version;
  84 + uint8_t unknown[3];
  85 +} __packed;
  86 +
  87 +struct isku_talk {
  88 + uint8_t data[0x10];
  89 +} __packed;
  90 +
  91 +struct isku_last_set {
  92 + uint8_t data[0x14];
  93 +} __packed;
  94 +
  95 +enum isku_commands {
  96 + ISKU_COMMAND_CONTROL = 0x4,
  97 + ISKU_COMMAND_ACTUAL_PROFILE = 0x5,
  98 + ISKU_COMMAND_KEY_MASK = 0x7,
  99 + ISKU_COMMAND_KEYS_FUNCTION = 0x8,
  100 + ISKU_COMMAND_KEYS_EASYZONE = 0x9,
  101 + ISKU_COMMAND_KEYS_MEDIA = 0xa,
  102 + ISKU_COMMAND_KEYS_THUMBSTER = 0xb,
  103 + ISKU_COMMAND_KEYS_MACRO = 0xd,
  104 + ISKU_COMMAND_MACRO = 0xe,
  105 + ISKU_COMMAND_INFO = 0xf,
  106 + ISKU_COMMAND_LIGHT = 0x10,
  107 + ISKU_COMMAND_KEYS_CAPSLOCK = 0x13,
  108 + ISKU_COMMAND_LAST_SET = 0x14,
  109 + ISKU_COMMAND_15 = 0x15,
  110 + ISKU_COMMAND_TALK = 0x16,
  111 + ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
  112 + ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
  113 +};
  114 +
  115 +struct isku_report_button {
  116 + uint8_t number; /* ISKU_REPORT_NUMBER_BUTTON */
  117 + uint8_t zero;
  118 + uint8_t event;
  119 + uint8_t data1;
  120 + uint8_t data2;
  121 +};
  122 +
  123 +enum isku_report_numbers {
  124 + ISKU_REPORT_NUMBER_BUTTON = 3,
  125 +};
  126 +
  127 +enum isku_report_button_events {
  128 + ISKU_REPORT_BUTTON_EVENT_PROFILE = 0x2,
  129 +};
  130 +
  131 +struct isku_roccat_report {
  132 + uint8_t event;
  133 + uint8_t data1;
  134 + uint8_t data2;
  135 + uint8_t profile;
  136 +} __packed;
  137 +
  138 +struct isku_device {
  139 + int roccat_claimed;
  140 + int chrdev_minor;
  141 +
  142 + struct mutex isku_lock;
  143 +
  144 + int actual_profile;
  145 +};
  146 +
  147 +#endif