10e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz/* 20e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * Roccat Kova[+] driver for Linux 30e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * 40e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net> 50e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz */ 60e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 70e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz/* 80e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * This program is free software; you can redistribute it and/or modify it 90e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * under the terms of the GNU General Public License as published by the Free 100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * Software Foundation; either version 2 of the License, or (at your option) 110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * any later version. 120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz */ 130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz/* 150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons. 160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz */ 170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include <linux/device.h> 190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include <linux/input.h> 200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include <linux/hid.h> 210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include <linux/module.h> 220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include <linux/slab.h> 235dc0c9835fb96c75c8dbf657393764bd0abbac04Stefan Achatz#include <linux/hid-roccat.h> 240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include "hid-ids.h" 250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include "hid-roccat-common.h" 260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz#include "hid-roccat-kovaplus.h" 270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic uint profile_numbers[5] = {0, 1, 2, 3, 4}; 290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic struct class *kovaplus_class; 310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic uint kovaplus_convert_event_cpi(uint value) 330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return (value == 7 ? 4 : (value == 4 ? 3 : value)); 350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void kovaplus_profile_activated(struct kovaplus_device *kovaplus, 380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz uint new_profile_index) 390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_profile = new_profile_index; 410e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level; 420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x; 430e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y; 440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_send_control(struct usb_device *usb_dev, uint value, 470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz enum kovaplus_control_requests request) 480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_control control; 510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS || 530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) && 540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz value > 4) 550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz control.command = KOVAPLUS_COMMAND_CONTROL; 580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz control.value = value; 590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz control.request = request; 600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 611edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL, 620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &control, sizeof(struct kovaplus_control)); 630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_receive_control_status(struct usb_device *usb_dev) 680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_control control; 710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz do { 731edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL, 740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &control, sizeof(struct kovaplus_control)); 750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz /* check if we get a completely wrong answer */ 770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK) 810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz /* indicates that hardware needs some more time to complete action */ 840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) { 850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz msleep(500); /* windows driver uses 1000 */ 860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz continue; 870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz /* seems to be critical - replug necessary */ 900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) 910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 931edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz hid_err(usb_dev, "roccat_common_receive_control_status: " 940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz "unknown response value 0x%x\n", control.value); 950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } while (1); 970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_send(struct usb_device *usb_dev, uint command, 1000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz void const *buf, uint size) 1010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 1030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = roccat_common_send(usb_dev, command, buf, size); 1050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 1060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 1070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz msleep(100); 1090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return kovaplus_receive_control_status(usb_dev); 1110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_select_profile(struct usb_device *usb_dev, uint number, 1140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz enum kovaplus_control_requests request) 1150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return kovaplus_send_control(usb_dev, number, request); 1170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_get_info(struct usb_device *usb_dev, 1200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_info *buf) 1210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1221edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO, 1230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf, sizeof(struct kovaplus_info)); 1240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_get_profile_settings(struct usb_device *usb_dev, 1270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_settings *buf, uint number) 1280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 1300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_select_profile(usb_dev, number, 1320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS); 1330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 1340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 1350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1361edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, 1370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf, sizeof(struct kovaplus_profile_settings)); 1380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_set_profile_settings(struct usb_device *usb_dev, 1410e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_settings const *settings) 1420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1431edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, 1440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz settings, sizeof(struct kovaplus_profile_settings)); 1450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_get_profile_buttons(struct usb_device *usb_dev, 1480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_buttons *buf, int number) 1490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 1510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_select_profile(usb_dev, number, 1530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS); 1540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 1550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 1560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1571edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, 1580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf, sizeof(struct kovaplus_profile_buttons)); 1590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_set_profile_buttons(struct usb_device *usb_dev, 1620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_buttons const *buttons) 1630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1641edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, 1650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buttons, sizeof(struct kovaplus_profile_buttons)); 1660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz/* retval is 0-4 on success, < 0 on error */ 1690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_get_actual_profile(struct usb_device *usb_dev) 1700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_actual_profile buf; 1720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 1730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1741edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, 1750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &buf, sizeof(struct kovaplus_actual_profile)); 1760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval ? retval : buf.actual_profile; 1780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_set_actual_profile(struct usb_device *usb_dev, 1810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int new_profile) 1820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_actual_profile buf; 1840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE; 1860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf.size = sizeof(struct kovaplus_actual_profile); 1870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz buf.actual_profile = new_profile; 1880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1891edd5b42a6631b1b1f147e9018e309bde8d96a05Stefan Achatz return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, 1900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &buf, sizeof(struct kovaplus_actual_profile)); 1910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 1920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 1930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp, 1940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 1950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz loff_t off, size_t count) 1960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 1970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device *dev = 1980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 1990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 2000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off >= sizeof(struct kovaplus_profile_settings)) 2020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 2030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off + count > sizeof(struct kovaplus_profile_settings)) 2050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz count = sizeof(struct kovaplus_profile_settings) - off; 2060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_lock(&kovaplus->kovaplus_lock); 2080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off, 2090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz count); 2100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 2110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return count; 2130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 2140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp, 2160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 2170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz loff_t off, size_t count) 2180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 2190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device *dev = 2200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 2210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 2220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 2230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval = 0; 2240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int difference; 2250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int profile_index; 2260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_settings *profile_settings; 2270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off != 0 || count != sizeof(struct kovaplus_profile_settings)) 2290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 2300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index; 2320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz profile_settings = &kovaplus->profile_settings[profile_index]; 2330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_lock(&kovaplus->kovaplus_lock); 2350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz difference = memcmp(buf, profile_settings, 2360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz sizeof(struct kovaplus_profile_settings)); 2370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (difference) { 2380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_set_profile_settings(usb_dev, 2390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz (struct kovaplus_profile_settings const *)buf); 2400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (!retval) 2410e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz memcpy(profile_settings, buf, 2420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz sizeof(struct kovaplus_profile_settings)); 2430e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 2440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 2450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 2470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 2480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return sizeof(struct kovaplus_profile_settings); 2500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 2510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp, 2530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 2540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz loff_t off, size_t count) 2550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 2560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device *dev = 2570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 2580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 2590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off >= sizeof(struct kovaplus_profile_buttons)) 2610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 2620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off + count > sizeof(struct kovaplus_profile_buttons)) 2640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz count = sizeof(struct kovaplus_profile_buttons) - off; 2650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_lock(&kovaplus->kovaplus_lock); 2670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off, 2680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz count); 2690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 2700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return count; 2720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 2730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp, 2750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 2760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz loff_t off, size_t count) 2770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 2780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device *dev = 2790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz container_of(kobj, struct device, kobj)->parent->parent; 2800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 2810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 2820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval = 0; 2830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int difference; 2840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz uint profile_index; 2850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_profile_buttons *profile_buttons; 2860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (off != 0 || count != sizeof(struct kovaplus_profile_buttons)) 2880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 2890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index; 2910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz profile_buttons = &kovaplus->profile_buttons[profile_index]; 2920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 2930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_lock(&kovaplus->kovaplus_lock); 2940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz difference = memcmp(buf, profile_buttons, 2950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz sizeof(struct kovaplus_profile_buttons)); 2960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (difference) { 2970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_set_profile_buttons(usb_dev, 2980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz (struct kovaplus_profile_buttons const *)buf); 2990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (!retval) 3000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz memcpy(profile_buttons, buf, 3010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz sizeof(struct kovaplus_profile_buttons)); 3020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 3030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 3040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 3060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 3070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return sizeof(struct kovaplus_profile_buttons); 3090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev, 3120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char *buf) 3130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = 3150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 3160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile); 3170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, 3200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char const *buf, size_t size) 3210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus; 3230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_device *usb_dev; 3240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz unsigned long profile; 3250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 3266b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz struct kovaplus_roccat_report roccat_report; 3270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz dev = dev->parent->parent; 3290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus = hid_get_drvdata(dev_get_drvdata(dev)); 3300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz usb_dev = interface_to_usbdev(to_usb_interface(dev)); 3310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = strict_strtoul(buf, 10, &profile); 3330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 3340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 3350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (profile >= 5) 3370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -EINVAL; 3380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_lock(&kovaplus->kovaplus_lock); 3400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_set_actual_profile(usb_dev, profile); 3416b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz if (retval) { 3426b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 3436b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz return retval; 3446b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz } 3456b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz 346901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz kovaplus_profile_activated(kovaplus, profile); 3476b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz 3486b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report.type = KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1; 3496b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report.profile = profile + 1; 3506b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report.button = 0; 3516b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report.data1 = profile + 1; 3526b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report.data2 = 0; 3536b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz roccat_report_event(kovaplus->chrdev_minor, 3546b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz (uint8_t const *)&roccat_report); 3556b9a57b9fb8194e00d49779bd0d1130844db6a84Stefan Achatz 3560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_unlock(&kovaplus->kovaplus_lock); 3570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return size; 3590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev, 3620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char *buf) 3630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = 3650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 3660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi); 3670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev, 3700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char *buf) 3710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = 3730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 3740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity); 3750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev, 3780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char *buf) 3790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = 3810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 3820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity); 3830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev, 3860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct device_attribute *attr, char *buf) 3870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 3880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = 3890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); 3900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version); 3910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 3920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 3930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic struct device_attribute kovaplus_attributes[] = { 3940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR(actual_cpi, 0440, 3950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_show_actual_cpi, NULL), 3960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR(firmware_version, 0440, 3970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_show_firmware_version, NULL), 3980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR(actual_profile, 0660, 3990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_show_actual_profile, 4000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_set_actual_profile), 4010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR(actual_sensitivity_x, 0440, 4020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_show_actual_sensitivity_x, NULL), 4030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR(actual_sensitivity_y, 0440, 4040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_sysfs_show_actual_sensitivity_y, NULL), 4050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR_NULL 4060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz}; 4070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 4080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic struct bin_attribute kovaplus_bin_attributes[] = { 4090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile_settings", .mode = 0220 }, 4110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .write = kovaplus_sysfs_write_profile_settings 4130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile1_settings", .mode = 0440 }, 4160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_settings, 4180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[0] 4190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile2_settings", .mode = 0440 }, 4220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_settings, 4240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[1] 4250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile3_settings", .mode = 0440 }, 4280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_settings, 4300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[2] 4310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile4_settings", .mode = 0440 }, 4340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_settings, 4360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[3] 4370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile5_settings", .mode = 0440 }, 4400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_settings), 4410e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_settings, 4420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[4] 4430e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile_buttons", .mode = 0220 }, 4460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .write = kovaplus_sysfs_write_profile_buttons 4480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile1_buttons", .mode = 0440 }, 4510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_buttons, 4530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[0] 4540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile2_buttons", .mode = 0440 }, 4570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_buttons, 4590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[1] 4600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile3_buttons", .mode = 0440 }, 4630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_buttons, 4650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[2] 4660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile4_buttons", .mode = 0440 }, 4690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_buttons, 4710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[3] 4720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { 4740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .attr = { .name = "profile5_buttons", .mode = 0440 }, 4750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .size = sizeof(struct kovaplus_profile_buttons), 4760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .read = kovaplus_sysfs_read_profilex_buttons, 4770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .private = &profile_numbers[4] 4780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz }, 4790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz __ATTR_NULL 4800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz}; 4810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 4820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev, 4830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus) 4840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 4850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval, i; 4860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz static uint wait = 70; /* device will freeze with just 60 */ 4870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 4880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz mutex_init(&kovaplus->kovaplus_lock); 4890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 4900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_get_info(usb_dev, &kovaplus->info); 4910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 4920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 4930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 4940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz for (i = 0; i < 5; ++i) { 4950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz msleep(wait); 4960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_get_profile_settings(usb_dev, 4970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &kovaplus->profile_settings[i], i); 4980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 4990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 5000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz msleep(wait); 5020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_get_profile_buttons(usb_dev, 5030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz &kovaplus->profile_buttons[i], i); 5040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 5050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 5060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz msleep(wait); 5090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_get_actual_profile(usb_dev); 5100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval < 0) 5110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 5120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_profile_activated(kovaplus, retval); 5130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 5150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 5160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_init_specials(struct hid_device *hdev) 5180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 5190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 5200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(intf); 5210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus; 5220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 5230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 5250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 5260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL); 5280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (!kovaplus) { 5290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "can't alloc device descriptor\n"); 5300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return -ENOMEM; 5310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_set_drvdata(hdev, kovaplus); 5330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus); 5350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) { 5360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "couldn't init struct kovaplus_device\n"); 5370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz goto exit_free; 5380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5408211e46004518c977f70f2661da961d5ba617399Stefan Achatz retval = roccat_connect(kovaplus_class, hdev, 5418211e46004518c977f70f2661da961d5ba617399Stefan Achatz sizeof(struct kovaplus_roccat_report)); 5420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval < 0) { 5430e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "couldn't init char dev\n"); 5440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } else { 5450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->chrdev_minor = retval; 5460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->roccat_claimed = 1; 5470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } else { 5500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_set_drvdata(hdev, NULL); 5510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 5540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzexit_free: 5550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kfree(kovaplus); 5560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 5570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 5580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void kovaplus_remove_specials(struct hid_device *hdev) 5600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 5610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 5620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus; 5630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 5650e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 5660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus = hid_get_drvdata(hdev); 5670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (kovaplus->roccat_claimed) 5680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_disconnect(kovaplus->chrdev_minor); 5690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kfree(kovaplus); 5700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 5720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_probe(struct hid_device *hdev, 5740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz const struct hid_device_id *id) 5750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 5760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 5770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5780e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = hid_parse(hdev); 5790e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) { 5800e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "parse failed\n"); 5810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz goto exit; 5820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 5850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) { 5860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "hw start failed\n"); 5870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz goto exit; 5880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = kovaplus_init_specials(hdev); 5910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) { 5920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_err(hdev, "couldn't install mouse\n"); 5930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz goto exit_stop; 5940e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 5950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 5970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 5980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzexit_stop: 5990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_hw_stop(hdev); 6000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzexit: 6010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 6020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 6030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void kovaplus_remove(struct hid_device *hdev) 6050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 6060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_remove_specials(hdev); 6070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_hw_stop(hdev); 6080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 6090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus, 6110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz u8 const *data) 6120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 6130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_mouse_report_button const *button_report; 6140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 6160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return; 6170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz button_report = (struct kovaplus_mouse_report_button const *)data; 6190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz switch (button_report->type) { 6210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1: 6220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_profile_activated(kovaplus, button_report->data1 - 1); 6230e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz break; 6240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI: 6250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1); 6260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY: 6270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_x_sensitivity = button_report->data1; 6280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus->actual_y_sensitivity = button_report->data2; 6290e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz } 6300e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 6310e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6320e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus, 6330e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz u8 const *data) 6340e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 6350e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_roccat_report roccat_report; 6360e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_mouse_report_button const *button_report; 6370e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6380e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON) 6390e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return; 6400e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6410e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz button_report = (struct kovaplus_mouse_report_button const *)data; 6420e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6430e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2) 6440e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return; 6450e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6460e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.type = button_report->type; 6470e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.profile = kovaplus->actual_profile + 1; 6480e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6490e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO || 6500e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT || 6510e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH || 6520e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) 6530e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.button = button_report->data1; 6540e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz else 6550e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.button = 0; 6560e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6570e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI) 6580e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1); 6590e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz else 6600e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.data1 = button_report->data1; 6610e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6620e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report.data2 = button_report->data2; 6630e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6640e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz roccat_report_event(kovaplus->chrdev_minor, 6658211e46004518c977f70f2661da961d5ba617399Stefan Achatz (uint8_t const *)&roccat_report); 6660e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 6670e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6680e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int kovaplus_raw_event(struct hid_device *hdev, 6690e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct hid_report *report, u8 *data, int size) 6700e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 6710e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 6720e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz struct kovaplus_device *kovaplus = hid_get_drvdata(hdev); 6730e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6740e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 6750e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz != USB_INTERFACE_PROTOCOL_MOUSE) 6760e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 6770e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 678901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz if (kovaplus == NULL) 679901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz return 0; 680901e64dbdb5998b9248c372a401c921bbdf662f6Stefan Achatz 6810e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_keep_values_up_to_date(kovaplus, data); 6820e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6830e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (kovaplus->roccat_claimed) 6840e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_report_to_chrdev(kovaplus, data); 6850e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6860e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return 0; 6870e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 6880e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6890e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic const struct hid_device_id kovaplus_devices[] = { 6900e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, 6910e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz { } 6920e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz}; 6930e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6940e70f97f257edcef4daa92ab9371a9aac0c851edStefan AchatzMODULE_DEVICE_TABLE(hid, kovaplus_devices); 6950e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 6960e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic struct hid_driver kovaplus_driver = { 6970e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .name = "kovaplus", 6980e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .id_table = kovaplus_devices, 6990e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .probe = kovaplus_probe, 7000e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .remove = kovaplus_remove, 7010e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz .raw_event = kovaplus_raw_event 7020e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz}; 7030e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7040e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic int __init kovaplus_init(void) 7050e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 7060e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz int retval; 7070e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7080e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_class = class_create(THIS_MODULE, "kovaplus"); 7090e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (IS_ERR(kovaplus_class)) 7100e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return PTR_ERR(kovaplus_class); 7110e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_class->dev_attrs = kovaplus_attributes; 7120e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes; 7130e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7140e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz retval = hid_register_driver(&kovaplus_driver); 7150e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz if (retval) 7160e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz class_destroy(kovaplus_class); 7170e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz return retval; 7180e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 7190e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7200e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzstatic void __exit kovaplus_exit(void) 7210e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz{ 7220e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz hid_unregister_driver(&kovaplus_driver); 72374b643dac475e29f53f4132d2349ec1dba3c9e44Stefan Achatz class_destroy(kovaplus_class); 7240e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz} 7250e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7260e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzmodule_init(kovaplus_init); 7270e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatzmodule_exit(kovaplus_exit); 7280e70f97f257edcef4daa92ab9371a9aac0c851edStefan Achatz 7290e70f97f257edcef4daa92ab9371a9aac0c851edStefan AchatzMODULE_AUTHOR("Stefan Achatz"); 7300e70f97f257edcef4daa92ab9371a9aac0c851edStefan AchatzMODULE_DESCRIPTION("USB Roccat Kova[+] driver"); 7310e70f97f257edcef4daa92ab9371a9aac0c851edStefan AchatzMODULE_LICENSE("GPL v2"); 732