// SPDX-License-Identifier: GPL-2.0-or-later /* * Roccat Kone driver for Linux * * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
*/
/* * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard * part. The keyboard part enables the mouse to execute stored macros with mixed * key- and button-events. * * TODO implement on-the-fly polling-rate change * The windows driver has the ability to change the polling rate of the * device on the press of a mousebutton. * Is it possible to remove and reinstall the urb in raw-event- or any * other handler, or to defer this action to be executed somewhere else? * * TODO is it possible to overwrite group for sysfs attributes via udev?
*/
for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address)
checksum += *address;
settings->checksum = cpu_to_le16(checksum);
}
/* * Checks success after writing data to mouse * On success returns 0 * On failure returns errno
*/ staticint kone_check_write(struct usb_device *usb_dev)
{ int retval;
uint8_t data;
do { /* * Mouse needs 50 msecs until it says ok, but there are * 30 more msecs needed for next write to work.
*/
msleep(80);
retval = kone_receive(usb_dev,
kone_command_confirm_write, &data, 1); if (retval) return retval;
/* * value of 3 seems to mean something like * "not finished yet, but it looks good" * So check again after a moment.
*/
} while (data == 3);
/* * Reads profile data from mouse and stores it in @buf * @number: profile number to read * On success returns 0 * On failure returns errno
*/ staticint kone_get_profile(struct usb_device *usb_dev, struct kone_profile *buf, int number)
{ int len;
if (len != sizeof(struct kone_profile)) return -EIO;
return 0;
}
/* * Writes profile data to mouse. * @number: profile number to write * On success returns 0 * On failure returns errno
*/ staticint kone_set_profile(struct usb_device *usb_dev, struct kone_profile const *profile, int number)
{ int len;
if (len != sizeof(struct kone_profile)) return len;
if (kone_check_write(usb_dev)) return -EIO;
return 0;
}
/* * Reads value of "fast-clip-weight" and stores it in @result * On success returns 0 * On failure returns errno
*/ staticint kone_get_weight(struct usb_device *usb_dev, int *result)
{ int retval;
uint8_t data;
/* * Reads firmware_version of mouse and stores it in @result * On success returns 0 * On failure returns errno
*/ staticint kone_get_firmware_version(struct usb_device *usb_dev, int *result)
{ int retval;
uint16_t data;
retval = kone_receive(usb_dev, kone_command_firmware_version,
&data, 2); if (retval) return retval;
/* * Writing settings automatically activates startup_profile. * This function keeps values in kone_device up to date and assumes that in * case of error the old data is still valid
*/ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, conststruct bin_attribute *attr, char *buf,
loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj)->parent->parent; struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval = 0, difference, old_profile; struct kone_settings *settings = (struct kone_settings *)buf;
/* I need to get my data in one piece */ if (off != 0 || count != sizeof(struct kone_settings)) return -EINVAL;
/* weight is read each time, since we don't get informed when it's changed */ static ssize_t kone_sysfs_show_weight(struct device *dev, struct device_attribute *attr, char *buf)
{ struct kone_device *kone; struct usb_device *usb_dev; int weight = 0; int retval;
dev = dev->parent->parent;
kone = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
staticint kone_tcu_command(struct usb_device *usb_dev, int number)
{ unsignedchar value;
value = number; return kone_send(usb_dev, kone_command_calibrate, &value, 1);
}
/* * Calibrating the tcu is the only action that changes settings data inside the * mouse, so this data needs to be reread
*/ static ssize_t kone_sysfs_set_tcu(struct device *dev, struct device_attribute *attr, charconst *buf, size_t size)
{ struct kone_device *kone; struct usb_device *usb_dev; int retval; unsignedlong state;
dev = dev->parent->parent;
kone = hid_get_drvdata(dev_get_drvdata(dev));
usb_dev = interface_to_usbdev(to_usb_interface(dev));
retval = kstrtoul(buf, 10, &state); if (retval) return retval;
if (state != 0 && state != 1) return -EINVAL;
mutex_lock(&kone->kone_lock);
if (state == 1) { /* state activate */
retval = kone_tcu_command(usb_dev, 1); if (retval) goto exit_unlock;
retval = kone_tcu_command(usb_dev, 2); if (retval) goto exit_unlock;
ssleep(5); /* tcu needs this time for calibration */
retval = kone_tcu_command(usb_dev, 3); if (retval) goto exit_unlock;
retval = kone_tcu_command(usb_dev, 0); if (retval) goto exit_unlock;
retval = kone_tcu_command(usb_dev, 4); if (retval) goto exit_unlock; /* * Kone needs this time to settle things. * Reading settings too early will result in invalid data. * Roccat's driver waits 1 sec, maybe this time could be * shortened.
*/
ssleep(1);
}
/* calibration changes values in settings, so reread */
retval = kone_get_settings(usb_dev, &kone->settings); if (retval) goto exit_no_settings;
/* only write settings back if activation state is different */ if (kone->settings.tcu != state) {
kone->settings.tcu = state;
kone_set_settings_checksum(&kone->settings);
retval = kone_set_settings(usb_dev, &kone->settings); if (retval) {
dev_err(&usb_dev->dev, "couldn't set tcu state\n"); /* * try to reread valid settings into buffer overwriting * first error code
*/
retval = kone_get_settings(usb_dev, &kone->settings); if (retval) goto exit_no_settings; goto exit_unlock;
} /* calibration resets profile */
kone_profile_activated(kone, kone->settings.startup_profile);
}
staticstruct attribute *kone_attrs[] = { /* * Read actual dpi settings. * Returns raw value for further processing. Refer to enum * kone_polling_rates to get real value.
*/
&dev_attr_actual_dpi.attr,
&dev_attr_actual_profile.attr,
/* * The mouse can be equipped with one of four supplied weights from 5 * to 20 grams which are recognized and its value can be read out. * This returns the raw value reported by the mouse for easy evaluation * by software. Refer to enum kone_weights to get corresponding real * weight.
*/
&dev_attr_weight.attr,
/* * Prints firmware version stored in mouse as integer. * The raw value reported by the mouse is returned for easy evaluation, * to get the real version number the decimal point has to be shifted 2 * positions to the left. E.g. a value of 138 means 1.38.
*/
&dev_attr_firmware_version.attr,
/* * Prints state of Tracking Control Unit as number where 0 = off and * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and * activates the tcu
*/
&dev_attr_tcu.attr,
/* Prints and takes the number of the profile the mouse starts with */
&dev_attr_startup_profile.attr,
NULL,
};
/* * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to * mousepart if usb_hid is compiled into the kernel and kone is compiled as * module. * Secial behaviour is bound only to mousepart since only mouseevents contain * additional notifications.
*/ staticint kone_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 kone_device *kone; int retval;
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
kone = kzalloc(sizeof(*kone), GFP_KERNEL); if (!kone) return -ENOMEM;
hid_set_drvdata(hdev, kone);
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
kone = hid_get_drvdata(hdev); if (kone->roccat_claimed)
roccat_disconnect(kone->chrdev_minor);
kfree(hid_get_drvdata(hdev));
}
}
staticint kone_probe(struct hid_device *hdev, conststruct hid_device_id *id)
{ int retval;
/* handle special events and keep actual profile and dpi values up to date */ staticvoid kone_keep_values_up_to_date(struct kone_device *kone, struct kone_mouse_event const *event)
{ switch (event->event) { case kone_mouse_event_switch_profile:
kone->actual_dpi = kone->profiles[event->value - 1].
startup_dpi;
fallthrough; case kone_mouse_event_osd_profile:
kone->actual_profile = event->value; break; case kone_mouse_event_switch_dpi: case kone_mouse_event_osd_dpi:
kone->actual_dpi = event->value; break;
}
}
switch (event->event) { case kone_mouse_event_switch_profile: case kone_mouse_event_switch_dpi: case kone_mouse_event_osd_profile: case kone_mouse_event_osd_dpi:
roccat_report.event = event->event;
roccat_report.value = event->value;
roccat_report.key = 0;
roccat_report_event(kone->chrdev_minor,
(uint8_t *)&roccat_report); break; case kone_mouse_event_call_overlong_macro: case kone_mouse_event_multimedia: if (event->value == kone_keystroke_action_press) {
roccat_report.event = event->event;
roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor,
(uint8_t *)&roccat_report);
} break;
}
}
/* * Is called for keyboard- and mousepart. * Only mousepart gets informations about special events in its extended event * structure.
*/ staticint kone_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{ struct kone_device *kone = hid_get_drvdata(hdev); struct kone_mouse_event *event = (struct kone_mouse_event *)data;
/* keyboard events are always processed by default handler */ if (size != sizeof(struct kone_mouse_event)) return 0;
if (kone == NULL) return 0;
/* * Firmware 1.38 introduced new behaviour for tilt and special buttons. * Pressed button is reported in each movement event. * Workaround sends only one event per press.
*/ if (memcmp(&kone->last_mouse_event.tilt, &event->tilt, 5))
memcpy(&kone->last_mouse_event, event, sizeof(struct kone_mouse_event)); else
memset(&event->wipe, 0, sizeof(event->wipe));
kone_keep_values_up_to_date(kone, event);
if (kone->roccat_claimed)
kone_report_to_chrdev(kone, event);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.