From f963d270cb7bbb8eeb57901d02b22a493e664fd2 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 8 Aug 2011 11:40:17 +0200 Subject: cciss: add transport mode attribute to sys Signed-off-by: Joseph Handzik Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-bus-pci-devices-cciss | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss index f5bb0a3bb8c0..53d99edd1d75 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss @@ -71,3 +71,10 @@ Description: Value of 1 indicates the controller can honor the reset_devices a dump device, as kdump requires resetting the device in order to work reliably. +Where: /sys/bus/pci/devices//ccissX/transport_mode +Date: July 2011 +Kernel Version: 3.0 +Contact: iss_storagedev@hp.com +Description: Value of "simple" indicates that the controller has been placed + in "simple mode". Value of "performant" indicates that the + controller has been placed in "performant mode". -- cgit v1.2.3 From 362b646062b2073bd5c38efb42171d86e4f717e6 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 4 Nov 2011 03:33:46 +0100 Subject: ACPI: Export FADT pm_profile integer value to userspace There are a lot userspace approaches to detect the usage of the platform (laptop, workstation, server, ...) and adjust kernel tunables accordingly (io/process scheduler, power management, ...). These approaches need constant maintaining and are ugly to implement (detect PCMCIA controller -> laptop, does not work on recent systems anymore, ...) On ACPI systems there is an easy and reliable way (if implemented in BIOS and most recent platforms have this value set). -> export it to userspace. Signed-off-by: Thomas Renninger Acked-by: Rafael J. Wysocki Signed-off-by: Len Brown --- Documentation/ABI/stable/sysfs-acpi-pmprofile | 22 ++++++++++++++++++++++ drivers/acpi/sysfs.c | 14 +++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/stable/sysfs-acpi-pmprofile (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/stable/sysfs-acpi-pmprofile b/Documentation/ABI/stable/sysfs-acpi-pmprofile new file mode 100644 index 000000000000..964c7a8afb26 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-acpi-pmprofile @@ -0,0 +1,22 @@ +What: /sys/firmware/acpi/pm_profile +Date: 03-Nov-2011 +KernelVersion: v3.2 +Contact: linux-acpi@vger.kernel.org +Description: The ACPI pm_profile sysfs interface exports the platform + power management (and performance) requirement expectations + as provided by BIOS. The integer value is directly passed as + retrieved from the FADT ACPI table. +Values: For possible values see ACPI specification: + 5.2.9 Fixed ACPI Description Table (FADT) + Field: Preferred_PM_Profile + + Currently these values are defined by spec: + 0 Unspecified + 1 Desktop + 2 Mobile + 3 Workstation + 4 Enterprise Server + 5 SOHO Server + 6 Appliance PC + 7 Performance Server + >7 Reserved diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index c538d0ef10ff..9f66181c814e 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -706,11 +706,23 @@ static void __exit interrupt_stats_exit(void) return; } +static ssize_t +acpi_show_profile(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); +} + +static const struct device_attribute pm_profile_attr = + __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); + int __init acpi_sysfs_init(void) { int result; result = acpi_tables_sysfs_init(); - + if (result) + return result; + result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); return result; } -- cgit v1.2.3 From d0985394e7fee6b25a7cc8335d45bc1c1a8ab2d3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 10 Nov 2011 09:03:55 +0100 Subject: block: Revert "[SCSI] genhd: add a new attribute "alias" in gendisk" This reverts commit a72c5e5eb738033938ab30d6a634b74d1d060f10. The commit introduced alias for block devices which is intended to be used during logging although actual usage hasn't been committed yet. This approach adds very limited benefit (raw log might be easier to follow) which can be trivially implemented in userland but has a lot of problems. It is much worse than netif renames because it doesn't rename the actual device but just adds conveninence name which isn't used universally or enforced. Everything internal including device lookup and sysfs still uses the internal name and nothing prevents two devices from using conflicting alias - ie. sda can have sdb as its alias. This has been nacked by people working on device driver core, block layer and kernel-userland interface and shouldn't have been upstreamed. Revert it. http://thread.gmane.org/gmane.linux.kernel/1155104 http://thread.gmane.org/gmane.linux.scsi/68632 http://thread.gmane.org/gmane.linux.scsi/69776 Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Acked-by: Kay Sievers Cc: "James E.J. Bottomley" Cc: Nao Nishijima Cc: Alan Cox Cc: Al Viro Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-block | 13 ------- block/genhd.c | 71 ----------------------------------- include/linux/genhd.h | 4 -- 3 files changed, 88 deletions(-) (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block index 2b5d56127fce..c1eb41cb9876 100644 --- a/Documentation/ABI/testing/sysfs-block +++ b/Documentation/ABI/testing/sysfs-block @@ -206,16 +206,3 @@ Description: when a discarded area is read the discard_zeroes_data parameter will be set to one. Otherwise it will be 0 and the result of reading a discarded area is undefined. -What: /sys/block//alias -Date: Aug 2011 -Contact: Nao Nishijima -Description: - A raw device name of a disk does not always point a same disk - each boot-up time. Therefore, users have to use persistent - device names, which udev creates when the kernel finds a disk, - instead of raw device name. However, kernel doesn't show those - persistent names on its messages (e.g. dmesg). - This file can store an alias of the disk and it would be - appeared in kernel messages if it is set. A disk can have an - alias which length is up to 255bytes. Users can use alphabets, - numbers, "-" and "_" in alias name. This file is writeonce. diff --git a/block/genhd.c b/block/genhd.c index 9253839714ff..02e9fca80825 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "blk.h" @@ -916,74 +915,6 @@ static int __init genhd_device_init(void) subsys_initcall(genhd_device_init); -static ssize_t alias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - ssize_t ret = 0; - - if (disk->alias) - ret = snprintf(buf, ALIAS_LEN, "%s\n", disk->alias); - return ret; -} - -static ssize_t alias_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gendisk *disk = dev_to_disk(dev); - char *alias; - char *envp[] = { NULL, NULL }; - unsigned char c; - int i; - ssize_t ret = count; - - if (!count) - return -EINVAL; - - if (count >= ALIAS_LEN) { - printk(KERN_ERR "alias: alias is too long\n"); - return -EINVAL; - } - - /* Validation check */ - for (i = 0; i < count; i++) { - c = buf[i]; - if (i == count - 1 && c == '\n') - break; - if (!isalnum(c) && c != '_' && c != '-') { - printk(KERN_ERR "alias: invalid alias\n"); - return -EINVAL; - } - } - - if (disk->alias) { - printk(KERN_INFO "alias: %s is already assigned (%s)\n", - disk->disk_name, disk->alias); - return -EINVAL; - } - - alias = kasprintf(GFP_KERNEL, "%s", buf); - if (!alias) - return -ENOMEM; - - if (alias[count - 1] == '\n') - alias[count - 1] = '\0'; - - envp[0] = kasprintf(GFP_KERNEL, "ALIAS=%s", alias); - if (!envp[0]) { - kfree(alias); - return -ENOMEM; - } - - disk->alias = alias; - printk(KERN_INFO "alias: assigned %s to %s\n", alias, disk->disk_name); - - kobject_uevent_env(&dev->kobj, KOBJ_ADD, envp); - - kfree(envp[0]); - return ret; -} - static ssize_t disk_range_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1043,7 +974,6 @@ static ssize_t disk_discard_alignment_show(struct device *dev, return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); } -static DEVICE_ATTR(alias, S_IRUGO|S_IWUSR, alias_show, alias_store); static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); @@ -1066,7 +996,6 @@ static struct device_attribute dev_attr_fail_timeout = #endif static struct attribute *disk_attrs[] = { - &dev_attr_alias.attr, &dev_attr_range.attr, &dev_attr_ext_range.attr, &dev_attr_removable.attr, diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 9de31bc98c88..6d18f3531f18 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -21,8 +21,6 @@ #define dev_to_part(device) container_of((device), struct hd_struct, __dev) #define disk_to_dev(disk) (&(disk)->part0.__dev) #define part_to_dev(part) (&((part)->__dev)) -#define alias_name(disk) ((disk)->alias ? (disk)->alias : \ - (disk)->disk_name) extern struct device_type part_type; extern struct kobject *block_depr; @@ -60,7 +58,6 @@ enum { #define DISK_MAX_PARTS 256 #define DISK_NAME_LEN 32 -#define ALIAS_LEN 256 #include #include @@ -166,7 +163,6 @@ struct gendisk { * disks that can't be partitioned. */ char disk_name[DISK_NAME_LEN]; /* name of major driver */ - char *alias; /* alias name of disk */ char *(*devnode)(struct gendisk *gd, mode_t *mode); unsigned int events; /* supported events */ -- cgit v1.2.3 From c1e51398a14bd74c58a838e9e76e8f726c5643b9 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 17 Nov 2011 14:12:04 +0100 Subject: HID: wiimote: Add extension sysfs attribute Add new sysfs attribute "extension" which returns the currently connected and initialized extensions. Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-hid-wiimote | 12 ++++++ drivers/hid/hid-wiimote-ext.c | 46 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote index 5d5a16ea57c6..3d98009f447a 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote +++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote @@ -8,3 +8,15 @@ Contact: David Herrmann Description: Make it possible to set/get current led state. Reading from it returns 0 if led is off and 1 if it is on. Writing 0 to it disables the led, writing 1 enables it. + +What: /sys/bus/hid/drivers/wiimote//extension +Date: August 2011 +KernelVersion: 3.2 +Contact: David Herrmann +Description: This file contains the currently connected and initialized + extensions. It can be one of: none, motionp, nunchuck, classic, + motionp+nunchuck, motionp+classic + motionp is the official Nintendo Motion+ extension, nunchuck is + the official Nintendo Nunchuck extension and classic is the + Nintendo Classic Controller extension. The motionp extension can + be combined with the other two. diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c index 233bdfe3205b..477513dfeb7a 100644 --- a/drivers/hid/hid-wiimote-ext.c +++ b/drivers/hid/hid-wiimote-ext.c @@ -199,11 +199,47 @@ bool wiiext_active(struct wiimote_data *wdata) return wdata->ext->motionp || wdata->ext->ext_type; } +static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wiimote_data *wdata = dev_to_wii(dev); + __u8 type = WIIEXT_NONE; + bool motionp = false; + unsigned long flags; + + spin_lock_irqsave(&wdata->state.lock, flags); + if (wdata->ext) { + motionp = wdata->ext->motionp; + type = wdata->ext->ext_type; + } + spin_unlock_irqrestore(&wdata->state.lock, flags); + + if (type == WIIEXT_NUNCHUCK) { + if (motionp) + return sprintf(buf, "motionp+nunchuck\n"); + else + return sprintf(buf, "nunchuck\n"); + } else if (type == WIIEXT_CLASSIC) { + if (motionp) + return sprintf(buf, "motionp+classic\n"); + else + return sprintf(buf, "classic\n"); + } else { + if (motionp) + return sprintf(buf, "motionp\n"); + else + return sprintf(buf, "none\n"); + } +} + +static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL); + /* Initializes the extension driver of a wiimote */ int wiiext_init(struct wiimote_data *wdata) { struct wiimote_ext *ext; unsigned long flags; + int ret; ext = kzalloc(sizeof(*ext), GFP_KERNEL); if (!ext) @@ -212,11 +248,19 @@ int wiiext_init(struct wiimote_data *wdata) ext->wdata = wdata; INIT_WORK(&ext->worker, wiiext_worker); + ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension); + if (ret) + goto err; + spin_lock_irqsave(&wdata->state.lock, flags); wdata->ext = ext; spin_unlock_irqrestore(&wdata->state.lock, flags); return 0; + +err: + kfree(ext); + return ret; } /* Deinitializes the extension driver of a wiimote */ @@ -240,6 +284,8 @@ void wiiext_deinit(struct wiimote_data *wdata) wdata->ext = NULL; spin_unlock_irqrestore(&wdata->state.lock, flags); + device_remove_file(&wdata->hdev->dev, &dev_attr_extension); + cancel_work_sync(&ext->worker); kfree(ext); } -- cgit v1.2.3 From eec29e3dab483a5d9a742a6fa68db1ec1f0f7504 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 23 Nov 2011 10:54:28 +0100 Subject: HID: multitouch: create sysfs attribute to control quirks from user-space Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-multitouch | 9 +++ drivers/hid/hid-multitouch.c | 77 +++++++++++++++++----- 2 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-multitouch (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-multitouch b/Documentation/ABI/testing/sysfs-driver-hid-multitouch new file mode 100644 index 000000000000..f79839d1af37 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-multitouch @@ -0,0 +1,9 @@ +What: /sys/bus/usb/devices/-:./::./quirks +Date: November 2011 +Contact: Benjamin Tissoires +Description: The integer value of this attribute corresponds to the + quirks actually in place to handle the device's protocol. + When read, this attribute returns the current settings (see + MT_QUIRKS_* in hid-multitouch.c). + When written this attribute change on the fly the quirks, then + the protocol to handle the device. diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index a59d939dd165..a51e62efbac1 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -60,9 +60,19 @@ struct mt_slot { bool seen_in_this_frame;/* has this slot been updated */ }; +struct mt_class { + __s32 name; /* MT_CLS */ + __s32 quirks; + __s32 sn_move; /* Signal/noise ratio for move events */ + __s32 sn_width; /* Signal/noise ratio for width events */ + __s32 sn_height; /* Signal/noise ratio for height events */ + __s32 sn_pressure; /* Signal/noise ratio for pressure events */ + __u8 maxcontacts; +}; + struct mt_device { struct mt_slot curdata; /* placeholder of incoming data */ - struct mt_class *mtclass; /* our mt device class */ + struct mt_class mtclass; /* our mt device class */ unsigned last_field_index; /* last field index of the report */ unsigned last_slot_field; /* the last field of a slot */ int last_mt_collection; /* last known mt-related collection */ @@ -74,16 +84,6 @@ struct mt_device { struct mt_slot *slots; }; -struct mt_class { - __s32 name; /* MT_CLS */ - __s32 quirks; - __s32 sn_move; /* Signal/noise ratio for move events */ - __s32 sn_width; /* Signal/noise ratio for width events */ - __s32 sn_height; /* Signal/noise ratio for height events */ - __s32 sn_pressure; /* Signal/noise ratio for pressure events */ - __u8 maxcontacts; -}; - /* classes of device behavior */ #define MT_CLS_DEFAULT 0x0001 @@ -181,6 +181,44 @@ struct mt_class mt_classes[] = { { } }; +static ssize_t mt_show_quirks(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct mt_device *td = hid_get_drvdata(hdev); + + return sprintf(buf, "%u\n", td->mtclass.quirks); +} + +static ssize_t mt_set_quirks(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct mt_device *td = hid_get_drvdata(hdev); + + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + td->mtclass.quirks = val; + + return count; +} + +static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); + +static struct attribute *sysfs_attrs[] = { + &dev_attr_quirks.attr, + NULL +}; + +static struct attribute_group mt_attribute_group = { + .attrs = sysfs_attrs +}; + static void mt_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { @@ -192,9 +230,9 @@ static void mt_feature_mapping(struct hid_device *hdev, break; case HID_DG_CONTACTMAX: td->maxcontacts = field->value[0]; - if (td->mtclass->maxcontacts) + if (td->mtclass.maxcontacts) /* check if the maxcontacts is given by the class */ - td->maxcontacts = td->mtclass->maxcontacts; + td->maxcontacts = td->mtclass.maxcontacts; break; } @@ -214,7 +252,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, unsigned long **bit, int *max) { struct mt_device *td = hid_get_drvdata(hdev); - struct mt_class *cls = td->mtclass; + struct mt_class *cls = &td->mtclass; __s32 quirks = cls->quirks; /* Only map fields from TouchScreen or TouchPad collections. @@ -363,7 +401,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, static int mt_compute_slot(struct mt_device *td) { - __s32 quirks = td->mtclass->quirks; + __s32 quirks = td->mtclass.quirks; if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) return td->curdata.contactid; @@ -407,7 +445,7 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) for (i = 0; i < td->maxcontacts; ++i) { struct mt_slot *s = &(td->slots[i]); - if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && + if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { s->touch_state = false; } @@ -444,7 +482,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct mt_device *td = hid_get_drvdata(hid); - __s32 quirks = td->mtclass->quirks; + __s32 quirks = td->mtclass.quirks; if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { switch (usage->hid) { @@ -552,7 +590,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) dev_err(&hdev->dev, "cannot allocate multitouch data\n"); return -ENOMEM; } - td->mtclass = mtclass; + td->mtclass = *mtclass; td->inputmode = -1; td->last_mt_collection = -1; hid_set_drvdata(hdev, td); @@ -574,6 +612,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail; } + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + mt_set_input_mode(hdev); return 0; @@ -594,6 +634,7 @@ static int mt_reset_resume(struct hid_device *hdev) static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); kfree(td->slots); kfree(td); -- cgit v1.2.3 From d41c2a7011dffc60571eab8dc4e2a297ef106f44 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Thu, 24 Nov 2011 17:46:24 +0100 Subject: 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 Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-roccat-isku | 135 ++++++ drivers/hid/Kconfig | 7 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-roccat-isku.c | 487 +++++++++++++++++++++ drivers/hid/hid-roccat-isku.h | 147 +++++++ 7 files changed, 779 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-hid-roccat-isku create mode 100644 drivers/hid/hid-roccat-isku.c create mode 100644 drivers/hid/hid-roccat-isku.h (limited to 'Documentation/ABI') diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku new file mode 100644 index 000000000000..189dc43891bf --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku @@ -0,0 +1,135 @@ +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/actual_profile +Date: June 2011 +Contact: Stefan Achatz +Description: The integer value of this attribute ranges from 0-4. + When read, this attribute returns the number of the actual + profile. This value is persistent, so its equivalent to the + profile that's active when the device is powered on next time. + When written, this file sets the number of the startup profile + and the device activates this profile immediately. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/info +Date: June 2011 +Contact: Stefan Achatz +Description: When read, this file returns general data like firmware version. + The data is 6 bytes long. + This file is readonly. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/key_mask +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one deactivate certain keys like + windows and application keys, to prevent accidental presses. + Profile number for which this settings occur is included in + written data. The data has to be 6 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_capslock +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the + capslock key for a specific profile. Profile number is included + in written data. The data has to be 6 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_easyzone +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the + easyzone keys for a specific profile. Profile number is included + in written data. The data has to be 65 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_function +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the + function keys for a specific profile. Profile number is included + in written data. The data has to be 41 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_macro +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the macro + keys for a specific profile. Profile number is included in + written data. The data has to be 35 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_media +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the media + keys for a specific profile. Profile number is included in + written data. The data has to be 29 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/keys_thumbster +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the function of the + thumbster keys for a specific profile. Profile number is included + in written data. The data has to be 23 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/last_set +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the time in secs since + epoch in which the last configuration took place. + The data has to be 20 bytes long. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/light +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one set the backlight intensity for + a specific profile. Profile number is included in written data. + The data has to be 10 bytes long. + Before reading this file, control has to be written to select + which profile to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/macro +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one store macros with max 500 + keystrokes for a specific button for a specific profile. + Button and profile numbers are included in written data. + The data has to be 2083 bytes long. + Before reading this file, control has to be written to select + which profile and key to read. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/control +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one select which data from which + profile will be read next. The data has to be 3 bytes long. + This file is writeonly. +Users: http://roccat.sourceforge.net + +What: /sys/bus/usb/devices/-:./::./isku/roccatisku/talk +Date: June 2011 +Contact: Stefan Achatz +Description: When written, this file lets one trigger easyshift functionality + from the host. + The data has to be 16 bytes long. + This file is writeonly. +Users: http://roccat.sourceforge.net diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 22a4a051f221..7f1190794290 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -492,6 +492,13 @@ config HID_ROCCAT_ARVO ---help--- Support for Roccat Arvo keyboard. +config HID_ROCCAT_ISKU + tristate "Roccat Isku keyboard support" + depends on USB_HID + depends on HID_ROCCAT + ---help--- + Support for Roccat Isku keyboard. + config HID_ROCCAT_KONE tristate "Roccat Kone Mouse support" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1e0d2a638b28..88660f7f3a55 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o +obj-$(CONFIG_HID_ROCCAT_ISKU) += hid-roccat-isku.o obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index af353842f75f..2f1672a49d56 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1503,6 +1503,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 4a441a6f9967..7d2fae1ebe50 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -586,6 +586,7 @@ #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 +#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced #define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51 #define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c new file mode 100644 index 000000000000..0e4a0ab47142 --- /dev/null +++ b/drivers/hid/hid-roccat-isku.c @@ -0,0 +1,487 @@ +/* + * Roccat Isku driver for Linux + * + * Copyright (c) 2011 Stefan Achatz + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +/* + * Roccat Isku is a gamer keyboard with macro keys that can be configured in + * 5 profiles. + */ + +#include +#include +#include +#include +#include +#include +#include "hid-ids.h" +#include "hid-roccat-common.h" +#include "hid-roccat-isku.h" + +static struct class *isku_class; + +static void isku_profile_activated(struct isku_device *isku, uint new_profile) +{ + isku->actual_profile = new_profile; +} + +static int isku_receive(struct usb_device *usb_dev, uint command, + void *buf, uint size) +{ + return roccat_common_receive(usb_dev, command, buf, size); +} + +static int isku_receive_control_status(struct usb_device *usb_dev) +{ + int retval; + struct isku_control control; + + do { + msleep(50); + retval = isku_receive(usb_dev, ISKU_COMMAND_CONTROL, + &control, sizeof(struct isku_control)); + + if (retval) + return retval; + + switch (control.value) { + case ISKU_CONTROL_VALUE_STATUS_OK: + return 0; + case ISKU_CONTROL_VALUE_STATUS_WAIT: + continue; + case ISKU_CONTROL_VALUE_STATUS_INVALID: + /* seems to be critical - replug necessary */ + case ISKU_CONTROL_VALUE_STATUS_OVERLOAD: + return -EINVAL; + default: + hid_err(usb_dev, "isku_receive_control_status: " + "unknown response value 0x%x\n", + control.value); + return -EINVAL; + } + + } while (1); +} + +static int isku_send(struct usb_device *usb_dev, uint command, + void const *buf, uint size) +{ + int retval; + + retval = roccat_common_send(usb_dev, command, buf, size); + if (retval) + return retval; + + return isku_receive_control_status(usb_dev); +} + +static int isku_get_actual_profile(struct usb_device *usb_dev) +{ + struct isku_actual_profile buf; + int retval; + + retval = isku_receive(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct isku_actual_profile)); + return retval ? retval : buf.actual_profile; +} + +static int isku_set_actual_profile(struct usb_device *usb_dev, int new_profile) +{ + struct isku_actual_profile buf; + + buf.command = ISKU_COMMAND_ACTUAL_PROFILE; + buf.size = sizeof(struct isku_actual_profile); + buf.actual_profile = new_profile; + return isku_send(usb_dev, ISKU_COMMAND_ACTUAL_PROFILE, &buf, + sizeof(struct isku_actual_profile)); +} + +static ssize_t isku_sysfs_show_actual_profile(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct isku_device *isku = + hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); + return snprintf(buf, PAGE_SIZE, "%d\n", isku->actual_profile); +} + +static ssize_t isku_sysfs_set_actual_profile(struct device *dev, + struct device_attribute *attr, char const *buf, size_t size) +{ + struct isku_device *isku; + struct usb_device *usb_dev; + unsigned long profile; + int retval; + struct isku_roccat_report roccat_report; + + dev = dev->parent->parent; + isku = hid_get_drvdata(dev_get_drvdata(dev)); + usb_dev = interface_to_usbdev(to_usb_interface(dev)); + + retval = strict_strtoul(buf, 10, &profile); + if (retval) + return retval; + + if (profile > 4) + return -EINVAL; + + mutex_lock(&isku->isku_lock); + + retval = isku_set_actual_profile(usb_dev, profile); + if (retval) { + mutex_unlock(&isku->isku_lock); + return retval; + } + + isku_profile_activated(isku, profile); + + roccat_report.event = ISKU_REPORT_BUTTON_EVENT_PROFILE; + roccat_report.data1 = profile + 1; + roccat_report.data2 = 0; + roccat_report.profile = profile + 1; + roccat_report_event(isku->chrdev_minor, (uint8_t const *)&roccat_report); + + mutex_unlock(&isku->isku_lock); + + return size; +} + +static struct device_attribute isku_attributes[] = { + __ATTR(actual_profile, 0660, + isku_sysfs_show_actual_profile, + isku_sysfs_set_actual_profile), + __ATTR_NULL +}; + +static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj, + char *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off >= real_size) + return 0; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&isku->isku_lock); + retval = isku_receive(usb_dev, command, buf, real_size); + mutex_unlock(&isku->isku_lock); + + return retval ? retval : real_size; +} + +static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj, + void const *buf, loff_t off, size_t count, + size_t real_size, uint command) +{ + struct device *dev = + container_of(kobj, struct device, kobj)->parent->parent; + struct isku_device *isku = hid_get_drvdata(dev_get_drvdata(dev)); + struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); + int retval; + + if (off != 0 || count != real_size) + return -EINVAL; + + mutex_lock(&isku->isku_lock); + retval = isku_send(usb_dev, command, (void *)buf, real_size); + mutex_unlock(&isku->isku_lock); + + return retval ? retval : real_size; +} + +#define ISKU_SYSFS_W(thingy, THINGY) \ +static ssize_t isku_sysfs_write_ ## thingy(struct file *fp, struct kobject *kobj, \ + struct bin_attribute *attr, char *buf, \ + loff_t off, size_t count) \ +{ \ + return isku_sysfs_write(fp, kobj, buf, off, count, \ + sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \ +} + +#define ISKU_SYSFS_R(thingy, THINGY) \ +static ssize_t isku_sysfs_read_ ## thingy(struct file *fp, struct kobject *kobj, \ + struct bin_attribute *attr, char *buf, \ + loff_t off, size_t count) \ +{ \ + return isku_sysfs_read(fp, kobj, buf, off, count, \ + sizeof(struct isku_ ## thingy), ISKU_COMMAND_ ## THINGY); \ +} + +#define ISKU_SYSFS_RW(thingy, THINGY) \ +ISKU_SYSFS_R(thingy, THINGY) \ +ISKU_SYSFS_W(thingy, THINGY) + +#define ISKU_BIN_ATTR_RW(thingy) \ +{ \ + .attr = { .name = #thingy, .mode = 0660 }, \ + .size = sizeof(struct isku_ ## thingy), \ + .read = isku_sysfs_read_ ## thingy, \ + .write = isku_sysfs_write_ ## thingy \ +} + +#define ISKU_BIN_ATTR_R(thingy) \ +{ \ + .attr = { .name = #thingy, .mode = 0440 }, \ + .size = sizeof(struct isku_ ## thingy), \ + .read = isku_sysfs_read_ ## thingy, \ +} + +#define ISKU_BIN_ATTR_W(thingy) \ +{ \ + .attr = { .name = #thingy, .mode = 0220 }, \ + .size = sizeof(struct isku_ ## thingy), \ + .write = isku_sysfs_write_ ## thingy \ +} + +ISKU_SYSFS_RW(macro, MACRO) +ISKU_SYSFS_RW(keys_function, KEYS_FUNCTION) +ISKU_SYSFS_RW(keys_easyzone, KEYS_EASYZONE) +ISKU_SYSFS_RW(keys_media, KEYS_MEDIA) +ISKU_SYSFS_RW(keys_thumbster, KEYS_THUMBSTER) +ISKU_SYSFS_RW(keys_macro, KEYS_MACRO) +ISKU_SYSFS_RW(keys_capslock, KEYS_CAPSLOCK) +ISKU_SYSFS_RW(light, LIGHT) +ISKU_SYSFS_RW(key_mask, KEY_MASK) +ISKU_SYSFS_RW(last_set, LAST_SET) +ISKU_SYSFS_W(talk, TALK) +ISKU_SYSFS_R(info, INFO) +ISKU_SYSFS_W(control, CONTROL) + +static struct bin_attribute isku_bin_attributes[] = { + ISKU_BIN_ATTR_RW(macro), + ISKU_BIN_ATTR_RW(keys_function), + ISKU_BIN_ATTR_RW(keys_easyzone), + ISKU_BIN_ATTR_RW(keys_media), + ISKU_BIN_ATTR_RW(keys_thumbster), + ISKU_BIN_ATTR_RW(keys_macro), + ISKU_BIN_ATTR_RW(keys_capslock), + ISKU_BIN_ATTR_RW(light), + ISKU_BIN_ATTR_RW(key_mask), + ISKU_BIN_ATTR_RW(last_set), + ISKU_BIN_ATTR_W(talk), + ISKU_BIN_ATTR_R(info), + ISKU_BIN_ATTR_W(control), + __ATTR_NULL +}; + +static int isku_init_isku_device_struct(struct usb_device *usb_dev, + struct isku_device *isku) +{ + int retval; + + mutex_init(&isku->isku_lock); + + retval = isku_get_actual_profile(usb_dev); + if (retval < 0) + return retval; + isku_profile_activated(isku, retval); + + return 0; +} + +static int isku_init_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct isku_device *isku; + int retval; + + if (intf->cur_altsetting->desc.bInterfaceProtocol + != ISKU_USB_INTERFACE_PROTOCOL) { + hid_set_drvdata(hdev, NULL); + return 0; + } + + isku = kzalloc(sizeof(*isku), GFP_KERNEL); + if (!isku) { + hid_err(hdev, "can't alloc device descriptor\n"); + return -ENOMEM; + } + hid_set_drvdata(hdev, isku); + + retval = isku_init_isku_device_struct(usb_dev, isku); + if (retval) { + hid_err(hdev, "couldn't init struct isku_device\n"); + goto exit_free; + } + + retval = roccat_connect(isku_class, hdev, + sizeof(struct isku_roccat_report)); + if (retval < 0) { + hid_err(hdev, "couldn't init char dev\n"); + } else { + isku->chrdev_minor = retval; + isku->roccat_claimed = 1; + } + + return 0; +exit_free: + kfree(isku); + return retval; +} + +static void isku_remove_specials(struct hid_device *hdev) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct isku_device *isku; + + if (intf->cur_altsetting->desc.bInterfaceProtocol + != ISKU_USB_INTERFACE_PROTOCOL) + return; + + isku = hid_get_drvdata(hdev); + if (isku->roccat_claimed) + roccat_disconnect(isku->chrdev_minor); + kfree(isku); +} + +static int isku_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int retval; + + retval = hid_parse(hdev); + if (retval) { + hid_err(hdev, "parse failed\n"); + goto exit; + } + + retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (retval) { + hid_err(hdev, "hw start failed\n"); + goto exit; + } + + retval = isku_init_specials(hdev); + if (retval) { + hid_err(hdev, "couldn't install keyboard\n"); + goto exit_stop; + } + + return 0; + +exit_stop: + hid_hw_stop(hdev); +exit: + return retval; +} + +static void isku_remove(struct hid_device *hdev) +{ + isku_remove_specials(hdev); + hid_hw_stop(hdev); +} + +static void isku_keep_values_up_to_date(struct isku_device *isku, + u8 const *data) +{ + struct isku_report_button const *button_report; + + switch (data[0]) { + case ISKU_REPORT_NUMBER_BUTTON: + button_report = (struct isku_report_button const *)data; + switch (button_report->event) { + case ISKU_REPORT_BUTTON_EVENT_PROFILE: + isku_profile_activated(isku, button_report->data1 - 1); + break; + } + break; + } +} + +static void isku_report_to_chrdev(struct isku_device const *isku, + u8 const *data) +{ + struct isku_roccat_report roccat_report; + struct isku_report_button const *button_report; + + if (data[0] != ISKU_REPORT_NUMBER_BUTTON) + return; + + button_report = (struct isku_report_button const *)data; + + roccat_report.event = button_report->event; + roccat_report.data1 = button_report->data1; + roccat_report.data2 = button_report->data2; + roccat_report.profile = isku->actual_profile + 1; + roccat_report_event(isku->chrdev_minor, + (uint8_t const *)&roccat_report); +} + +static int isku_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + struct isku_device *isku = hid_get_drvdata(hdev); + + if (intf->cur_altsetting->desc.bInterfaceProtocol + != ISKU_USB_INTERFACE_PROTOCOL) + return 0; + + if (isku == NULL) + return 0; + + isku_keep_values_up_to_date(isku, data); + + if (isku->roccat_claimed) + isku_report_to_chrdev(isku, data); + + return 0; +} + +static const struct hid_device_id isku_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, + { } +}; + +MODULE_DEVICE_TABLE(hid, isku_devices); + +static struct hid_driver isku_driver = { + .name = "isku", + .id_table = isku_devices, + .probe = isku_probe, + .remove = isku_remove, + .raw_event = isku_raw_event +}; + +static int __init isku_init(void) +{ + int retval; + isku_class = class_create(THIS_MODULE, "isku"); + if (IS_ERR(isku_class)) + return PTR_ERR(isku_class); + isku_class->dev_attrs = isku_attributes; + isku_class->dev_bin_attrs = isku_bin_attributes; + + retval = hid_register_driver(&isku_driver); + if (retval) + class_destroy(isku_class); + return retval; +} + +static void __exit isku_exit(void) +{ + hid_unregister_driver(&isku_driver); + class_destroy(isku_class); +} + +module_init(isku_init); +module_exit(isku_exit); + +MODULE_AUTHOR("Stefan Achatz"); +MODULE_DESCRIPTION("USB Roccat Isku driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hid/hid-roccat-isku.h b/drivers/hid/hid-roccat-isku.h new file mode 100644 index 000000000000..075f6efaec58 --- /dev/null +++ b/drivers/hid/hid-roccat-isku.h @@ -0,0 +1,147 @@ +#ifndef __HID_ROCCAT_ISKU_H +#define __HID_ROCCAT_ISKU_H + +/* + * Copyright (c) 2011 Stefan Achatz + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include + +enum { + ISKU_PROFILE_NUM = 5, + ISKU_USB_INTERFACE_PROTOCOL = 0, +}; + +struct isku_control { + uint8_t command; /* ISKU_COMMAND_CONTROL */ + uint8_t value; + uint8_t request; +} __packed; + +enum isku_control_values { + ISKU_CONTROL_VALUE_STATUS_OVERLOAD = 0, + ISKU_CONTROL_VALUE_STATUS_OK = 1, + ISKU_CONTROL_VALUE_STATUS_INVALID = 2, + ISKU_CONTROL_VALUE_STATUS_WAIT = 3, +}; + +struct isku_actual_profile { + uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */ + uint8_t size; /* always 3 */ + uint8_t actual_profile; +} __packed; + +struct isku_key_mask { + uint8_t command; /* ISKU_COMMAND_KEY_MASK */ + uint8_t size; /* 6 */ + uint8_t profile_number; /* 0-4 */ + uint8_t mask; + uint16_t checksum; +} __packed; + +struct isku_keys_function { + uint8_t data[0x29]; +} __packed; + +struct isku_keys_easyzone { + uint8_t data[0x41]; +} __packed; + +struct isku_keys_media { + uint8_t data[0x1d]; +} __packed; + +struct isku_keys_thumbster { + uint8_t data[0x17]; +} __packed; + +struct isku_keys_macro { + uint8_t data[0x23]; +} __packed; + +struct isku_keys_capslock { + uint8_t data[0x6]; +} __packed; + +struct isku_macro { + uint8_t data[0x823]; +} __packed; + +struct isku_light { + uint8_t data[0xa]; +} __packed; + +struct isku_info { + uint8_t data[2]; + uint8_t firmware_version; + uint8_t unknown[3]; +} __packed; + +struct isku_talk { + uint8_t data[0x10]; +} __packed; + +struct isku_last_set { + uint8_t data[0x14]; +} __packed; + +enum isku_commands { + ISKU_COMMAND_CONTROL = 0x4, + ISKU_COMMAND_ACTUAL_PROFILE = 0x5, + ISKU_COMMAND_KEY_MASK = 0x7, + ISKU_COMMAND_KEYS_FUNCTION = 0x8, + ISKU_COMMAND_KEYS_EASYZONE = 0x9, + ISKU_COMMAND_KEYS_MEDIA = 0xa, + ISKU_COMMAND_KEYS_THUMBSTER = 0xb, + ISKU_COMMAND_KEYS_MACRO = 0xd, + ISKU_COMMAND_MACRO = 0xe, + ISKU_COMMAND_INFO = 0xf, + ISKU_COMMAND_LIGHT = 0x10, + ISKU_COMMAND_KEYS_CAPSLOCK = 0x13, + ISKU_COMMAND_LAST_SET = 0x14, + ISKU_COMMAND_15 = 0x15, + ISKU_COMMAND_TALK = 0x16, + ISKU_COMMAND_FIRMWARE_WRITE = 0x1b, + ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c, +}; + +struct isku_report_button { + uint8_t number; /* ISKU_REPORT_NUMBER_BUTTON */ + uint8_t zero; + uint8_t event; + uint8_t data1; + uint8_t data2; +}; + +enum isku_report_numbers { + ISKU_REPORT_NUMBER_BUTTON = 3, +}; + +enum isku_report_button_events { + ISKU_REPORT_BUTTON_EVENT_PROFILE = 0x2, +}; + +struct isku_roccat_report { + uint8_t event; + uint8_t data1; + uint8_t data2; + uint8_t profile; +} __packed; + +struct isku_device { + int roccat_claimed; + int chrdev_minor; + + struct mutex isku_lock; + + int actual_profile; +}; + +#endif -- cgit v1.2.3