114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Roccat Kone driver for Linux 314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * 414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> 514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * This program is free software; you can redistribute it and/or modify it 914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * under the terms of the GNU General Public License as published by the Free 1014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Software Foundation; either version 2 of the License, or (at your option) 1114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * any later version. 1214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 1314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 1414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 1514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Roccat Kone is a gamer mouse which consists of a mouse part and a keyboard 1614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * part. The keyboard part enables the mouse to execute stored macros with mixed 1714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * key- and button-events. 1814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * 1914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * TODO implement on-the-fly polling-rate change 2014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * The windows driver has the ability to change the polling rate of the 2114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * device on the press of a mousebutton. 2214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Is it possible to remove and reinstall the urb in raw-event- or any 2314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * other handler, or to defer this action to be executed somewhere else? 2414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * 2514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * TODO is it possible to overwrite group for sysfs attributes via udev? 2614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 2714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/device.h> 2914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/input.h> 3014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/hid.h> 3114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include <linux/module.h> 32ed28f04b2753ce1b07b9c3dab7d186c43ce19e8cTejun Heo#include <linux/slab.h> 335dc0c9835fb96c75c8dbf657393764bd0abbac04Stefan Achatz#include <linux/hid-roccat.h> 3414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include "hid-ids.h" 355772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz#include "hid-roccat-common.h" 3614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz#include "hid-roccat-kone.h" 3714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 3814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic uint profile_numbers[5] = {0, 1, 2, 3, 4}; 3914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz 40bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatzstatic void kone_profile_activated(struct kone_device *kone, uint new_profile) 41bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz{ 42bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone->actual_profile = new_profile; 43bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone->actual_dpi = kone->profiles[new_profile - 1].startup_dpi; 44bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz} 45bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz 463200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatzstatic void kone_profile_report(struct kone_device *kone, uint new_profile) 473200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz{ 483200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz struct kone_roccat_report roccat_report; 493200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz roccat_report.event = kone_mouse_event_switch_profile; 503200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz roccat_report.value = new_profile; 513200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz roccat_report.key = 0; 523200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz roccat_report_event(kone->chrdev_minor, (uint8_t *)&roccat_report); 533200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz} 543200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz 551edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatzstatic int kone_receive(struct usb_device *usb_dev, uint usb_command, 561edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz void *data, uint size) 571edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz{ 581edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz char *buf; 591edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz int len; 601edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 611edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz buf = kmalloc(size, GFP_KERNEL); 621edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz if (buf == NULL) 631edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return -ENOMEM; 641edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 651edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 661edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz HID_REQ_GET_REPORT, 671edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 681edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); 691edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 701edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz memcpy(data, buf, size); 711edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz kfree(buf); 721edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return ((len < 0) ? len : ((len != size) ? -EIO : 0)); 731edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz} 741edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 751edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatzstatic int kone_send(struct usb_device *usb_dev, uint usb_command, 761edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz void const *data, uint size) 771edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz{ 781edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz char *buf; 791edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz int len; 801edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 814c33a885a5c8a9ad573249fa4ee4fb39af866599Thomas Meyer buf = kmemdup(data, size, GFP_KERNEL); 821edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz if (buf == NULL) 831edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return -ENOMEM; 841edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 851edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 861edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz HID_REQ_SET_REPORT, 871edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 881edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); 891edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 901edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz kfree(buf); 911edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return ((len < 0) ? len : ((len != size) ? -EIO : 0)); 921edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz} 931edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz 945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz/* kone_class is used for creating sysfs attributes via roccat char device */ 955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct class *kone_class; 965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 9714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_set_settings_checksum(struct kone_settings *settings) 9814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 9914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz uint16_t checksum = 0; 10014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz unsigned char *address = (unsigned char *)settings; 10114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int i; 10214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 10314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz for (i = 0; i < sizeof(struct kone_settings) - 2; ++i, ++address) 10414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz checksum += *address; 10514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz settings->checksum = cpu_to_le16(checksum); 10614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 10714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 10814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 10914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Checks success after writing data to mouse 11014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 11114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 11214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 11314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_check_write(struct usb_device *usb_dev) 11414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 1155772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz int retval; 1165772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz uint8_t data; 11714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 11814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz do { 11914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* 12014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Mouse needs 50 msecs until it says ok, but there are 12114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * 30 more msecs needed for next write to work. 12214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 12314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz msleep(80); 12414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 1251edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = kone_receive(usb_dev, 1265772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz kone_command_confirm_write, &data, 1); 1275772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz if (retval) 1285772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return retval; 12914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 13014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* 13114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * value of 3 seems to mean something like 13214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * "not finished yet, but it looks good" 13314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * So check again after a moment. 13414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 1355772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz } while (data == 3); 13614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 1375772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz if (data == 1) /* everything alright */ 13814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 1395772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz 1405772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz /* unknown answer */ 1415772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz hid_err(usb_dev, "got retval %d when checking write\n", data); 1425772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return -EIO; 14314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 14414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 14514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 14614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads settings from mouse and stores it in @buf 14714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 14814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 14914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 15014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_settings(struct usb_device *usb_dev, 15114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_settings *buf) 15214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 1531edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return kone_receive(usb_dev, kone_command_settings, buf, 1545772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz sizeof(struct kone_settings)); 15514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 15614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 15714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 15814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writes settings from @buf to mouse 15914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 16014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 16114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 16214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_set_settings(struct usb_device *usb_dev, 16314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_settings const *settings) 16414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 1655772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz int retval; 1661edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = kone_send(usb_dev, kone_command_settings, 1675772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz settings, sizeof(struct kone_settings)); 1685772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz if (retval) 1695772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return retval; 1705772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return kone_check_write(usb_dev); 17114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 17214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 17314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 17414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads profile data from mouse and stores it in @buf 17514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * @number: profile number to read 17614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 17714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 17814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 17914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_profile(struct usb_device *usb_dev, 18014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_profile *buf, int number) 18114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 18214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int len; 18314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 18414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (number < 1 || number > 5) 18514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 18614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 18714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 18814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz USB_REQ_CLEAR_FEATURE, 18914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 19014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone_command_profile, number, buf, 19114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz sizeof(struct kone_profile), USB_CTRL_SET_TIMEOUT); 19214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 19314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (len != sizeof(struct kone_profile)) 19414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EIO; 19514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 19614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 19714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 19814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 19914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 20014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writes profile data to mouse. 20114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * @number: profile number to write 20214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 20314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 20414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 20514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_set_profile(struct usb_device *usb_dev, 20614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_profile const *profile, int number) 20714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 20814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int len; 20914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 21014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (number < 1 || number > 5) 21114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 21214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 21314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 21414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz USB_REQ_SET_CONFIGURATION, 21514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 2165772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz kone_command_profile, number, (void *)profile, 21714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz sizeof(struct kone_profile), 21814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz USB_CTRL_SET_TIMEOUT); 21914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 22014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (len != sizeof(struct kone_profile)) 22114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return len; 22214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 22314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (kone_check_write(usb_dev)) 22414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EIO; 22514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 22614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 22714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 22814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 22914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 23014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads value of "fast-clip-weight" and stores it in @result 23114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 23214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 23314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 23414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_weight(struct usb_device *usb_dev, int *result) 23514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 2365772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz int retval; 2375772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz uint8_t data; 23814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2391edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = kone_receive(usb_dev, kone_command_weight, &data, 1); 24014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2415772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz if (retval) 2425772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return retval; 24314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2445772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz *result = (int)data; 24514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 24614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 24714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 24814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 24914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reads firmware_version of mouse and stores it in @result 25014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On success returns 0 25114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * On failure returns errno 25214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 25314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_get_firmware_version(struct usb_device *usb_dev, int *result) 25414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 2555772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz int retval; 2565772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz uint16_t data; 25714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2581edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = kone_receive(usb_dev, kone_command_firmware_version, 2595772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz &data, 2); 2605772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz if (retval) 2615772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz return retval; 26214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2635772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz *result = le16_to_cpu(data); 26414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 26514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 26614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 2675f2776293f7a4390f587642b1b7e1e6288e11a01Stephen Rothwellstatic ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, 26814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct bin_attribute *attr, char *buf, 26914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz loff_t off, size_t count) { 2705012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct device *dev = 2715012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 27214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); 27314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 27414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off >= sizeof(struct kone_settings)) 27514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 27614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 27714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off + count > sizeof(struct kone_settings)) 27814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz count = sizeof(struct kone_settings) - off; 27914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 28014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 281cab6b16aca4ac12f731a523fe14770add2f9394aStefan Achatz memcpy(buf, ((char const *)&kone->settings) + off, count); 28214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_unlock(&kone->kone_lock); 28314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 28414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return count; 28514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 28614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 28714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 28814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Writing settings automatically activates startup_profile. 28914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * This function keeps values in kone_device up to date and assumes that in 29014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * case of error the old data is still valid 29114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 2925f2776293f7a4390f587642b1b7e1e6288e11a01Stephen Rothwellstatic ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj, 29314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct bin_attribute *attr, char *buf, 29414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz loff_t off, size_t count) { 2955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct device *dev = 2965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 29714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); 29814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 2993200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz int retval = 0, difference, old_profile; 30014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 30114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* I need to get my data in one piece */ 30214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off != 0 || count != sizeof(struct kone_settings)) 30314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 30414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 30514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 30614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings)); 30714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (difference) { 30814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_set_settings(usb_dev, 30914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz (struct kone_settings const *)buf); 310bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz if (retval) { 311bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz mutex_unlock(&kone->kone_lock); 312bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz return retval; 313bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz } 31414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 3153200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz old_profile = kone->settings.startup_profile; 316bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz memcpy(&kone->settings, buf, sizeof(struct kone_settings)); 31714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 318bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone_profile_activated(kone, kone->settings.startup_profile); 3193200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz 3203200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz if (kone->settings.startup_profile != old_profile) 3213200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz kone_profile_report(kone, kone->settings.startup_profile); 322bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz } 323bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz mutex_unlock(&kone->kone_lock); 32414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 32514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return sizeof(struct kone_settings); 32614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 32714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 32814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic ssize_t kone_sysfs_read_profilex(struct file *fp, 32914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz struct kobject *kobj, struct bin_attribute *attr, 33014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz char *buf, loff_t off, size_t count) { 3315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct device *dev = 3325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 33314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); 33414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 33514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off >= sizeof(struct kone_profile)) 33614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 33714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 33814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off + count > sizeof(struct kone_profile)) 33914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz count = sizeof(struct kone_profile) - off; 34014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 34114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 34214a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count); 34314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_unlock(&kone->kone_lock); 34414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 34514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return count; 34614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 34714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 34814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* Writes data only if different to stored data */ 34914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatzstatic ssize_t kone_sysfs_write_profilex(struct file *fp, 35014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz struct kobject *kobj, struct bin_attribute *attr, 35114a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz char *buf, loff_t off, size_t count) { 3525012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct device *dev = 3535012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 35414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); 35514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 35614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_profile *profile; 35714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval = 0, difference; 35814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 35914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* I need to get my data in one piece */ 36014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (off != 0 || count != sizeof(struct kone_profile)) 36114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 36214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 36314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz profile = &kone->profiles[*(uint *)(attr->private)]; 36414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 36514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 36614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz difference = memcmp(buf, profile, sizeof(struct kone_profile)); 36714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (difference) { 36814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_set_profile(usb_dev, 36914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz (struct kone_profile const *)buf, 37014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz *(uint *)(attr->private) + 1); 37114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (!retval) 37214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz memcpy(profile, buf, sizeof(struct kone_profile)); 37314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 37414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_unlock(&kone->kone_lock); 37514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 37614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 37714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 37814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 37914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return sizeof(struct kone_profile); 38014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 38114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 38214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_actual_profile(struct device *dev, 38314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 38414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 3855012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone = 3865012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 38714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile); 38814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 38914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 39014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_actual_dpi(struct device *dev, 39114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 39214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 3935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone = 3945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 39514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi); 39614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 39714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 39814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* weight is read each time, since we don't get informed when it's changed */ 39914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_weight(struct device *dev, 40014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 40114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 4025012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone; 4035012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct usb_device *usb_dev; 40414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int weight = 0; 40514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 40614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 4075012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz dev = dev->parent->parent; 4085012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone = hid_get_drvdata(dev_get_drvdata(dev)); 4095012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz usb_dev = interface_to_usbdev(to_usb_interface(dev)); 4105012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 41114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 41214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_weight(usb_dev, &weight); 41314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_unlock(&kone->kone_lock); 41414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 41514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 41614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 41714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", weight); 41814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 41914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 42014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_firmware_version(struct device *dev, 42114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 42214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 4235012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone = 4245012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 42514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version); 42614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 42714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 42814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_tcu(struct device *dev, 42914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 43014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 4315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone = 4325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 43314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu); 43414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 43514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 43614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_tcu_command(struct usb_device *usb_dev, int number) 43714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 4385772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz unsigned char value; 4395772f63613ce0a6777e82a7e8fb553e49da27719Stefan Achatz value = number; 4401edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return kone_send(usb_dev, kone_command_calibrate, &value, 1); 44114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 44214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 44314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 44414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Calibrating the tcu is the only action that changes settings data inside the 44514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * mouse, so this data needs to be reread 44614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 44714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_set_tcu(struct device *dev, 44814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char const *buf, size_t size) 44914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 4505012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone; 4515012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct usb_device *usb_dev; 45214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 45314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz unsigned long state; 45414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 4555012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz dev = dev->parent->parent; 4565012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone = hid_get_drvdata(dev_get_drvdata(dev)); 4575012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz usb_dev = interface_to_usbdev(to_usb_interface(dev)); 4585012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 45914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = strict_strtoul(buf, 10, &state); 46014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 46114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 46214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 46314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (state != 0 && state != 1) 46414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 46514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 46614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 46714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 46814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (state == 1) { /* state activate */ 46914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_tcu_command(usb_dev, 1); 47014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 47114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 47214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_tcu_command(usb_dev, 2); 47314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 47414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 47514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz ssleep(5); /* tcu needs this time for calibration */ 47614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_tcu_command(usb_dev, 3); 47714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 47814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 47914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_tcu_command(usb_dev, 0); 48014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 48114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 48214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_tcu_command(usb_dev, 4); 48314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 48414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 48514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* 48614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Kone needs this time to settle things. 48714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Reading settings too early will result in invalid data. 48814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Roccat's driver waits 1 sec, maybe this time could be 48914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * shortened. 49014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 49114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz ssleep(1); 49214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 49314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 49414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* calibration changes values in settings, so reread */ 49514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_settings(usb_dev, &kone->settings); 49614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 49714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_no_settings; 49814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 49914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* only write settings back if activation state is different */ 50014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (kone->settings.tcu != state) { 50114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone->settings.tcu = state; 50214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone_set_settings_checksum(&kone->settings); 50314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 50414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_set_settings(usb_dev, &kone->settings); 50514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) { 5064291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(usb_dev, "couldn't set tcu state\n"); 50714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* 50814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * try to reread valid settings into buffer overwriting 50914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * first error code 51014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 51114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_settings(usb_dev, &kone->settings); 51214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 51314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_no_settings; 51414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_unlock; 51514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 516bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz /* calibration resets profile */ 517bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone_profile_activated(kone, kone->settings.startup_profile); 51814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 51914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 52014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = size; 52114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_no_settings: 5224291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(usb_dev, "couldn't read settings\n"); 52314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_unlock: 52414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_unlock(&kone->kone_lock); 52514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 52614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 52714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 52814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_show_startup_profile(struct device *dev, 52914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char *buf) 53014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 5315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone = 5325012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 53314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile); 53414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 53514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 53614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic ssize_t kone_sysfs_set_startup_profile(struct device *dev, 53714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct device_attribute *attr, char const *buf, size_t size) 53814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 5395012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct kone_device *kone; 5405012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz struct usb_device *usb_dev; 54114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 54214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz unsigned long new_startup_profile; 54314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 5445012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz dev = dev->parent->parent; 5455012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone = hid_get_drvdata(dev_get_drvdata(dev)); 5465012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz usb_dev = interface_to_usbdev(to_usb_interface(dev)); 5475012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 54814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = strict_strtoul(buf, 10, &new_startup_profile); 54914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 55014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 55114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 55214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (new_startup_profile < 1 || new_startup_profile > 5) 55314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -EINVAL; 55414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 55514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_lock(&kone->kone_lock); 55614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 55714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone->settings.startup_profile = new_startup_profile; 55814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone_set_settings_checksum(&kone->settings); 55914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 56014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_set_settings(usb_dev, &kone->settings); 561bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz if (retval) { 562bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz mutex_unlock(&kone->kone_lock); 56314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 564bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz } 56514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 56614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* changing the startup profile immediately activates this profile */ 567bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone_profile_activated(kone, new_startup_profile); 5683200a6a5fa36585ec1c547d4fefeb622ae02c5ecStefan Achatz kone_profile_report(kone, new_startup_profile); 56914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 570bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz mutex_unlock(&kone->kone_lock); 57114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return size; 57214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 57314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 5745012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct device_attribute kone_attributes[] = { 5755012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* 5765012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * Read actual dpi settings. 5775012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * Returns raw value for further processing. Refer to enum 5785012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * kone_polling_rates to get real value. 5795012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz */ 5805012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL), 5815012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL), 58214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 5835012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* 5845012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * The mouse can be equipped with one of four supplied weights from 5 5855012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * to 20 grams which are recognized and its value can be read out. 5865012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * This returns the raw value reported by the mouse for easy evaluation 5875012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * by software. Refer to enum kone_weights to get corresponding real 5885012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * weight. 5895012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz */ 5905012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(weight, 0440, kone_sysfs_show_weight, NULL), 59114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 5925012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* 5935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * Prints firmware version stored in mouse as integer. 5945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * The raw value reported by the mouse is returned for easy evaluation, 5955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * to get the real version number the decimal point has to be shifted 2 5965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * positions to the left. E.g. a value of 138 means 1.38. 5975012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz */ 5985012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(firmware_version, 0440, 5995012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_sysfs_show_firmware_version, NULL), 60014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 6015012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* 6025012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * Prints state of Tracking Control Unit as number where 0 = off and 6035012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and 6045012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz * activates the tcu 6055012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz */ 6065012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu), 60714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 6085012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* Prints and takes the number of the profile the mouse starts with */ 6095012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR(startup_profile, 0660, 6105012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_sysfs_show_startup_profile, 6115012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_sysfs_set_startup_profile), 6125012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR_NULL 61314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}; 61414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 6155012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatzstatic struct bin_attribute kone_bin_attributes[] = { 6165012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6175012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "settings", .mode = 0660 }, 6185012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_settings), 6195012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .read = kone_sysfs_read_settings, 6205012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .write = kone_sysfs_write_settings 6215012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6225012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6235012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "profile1", .mode = 0660 }, 6245012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_profile), 62514a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .read = kone_sysfs_read_profilex, 62614a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .write = kone_sysfs_write_profilex, 62714a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .private = &profile_numbers[0] 6285012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6295012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6305012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "profile2", .mode = 0660 }, 6315012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_profile), 63214a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .read = kone_sysfs_read_profilex, 63314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .write = kone_sysfs_write_profilex, 63414a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .private = &profile_numbers[1] 6355012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6365012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6375012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "profile3", .mode = 0660 }, 6385012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_profile), 63914a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .read = kone_sysfs_read_profilex, 64014a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .write = kone_sysfs_write_profilex, 64114a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .private = &profile_numbers[2] 6425012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6435012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6445012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "profile4", .mode = 0660 }, 6455012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_profile), 64614a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .read = kone_sysfs_read_profilex, 64714a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .write = kone_sysfs_write_profilex, 64814a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .private = &profile_numbers[3] 6495012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6505012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz { 6515012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .attr = { .name = "profile5", .mode = 0660 }, 6525012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz .size = sizeof(struct kone_profile), 65314a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .read = kone_sysfs_read_profilex, 65414a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .write = kone_sysfs_write_profilex, 65514a057f80f0c4d45a9e68009f8bcb6b246e87ca0Stefan Achatz .private = &profile_numbers[4] 6565012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz }, 6575012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz __ATTR_NULL 65814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}; 65914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 66014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_init_kone_device_struct(struct usb_device *usb_dev, 66114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone) 66214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 66314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz uint i; 66414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 66514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 66614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz mutex_init(&kone->kone_lock); 66714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 66814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz for (i = 0; i < 5; ++i) { 66914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_profile(usb_dev, &kone->profiles[i], i + 1); 67014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 67114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 67214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 67314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 67414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_settings(usb_dev, &kone->settings); 67514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 67614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 67714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 67814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_get_firmware_version(usb_dev, &kone->firmware_version); 67914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) 68014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 68114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 682bd9c35d0e5d442568f22e64066a5e687e54881a4Stefan Achatz kone_profile_activated(kone, kone->settings.startup_profile); 68314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 68414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 68514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 68614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 68714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 68814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Since IGNORE_MOUSE quirk moved to hid-apple, there is no way to bind only to 68914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * mousepart if usb_hid is compiled into the kernel and kone is compiled as 69014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * module. 69114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Secial behaviour is bound only to mousepart since only mouseevents contain 69214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * additional notifications. 69314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 69414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_init_specials(struct hid_device *hdev) 69514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 69614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 69714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct usb_device *usb_dev = interface_to_usbdev(intf); 69814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone; 69914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 70014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 70114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 70214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 70314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 70414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone = kzalloc(sizeof(*kone), GFP_KERNEL); 70514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (!kone) { 7064291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "can't alloc device descriptor\n"); 70714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return -ENOMEM; 70814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 70914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz hid_set_drvdata(hdev, kone); 71014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 71114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_init_kone_device_struct(usb_dev, kone); 71214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) { 7134291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "couldn't init struct kone_device\n"); 71414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_free; 71514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 716206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz 7178211e46004518c977f70f2661da961d5ba617399Stefan Achatz retval = roccat_connect(kone_class, hdev, 7188211e46004518c977f70f2661da961d5ba617399Stefan Achatz sizeof(struct kone_roccat_report)); 719206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz if (retval < 0) { 7204291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "couldn't init char dev\n"); 721206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz /* be tolerant about not getting chrdev */ 722206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz } else { 723206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz kone->roccat_claimed = 1; 724206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz kone->chrdev_minor = retval; 725206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz } 72614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } else { 72714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz hid_set_drvdata(hdev, NULL); 72814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 72914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 73014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 73114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_free: 73214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kfree(kone); 73314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 73414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 73514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 73614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_remove_specials(struct hid_device *hdev) 73714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 73814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 739206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz struct kone_device *kone; 74014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 74114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 74214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 743206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz kone = hid_get_drvdata(hdev); 744206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz if (kone->roccat_claimed) 745206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_disconnect(kone->chrdev_minor); 74614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kfree(hid_get_drvdata(hdev)); 74714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 74814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 74914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 75014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_probe(struct hid_device *hdev, const struct hid_device_id *id) 75114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 75214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz int retval; 75314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 75414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = hid_parse(hdev); 75514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) { 7564291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "parse failed\n"); 75714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit; 75814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 75914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 76014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 76114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) { 7624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "hw start failed\n"); 76314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit; 76414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 76514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 76614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz retval = kone_init_specials(hdev); 76714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (retval) { 7684291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches hid_err(hdev, "couldn't install mouse\n"); 76914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz goto exit_stop; 77014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz } 77114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 77214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 77314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 77414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit_stop: 77514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz hid_hw_stop(hdev); 77614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzexit: 77714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return retval; 77814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 77914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 78014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic void kone_remove(struct hid_device *hdev) 78114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 78214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz kone_remove_specials(hdev); 78314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz hid_hw_stop(hdev); 78414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 78514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 78648e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz/* handle special events and keep actual profile and dpi values up to date */ 78748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatzstatic void kone_keep_values_up_to_date(struct kone_device *kone, 78848e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz struct kone_mouse_event const *event) 78948e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz{ 79048e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz switch (event->event) { 79148e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz case kone_mouse_event_switch_profile: 7921c5784da12e34e98eb0a1b8f4323419dd84ea0b0Stefan Achatz kone->actual_dpi = kone->profiles[event->value - 1]. 7931c5784da12e34e98eb0a1b8f4323419dd84ea0b0Stefan Achatz startup_dpi; 79448e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz case kone_mouse_event_osd_profile: 79548e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz kone->actual_profile = event->value; 79648e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz break; 79748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz case kone_mouse_event_switch_dpi: 79848e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz case kone_mouse_event_osd_dpi: 79948e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz kone->actual_dpi = event->value; 80048e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz break; 80148e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz } 80248e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz} 80348e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz 804206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatzstatic void kone_report_to_chrdev(struct kone_device const *kone, 805206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz struct kone_mouse_event const *event) 806206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz{ 807206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz struct kone_roccat_report roccat_report; 808206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz 809206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz switch (event->event) { 810206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz case kone_mouse_event_switch_profile: 811206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz case kone_mouse_event_switch_dpi: 812206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz case kone_mouse_event_osd_profile: 813206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz case kone_mouse_event_osd_dpi: 814206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.event = event->event; 815206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.value = event->value; 816206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.key = 0; 817206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report_event(kone->chrdev_minor, 8188211e46004518c977f70f2661da961d5ba617399Stefan Achatz (uint8_t *)&roccat_report); 819206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz break; 820206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz case kone_mouse_event_call_overlong_macro: 821206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz if (event->value == kone_keystroke_action_press) { 822206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.event = kone_mouse_event_call_overlong_macro; 823206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.value = kone->actual_profile; 824206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report.key = event->macro_key; 825206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz roccat_report_event(kone->chrdev_minor, 8268211e46004518c977f70f2661da961d5ba617399Stefan Achatz (uint8_t *)&roccat_report); 827206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz } 828206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz break; 829206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz } 830206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz 831206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz} 832206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz 83314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz/* 83414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Is called for keyboard- and mousepart. 83514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Only mousepart gets informations about special events in its extended event 83614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * structure. 83714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 83814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic int kone_raw_event(struct hid_device *hdev, struct hid_report *report, 83914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz u8 *data, int size) 84014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 84114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_device *kone = hid_get_drvdata(hdev); 84214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz struct kone_mouse_event *event = (struct kone_mouse_event *)data; 84314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 84414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* keyboard events are always processed by default handler */ 84514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz if (size != sizeof(struct kone_mouse_event)) 84614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz return 0; 84714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 848901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz if (kone == NULL) 849901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz return 0; 850901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz 85114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz /* 85273b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz * Firmware 1.38 introduced new behaviour for tilt and special buttons. 85373b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz * Pressed button is reported in each movement event. 85414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz * Workaround sends only one event per press. 85514bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz */ 85673b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz if (memcmp(&kone->last_mouse_event.tilt, &event->tilt, 5)) 85773b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz memcpy(&kone->last_mouse_event, event, 85873b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz sizeof(struct kone_mouse_event)); 85914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz else 86073b3577d5dc80bf5f079ddd5c0449459a1997765Stefan Achatz memset(&event->tilt, 0, 5); 86114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 86248e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz kone_keep_values_up_to_date(kone, event); 86314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 864206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz if (kone->roccat_claimed) 865206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz kone_report_to_chrdev(kone, event); 866206f5f2fcb5ff5bb0c60f9e9189937f3ca03e378Stefan Achatz 86748e70804d37f9c52aab7c4ce7b7ab7bc7b800099Stefan Achatz return 0; /* always do further processing */ 86814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 86914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 87014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic const struct hid_device_id kone_devices[] = { 87114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, 87214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz { } 87314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}; 87414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 87514bf62cde79423a02a590e02664ed29a36facec1Stefan AchatzMODULE_DEVICE_TABLE(hid, kone_devices); 87614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 87714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzstatic struct hid_driver kone_driver = { 87814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz .name = "kone", 87914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz .id_table = kone_devices, 88014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz .probe = kone_probe, 88114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz .remove = kone_remove, 88214bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz .raw_event = kone_raw_event 88314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz}; 88414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 88500237bc5204c43f67b2e68546012d7bd27efc1b6Stefan Achatzstatic int __init kone_init(void) 88614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 8875012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz int retval; 8885012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 8895012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz /* class name has to be same as driver name */ 8905012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_class = class_create(THIS_MODULE, "kone"); 8915012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz if (IS_ERR(kone_class)) 8925012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz return PTR_ERR(kone_class); 8935012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_class->dev_attrs = kone_attributes; 8945012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz kone_class->dev_bin_attrs = kone_bin_attributes; 8955012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz 8965012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz retval = hid_register_driver(&kone_driver); 8975012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz if (retval) 8985012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz class_destroy(kone_class); 8995012aada506cb8b570e46579077c0ec5b82ebd5dStefan Achatz return retval; 90014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 90114bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 90200237bc5204c43f67b2e68546012d7bd27efc1b6Stefan Achatzstatic void __exit kone_exit(void) 90314bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz{ 90414bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz hid_unregister_driver(&kone_driver); 90574b643dac475e29f53f4132d2349ec1dba3c9e44Stefan Achatz class_destroy(kone_class); 90614bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz} 90714bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 90814bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzmodule_init(kone_init); 90914bf62cde79423a02a590e02664ed29a36facec1Stefan Achatzmodule_exit(kone_exit); 91014bf62cde79423a02a590e02664ed29a36facec1Stefan Achatz 9111f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_AUTHOR("Stefan Achatz"); 9121f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_DESCRIPTION("USB Roccat Kone driver"); 9131f749d8d5f92c275e35cdcd1fdcb7c8298157118Stefan AchatzMODULE_LICENSE("GPL v2"); 914