1cb7cf3daSStefan Achatz /* 2cb7cf3daSStefan Achatz * Roccat Pyra driver for Linux 3cb7cf3daSStefan Achatz * 4cb7cf3daSStefan Achatz * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net> 5cb7cf3daSStefan Achatz */ 6cb7cf3daSStefan Achatz 7cb7cf3daSStefan Achatz /* 8cb7cf3daSStefan Achatz * This program is free software; you can redistribute it and/or modify it 9cb7cf3daSStefan Achatz * under the terms of the GNU General Public License as published by the Free 10cb7cf3daSStefan Achatz * Software Foundation; either version 2 of the License, or (at your option) 11cb7cf3daSStefan Achatz * any later version. 12cb7cf3daSStefan Achatz */ 13cb7cf3daSStefan Achatz 14cb7cf3daSStefan Achatz /* 15cb7cf3daSStefan Achatz * Roccat Pyra is a mobile gamer mouse which comes in wired and wireless 16cb7cf3daSStefan Achatz * variant. Wireless variant is not tested. 17cb7cf3daSStefan Achatz * Userland tools can be found at http://sourceforge.net/projects/roccat 18cb7cf3daSStefan Achatz */ 19cb7cf3daSStefan Achatz 20cb7cf3daSStefan Achatz #include <linux/device.h> 21cb7cf3daSStefan Achatz #include <linux/input.h> 22cb7cf3daSStefan Achatz #include <linux/hid.h> 23cb7cf3daSStefan Achatz #include <linux/usb.h> 24cb7cf3daSStefan Achatz #include <linux/module.h> 25cb7cf3daSStefan Achatz #include <linux/slab.h> 26cb7cf3daSStefan Achatz #include "hid-ids.h" 27cb7cf3daSStefan Achatz #include "hid-roccat.h" 28cb7cf3daSStefan Achatz #include "hid-roccat-pyra.h" 29cb7cf3daSStefan Achatz 30cb7cf3daSStefan Achatz static void profile_activated(struct pyra_device *pyra, 31cb7cf3daSStefan Achatz unsigned int new_profile) 32cb7cf3daSStefan Achatz { 33cb7cf3daSStefan Achatz pyra->actual_profile = new_profile; 34cb7cf3daSStefan Achatz pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi; 35cb7cf3daSStefan Achatz } 36cb7cf3daSStefan Achatz 37cb7cf3daSStefan Achatz static int pyra_send_control(struct usb_device *usb_dev, int value, 38cb7cf3daSStefan Achatz enum pyra_control_requests request) 39cb7cf3daSStefan Achatz { 40cb7cf3daSStefan Achatz int len; 41cb7cf3daSStefan Achatz struct pyra_control control; 42cb7cf3daSStefan Achatz 43cb7cf3daSStefan Achatz if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS || 44cb7cf3daSStefan Achatz request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) && 45cb7cf3daSStefan Achatz (value < 0 || value > 4)) 46cb7cf3daSStefan Achatz return -EINVAL; 47cb7cf3daSStefan Achatz 48cb7cf3daSStefan Achatz control.command = PYRA_COMMAND_CONTROL; 49cb7cf3daSStefan Achatz control.value = value; 50cb7cf3daSStefan Achatz control.request = request; 51cb7cf3daSStefan Achatz 52cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 53cb7cf3daSStefan Achatz USB_REQ_SET_CONFIGURATION, 54cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 55cb7cf3daSStefan Achatz PYRA_USB_COMMAND_CONTROL, 0, (char *)&control, 56cb7cf3daSStefan Achatz sizeof(struct pyra_control), 57cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 58cb7cf3daSStefan Achatz 59cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_control)) 60cb7cf3daSStefan Achatz return len; 61cb7cf3daSStefan Achatz 62cb7cf3daSStefan Achatz return 0; 63cb7cf3daSStefan Achatz } 64cb7cf3daSStefan Achatz 65cb7cf3daSStefan Achatz static int pyra_receive_control_status(struct usb_device *usb_dev) 66cb7cf3daSStefan Achatz { 67cb7cf3daSStefan Achatz int len; 68cb7cf3daSStefan Achatz struct pyra_control control; 69cb7cf3daSStefan Achatz 70cb7cf3daSStefan Achatz do { 71cb7cf3daSStefan Achatz msleep(10); 72cb7cf3daSStefan Achatz 73cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 74cb7cf3daSStefan Achatz USB_REQ_CLEAR_FEATURE, 75cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | 76cb7cf3daSStefan Achatz USB_DIR_IN, 77cb7cf3daSStefan Achatz PYRA_USB_COMMAND_CONTROL, 0, (char *)&control, 78cb7cf3daSStefan Achatz sizeof(struct pyra_control), 79cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 80cb7cf3daSStefan Achatz 81cb7cf3daSStefan Achatz /* requested too early, try again */ 82cb7cf3daSStefan Achatz } while (len == -EPROTO); 83cb7cf3daSStefan Achatz 84cb7cf3daSStefan Achatz if (len == sizeof(struct pyra_control) && 85cb7cf3daSStefan Achatz control.command == PYRA_COMMAND_CONTROL && 86cb7cf3daSStefan Achatz control.request == PYRA_CONTROL_REQUEST_STATUS && 87cb7cf3daSStefan Achatz control.value == 1) 88cb7cf3daSStefan Achatz return 0; 89cb7cf3daSStefan Achatz else { 90cb7cf3daSStefan Achatz dev_err(&usb_dev->dev, "receive control status: " 91cb7cf3daSStefan Achatz "unknown response 0x%x 0x%x\n", 92cb7cf3daSStefan Achatz control.request, control.value); 93cb7cf3daSStefan Achatz return -EINVAL; 94cb7cf3daSStefan Achatz } 95cb7cf3daSStefan Achatz } 96cb7cf3daSStefan Achatz 97cb7cf3daSStefan Achatz static int pyra_get_profile_settings(struct usb_device *usb_dev, 98cb7cf3daSStefan Achatz struct pyra_profile_settings *buf, int number) 99cb7cf3daSStefan Achatz { 100cb7cf3daSStefan Achatz int retval; 101cb7cf3daSStefan Achatz 102cb7cf3daSStefan Achatz retval = pyra_send_control(usb_dev, number, 103cb7cf3daSStefan Achatz PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); 104cb7cf3daSStefan Achatz 105cb7cf3daSStefan Achatz if (retval) 106cb7cf3daSStefan Achatz return retval; 107cb7cf3daSStefan Achatz 108cb7cf3daSStefan Achatz retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 109cb7cf3daSStefan Achatz USB_REQ_CLEAR_FEATURE, 110cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 111cb7cf3daSStefan Achatz PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf, 112cb7cf3daSStefan Achatz sizeof(struct pyra_profile_settings), 113cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 114cb7cf3daSStefan Achatz 115cb7cf3daSStefan Achatz if (retval != sizeof(struct pyra_profile_settings)) 116cb7cf3daSStefan Achatz return retval; 117cb7cf3daSStefan Achatz 118cb7cf3daSStefan Achatz return 0; 119cb7cf3daSStefan Achatz } 120cb7cf3daSStefan Achatz 121cb7cf3daSStefan Achatz static int pyra_get_profile_buttons(struct usb_device *usb_dev, 122cb7cf3daSStefan Achatz struct pyra_profile_buttons *buf, int number) 123cb7cf3daSStefan Achatz { 124cb7cf3daSStefan Achatz int retval; 125cb7cf3daSStefan Achatz 126cb7cf3daSStefan Achatz retval = pyra_send_control(usb_dev, number, 127cb7cf3daSStefan Achatz PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); 128cb7cf3daSStefan Achatz 129cb7cf3daSStefan Achatz if (retval) 130cb7cf3daSStefan Achatz return retval; 131cb7cf3daSStefan Achatz 132cb7cf3daSStefan Achatz retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 133cb7cf3daSStefan Achatz USB_REQ_CLEAR_FEATURE, 134cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 135cb7cf3daSStefan Achatz PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf, 136cb7cf3daSStefan Achatz sizeof(struct pyra_profile_buttons), 137cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 138cb7cf3daSStefan Achatz 139cb7cf3daSStefan Achatz if (retval != sizeof(struct pyra_profile_buttons)) 140cb7cf3daSStefan Achatz return retval; 141cb7cf3daSStefan Achatz 142cb7cf3daSStefan Achatz return 0; 143cb7cf3daSStefan Achatz } 144cb7cf3daSStefan Achatz 145cb7cf3daSStefan Achatz static int pyra_get_settings(struct usb_device *usb_dev, 146cb7cf3daSStefan Achatz struct pyra_settings *buf) 147cb7cf3daSStefan Achatz { 148cb7cf3daSStefan Achatz int len; 149cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 150cb7cf3daSStefan Achatz USB_REQ_CLEAR_FEATURE, 151cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 152cb7cf3daSStefan Achatz PYRA_USB_COMMAND_SETTINGS, 0, buf, 153cb7cf3daSStefan Achatz sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT); 154cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_settings)) 155cb7cf3daSStefan Achatz return -EIO; 156cb7cf3daSStefan Achatz return 0; 157cb7cf3daSStefan Achatz } 158cb7cf3daSStefan Achatz 159cb7cf3daSStefan Achatz static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) 160cb7cf3daSStefan Achatz { 161cb7cf3daSStefan Achatz int len; 162cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 163cb7cf3daSStefan Achatz USB_REQ_CLEAR_FEATURE, 164cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 165cb7cf3daSStefan Achatz PYRA_USB_COMMAND_INFO, 0, buf, 166cb7cf3daSStefan Achatz sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT); 167cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_info)) 168cb7cf3daSStefan Achatz return -EIO; 169cb7cf3daSStefan Achatz return 0; 170cb7cf3daSStefan Achatz } 171cb7cf3daSStefan Achatz 172cb7cf3daSStefan Achatz static int pyra_set_profile_settings(struct usb_device *usb_dev, 173cb7cf3daSStefan Achatz struct pyra_profile_settings const *settings) 174cb7cf3daSStefan Achatz { 175cb7cf3daSStefan Achatz int len; 176cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 177cb7cf3daSStefan Achatz USB_REQ_SET_CONFIGURATION, 178cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 179cb7cf3daSStefan Achatz PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings, 180cb7cf3daSStefan Achatz sizeof(struct pyra_profile_settings), 181cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 182cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_profile_settings)) 183cb7cf3daSStefan Achatz return -EIO; 184cb7cf3daSStefan Achatz if (pyra_receive_control_status(usb_dev)) 185cb7cf3daSStefan Achatz return -EIO; 186cb7cf3daSStefan Achatz return 0; 187cb7cf3daSStefan Achatz } 188cb7cf3daSStefan Achatz 189cb7cf3daSStefan Achatz static int pyra_set_profile_buttons(struct usb_device *usb_dev, 190cb7cf3daSStefan Achatz struct pyra_profile_buttons const *buttons) 191cb7cf3daSStefan Achatz { 192cb7cf3daSStefan Achatz int len; 193cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 194cb7cf3daSStefan Achatz USB_REQ_SET_CONFIGURATION, 195cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 196cb7cf3daSStefan Achatz PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons, 197cb7cf3daSStefan Achatz sizeof(struct pyra_profile_buttons), 198cb7cf3daSStefan Achatz USB_CTRL_SET_TIMEOUT); 199cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_profile_buttons)) 200cb7cf3daSStefan Achatz return -EIO; 201cb7cf3daSStefan Achatz if (pyra_receive_control_status(usb_dev)) 202cb7cf3daSStefan Achatz return -EIO; 203cb7cf3daSStefan Achatz return 0; 204cb7cf3daSStefan Achatz } 205cb7cf3daSStefan Achatz 206cb7cf3daSStefan Achatz static int pyra_set_settings(struct usb_device *usb_dev, 207cb7cf3daSStefan Achatz struct pyra_settings const *settings) 208cb7cf3daSStefan Achatz { 209cb7cf3daSStefan Achatz int len; 210cb7cf3daSStefan Achatz len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 211cb7cf3daSStefan Achatz USB_REQ_SET_CONFIGURATION, 212cb7cf3daSStefan Achatz USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 213cb7cf3daSStefan Achatz PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings, 214cb7cf3daSStefan Achatz sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT); 215cb7cf3daSStefan Achatz if (len != sizeof(struct pyra_settings)) 216cb7cf3daSStefan Achatz return -EIO; 217cb7cf3daSStefan Achatz if (pyra_receive_control_status(usb_dev)) 218cb7cf3daSStefan Achatz return -EIO; 219cb7cf3daSStefan Achatz return 0; 220cb7cf3daSStefan Achatz } 221cb7cf3daSStefan Achatz 222cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, 223cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 224cb7cf3daSStefan Achatz loff_t off, size_t count, int number) 225cb7cf3daSStefan Achatz { 226cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 227cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 228cb7cf3daSStefan Achatz 229cb7cf3daSStefan Achatz if (off >= sizeof(struct pyra_profile_settings)) 230cb7cf3daSStefan Achatz return 0; 231cb7cf3daSStefan Achatz 232cb7cf3daSStefan Achatz if (off + count > sizeof(struct pyra_profile_settings)) 233cb7cf3daSStefan Achatz count = sizeof(struct pyra_profile_settings) - off; 234cb7cf3daSStefan Achatz 235cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 236cb7cf3daSStefan Achatz memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off, 237cb7cf3daSStefan Achatz count); 238cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 239cb7cf3daSStefan Achatz 240cb7cf3daSStefan Achatz return count; 241cb7cf3daSStefan Achatz } 242cb7cf3daSStefan Achatz 243cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp, 244cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 245cb7cf3daSStefan Achatz loff_t off, size_t count) 246cb7cf3daSStefan Achatz { 247cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_settings(fp, kobj, 248cb7cf3daSStefan Achatz attr, buf, off, count, 0); 249cb7cf3daSStefan Achatz } 250cb7cf3daSStefan Achatz 251cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp, 252cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 253cb7cf3daSStefan Achatz loff_t off, size_t count) 254cb7cf3daSStefan Achatz { 255cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_settings(fp, kobj, 256cb7cf3daSStefan Achatz attr, buf, off, count, 1); 257cb7cf3daSStefan Achatz } 258cb7cf3daSStefan Achatz 259cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp, 260cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 261cb7cf3daSStefan Achatz loff_t off, size_t count) 262cb7cf3daSStefan Achatz { 263cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_settings(fp, kobj, 264cb7cf3daSStefan Achatz attr, buf, off, count, 2); 265cb7cf3daSStefan Achatz } 266cb7cf3daSStefan Achatz 267cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp, 268cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 269cb7cf3daSStefan Achatz loff_t off, size_t count) 270cb7cf3daSStefan Achatz { 271cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_settings(fp, kobj, 272cb7cf3daSStefan Achatz attr, buf, off, count, 3); 273cb7cf3daSStefan Achatz } 274cb7cf3daSStefan Achatz 275cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp, 276cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 277cb7cf3daSStefan Achatz loff_t off, size_t count) 278cb7cf3daSStefan Achatz { 279cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_settings(fp, kobj, 280cb7cf3daSStefan Achatz attr, buf, off, count, 4); 281cb7cf3daSStefan Achatz } 282cb7cf3daSStefan Achatz 283cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp, 284cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 285cb7cf3daSStefan Achatz loff_t off, size_t count, int number) 286cb7cf3daSStefan Achatz { 287cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 288cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 289cb7cf3daSStefan Achatz 290cb7cf3daSStefan Achatz if (off >= sizeof(struct pyra_profile_buttons)) 291cb7cf3daSStefan Achatz return 0; 292cb7cf3daSStefan Achatz 293cb7cf3daSStefan Achatz if (off + count > sizeof(struct pyra_profile_buttons)) 294cb7cf3daSStefan Achatz count = sizeof(struct pyra_profile_buttons) - off; 295cb7cf3daSStefan Achatz 296cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 297cb7cf3daSStefan Achatz memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off, 298cb7cf3daSStefan Achatz count); 299cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 300cb7cf3daSStefan Achatz 301cb7cf3daSStefan Achatz return count; 302cb7cf3daSStefan Achatz } 303cb7cf3daSStefan Achatz 304cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp, 305cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 306cb7cf3daSStefan Achatz loff_t off, size_t count) 307cb7cf3daSStefan Achatz { 308cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_buttons(fp, kobj, 309cb7cf3daSStefan Achatz attr, buf, off, count, 0); 310cb7cf3daSStefan Achatz } 311cb7cf3daSStefan Achatz 312cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp, 313cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 314cb7cf3daSStefan Achatz loff_t off, size_t count) 315cb7cf3daSStefan Achatz { 316cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_buttons(fp, kobj, 317cb7cf3daSStefan Achatz attr, buf, off, count, 1); 318cb7cf3daSStefan Achatz } 319cb7cf3daSStefan Achatz 320cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp, 321cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 322cb7cf3daSStefan Achatz loff_t off, size_t count) 323cb7cf3daSStefan Achatz { 324cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_buttons(fp, kobj, 325cb7cf3daSStefan Achatz attr, buf, off, count, 2); 326cb7cf3daSStefan Achatz } 327cb7cf3daSStefan Achatz 328cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp, 329cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 330cb7cf3daSStefan Achatz loff_t off, size_t count) 331cb7cf3daSStefan Achatz { 332cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_buttons(fp, kobj, 333cb7cf3daSStefan Achatz attr, buf, off, count, 3); 334cb7cf3daSStefan Achatz } 335cb7cf3daSStefan Achatz 336cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp, 337cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 338cb7cf3daSStefan Achatz loff_t off, size_t count) 339cb7cf3daSStefan Achatz { 340cb7cf3daSStefan Achatz return pyra_sysfs_read_profilex_buttons(fp, kobj, 341cb7cf3daSStefan Achatz attr, buf, off, count, 4); 342cb7cf3daSStefan Achatz } 343cb7cf3daSStefan Achatz 344cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_write_profile_settings(struct file *fp, 345cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 346cb7cf3daSStefan Achatz loff_t off, size_t count) 347cb7cf3daSStefan Achatz { 348cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 349cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 350cb7cf3daSStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 351cb7cf3daSStefan Achatz int retval = 0; 352cb7cf3daSStefan Achatz int difference; 353cb7cf3daSStefan Achatz int profile_number; 354cb7cf3daSStefan Achatz struct pyra_profile_settings *profile_settings; 355cb7cf3daSStefan Achatz 356cb7cf3daSStefan Achatz if (off != 0 || count != sizeof(struct pyra_profile_settings)) 357cb7cf3daSStefan Achatz return -EINVAL; 358cb7cf3daSStefan Achatz 359cb7cf3daSStefan Achatz profile_number = ((struct pyra_profile_settings const *)buf)->number; 360cb7cf3daSStefan Achatz profile_settings = &pyra->profile_settings[profile_number]; 361cb7cf3daSStefan Achatz 362cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 363cb7cf3daSStefan Achatz difference = memcmp(buf, profile_settings, 364cb7cf3daSStefan Achatz sizeof(struct pyra_profile_settings)); 365cb7cf3daSStefan Achatz if (difference) { 366cb7cf3daSStefan Achatz retval = pyra_set_profile_settings(usb_dev, 367cb7cf3daSStefan Achatz (struct pyra_profile_settings const *)buf); 368cb7cf3daSStefan Achatz if (!retval) 369cb7cf3daSStefan Achatz memcpy(profile_settings, buf, 370cb7cf3daSStefan Achatz sizeof(struct pyra_profile_settings)); 371cb7cf3daSStefan Achatz } 372cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 373cb7cf3daSStefan Achatz 374cb7cf3daSStefan Achatz if (retval) 375cb7cf3daSStefan Achatz return retval; 376cb7cf3daSStefan Achatz 377cb7cf3daSStefan Achatz return sizeof(struct pyra_profile_settings); 378cb7cf3daSStefan Achatz } 379cb7cf3daSStefan Achatz 380cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp, 381cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 382cb7cf3daSStefan Achatz loff_t off, size_t count) 383cb7cf3daSStefan Achatz { 384cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 385cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 386cb7cf3daSStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 387cb7cf3daSStefan Achatz int retval = 0; 388cb7cf3daSStefan Achatz int difference; 389cb7cf3daSStefan Achatz int profile_number; 390cb7cf3daSStefan Achatz struct pyra_profile_buttons *profile_buttons; 391cb7cf3daSStefan Achatz 392cb7cf3daSStefan Achatz if (off != 0 || count != sizeof(struct pyra_profile_buttons)) 393cb7cf3daSStefan Achatz return -EINVAL; 394cb7cf3daSStefan Achatz 395cb7cf3daSStefan Achatz profile_number = ((struct pyra_profile_buttons const *)buf)->number; 396cb7cf3daSStefan Achatz profile_buttons = &pyra->profile_buttons[profile_number]; 397cb7cf3daSStefan Achatz 398cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 399cb7cf3daSStefan Achatz difference = memcmp(buf, profile_buttons, 400cb7cf3daSStefan Achatz sizeof(struct pyra_profile_buttons)); 401cb7cf3daSStefan Achatz if (difference) { 402cb7cf3daSStefan Achatz retval = pyra_set_profile_buttons(usb_dev, 403cb7cf3daSStefan Achatz (struct pyra_profile_buttons const *)buf); 404cb7cf3daSStefan Achatz if (!retval) 405cb7cf3daSStefan Achatz memcpy(profile_buttons, buf, 406cb7cf3daSStefan Achatz sizeof(struct pyra_profile_buttons)); 407cb7cf3daSStefan Achatz } 408cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 409cb7cf3daSStefan Achatz 410cb7cf3daSStefan Achatz if (retval) 411cb7cf3daSStefan Achatz return retval; 412cb7cf3daSStefan Achatz 413cb7cf3daSStefan Achatz return sizeof(struct pyra_profile_buttons); 414cb7cf3daSStefan Achatz } 415cb7cf3daSStefan Achatz 416cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_read_settings(struct file *fp, 417cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 418cb7cf3daSStefan Achatz loff_t off, size_t count) 419cb7cf3daSStefan Achatz { 420cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 421cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 422cb7cf3daSStefan Achatz 423cb7cf3daSStefan Achatz if (off >= sizeof(struct pyra_settings)) 424cb7cf3daSStefan Achatz return 0; 425cb7cf3daSStefan Achatz 426cb7cf3daSStefan Achatz if (off + count > sizeof(struct pyra_settings)) 427cb7cf3daSStefan Achatz count = sizeof(struct pyra_settings) - off; 428cb7cf3daSStefan Achatz 429cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 430cb7cf3daSStefan Achatz memcpy(buf, ((char const *)&pyra->settings) + off, count); 431cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 432cb7cf3daSStefan Achatz 433cb7cf3daSStefan Achatz return count; 434cb7cf3daSStefan Achatz } 435cb7cf3daSStefan Achatz 436cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_write_settings(struct file *fp, 437cb7cf3daSStefan Achatz struct kobject *kobj, struct bin_attribute *attr, char *buf, 438cb7cf3daSStefan Achatz loff_t off, size_t count) 439cb7cf3daSStefan Achatz { 440cb7cf3daSStefan Achatz struct device *dev = container_of(kobj, struct device, kobj); 441cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 442cb7cf3daSStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 443cb7cf3daSStefan Achatz int retval = 0; 444cb7cf3daSStefan Achatz int difference; 445cb7cf3daSStefan Achatz 446cb7cf3daSStefan Achatz if (off != 0 || count != sizeof(struct pyra_settings)) 447cb7cf3daSStefan Achatz return -EINVAL; 448cb7cf3daSStefan Achatz 449cb7cf3daSStefan Achatz mutex_lock(&pyra->pyra_lock); 450cb7cf3daSStefan Achatz difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings)); 451cb7cf3daSStefan Achatz if (difference) { 452cb7cf3daSStefan Achatz retval = pyra_set_settings(usb_dev, 453cb7cf3daSStefan Achatz (struct pyra_settings const *)buf); 454cb7cf3daSStefan Achatz if (!retval) 455cb7cf3daSStefan Achatz memcpy(&pyra->settings, buf, 456cb7cf3daSStefan Achatz sizeof(struct pyra_settings)); 457cb7cf3daSStefan Achatz } 458cb7cf3daSStefan Achatz mutex_unlock(&pyra->pyra_lock); 459cb7cf3daSStefan Achatz 460cb7cf3daSStefan Achatz if (retval) 461cb7cf3daSStefan Achatz return retval; 462cb7cf3daSStefan Achatz 463cb7cf3daSStefan Achatz profile_activated(pyra, pyra->settings.startup_profile); 464cb7cf3daSStefan Achatz 465cb7cf3daSStefan Achatz return sizeof(struct pyra_settings); 466cb7cf3daSStefan Achatz } 467cb7cf3daSStefan Achatz 468cb7cf3daSStefan Achatz 469cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev, 470cb7cf3daSStefan Achatz struct device_attribute *attr, char *buf) 471cb7cf3daSStefan Achatz { 472cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 473cb7cf3daSStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi); 474cb7cf3daSStefan Achatz } 475cb7cf3daSStefan Achatz 476cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_show_actual_profile(struct device *dev, 477cb7cf3daSStefan Achatz struct device_attribute *attr, char *buf) 478cb7cf3daSStefan Achatz { 479cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 480cb7cf3daSStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile); 481cb7cf3daSStefan Achatz } 482cb7cf3daSStefan Achatz 483cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_show_firmware_version(struct device *dev, 484cb7cf3daSStefan Achatz struct device_attribute *attr, char *buf) 485cb7cf3daSStefan Achatz { 486cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 487cb7cf3daSStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version); 488cb7cf3daSStefan Achatz } 489cb7cf3daSStefan Achatz 490cb7cf3daSStefan Achatz static ssize_t pyra_sysfs_show_startup_profile(struct device *dev, 491cb7cf3daSStefan Achatz struct device_attribute *attr, char *buf) 492cb7cf3daSStefan Achatz { 493cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev)); 494cb7cf3daSStefan Achatz return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile); 495cb7cf3daSStefan Achatz } 496cb7cf3daSStefan Achatz 497cb7cf3daSStefan Achatz static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL); 498cb7cf3daSStefan Achatz 499cb7cf3daSStefan Achatz static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL); 500cb7cf3daSStefan Achatz 501cb7cf3daSStefan Achatz static DEVICE_ATTR(firmware_version, 0440, 502cb7cf3daSStefan Achatz pyra_sysfs_show_firmware_version, NULL); 503cb7cf3daSStefan Achatz 504cb7cf3daSStefan Achatz static DEVICE_ATTR(startup_profile, 0440, 505cb7cf3daSStefan Achatz pyra_sysfs_show_startup_profile, NULL); 506cb7cf3daSStefan Achatz 507cb7cf3daSStefan Achatz static struct attribute *pyra_attributes[] = { 508cb7cf3daSStefan Achatz &dev_attr_actual_cpi.attr, 509cb7cf3daSStefan Achatz &dev_attr_actual_profile.attr, 510cb7cf3daSStefan Achatz &dev_attr_firmware_version.attr, 511cb7cf3daSStefan Achatz &dev_attr_startup_profile.attr, 512cb7cf3daSStefan Achatz NULL 513cb7cf3daSStefan Achatz }; 514cb7cf3daSStefan Achatz 515cb7cf3daSStefan Achatz static struct attribute_group pyra_attribute_group = { 516cb7cf3daSStefan Achatz .attrs = pyra_attributes 517cb7cf3daSStefan Achatz }; 518cb7cf3daSStefan Achatz 519cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile_settings_attr = { 520cb7cf3daSStefan Achatz .attr = { .name = "profile_settings", .mode = 0220 }, 521cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 522cb7cf3daSStefan Achatz .write = pyra_sysfs_write_profile_settings 523cb7cf3daSStefan Achatz }; 524cb7cf3daSStefan Achatz 525cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile1_settings_attr = { 526cb7cf3daSStefan Achatz .attr = { .name = "profile1_settings", .mode = 0440 }, 527cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 528cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile1_settings 529cb7cf3daSStefan Achatz }; 530cb7cf3daSStefan Achatz 531cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile2_settings_attr = { 532cb7cf3daSStefan Achatz .attr = { .name = "profile2_settings", .mode = 0440 }, 533cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 534cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile2_settings 535cb7cf3daSStefan Achatz }; 536cb7cf3daSStefan Achatz 537cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile3_settings_attr = { 538cb7cf3daSStefan Achatz .attr = { .name = "profile3_settings", .mode = 0440 }, 539cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 540cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile3_settings 541cb7cf3daSStefan Achatz }; 542cb7cf3daSStefan Achatz 543cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile4_settings_attr = { 544cb7cf3daSStefan Achatz .attr = { .name = "profile4_settings", .mode = 0440 }, 545cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 546cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile4_settings 547cb7cf3daSStefan Achatz }; 548cb7cf3daSStefan Achatz 549cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile5_settings_attr = { 550cb7cf3daSStefan Achatz .attr = { .name = "profile5_settings", .mode = 0440 }, 551cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_settings), 552cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile5_settings 553cb7cf3daSStefan Achatz }; 554cb7cf3daSStefan Achatz 555cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile_buttons_attr = { 556cb7cf3daSStefan Achatz .attr = { .name = "profile_buttons", .mode = 0220 }, 557cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 558cb7cf3daSStefan Achatz .write = pyra_sysfs_write_profile_buttons 559cb7cf3daSStefan Achatz }; 560cb7cf3daSStefan Achatz 561cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile1_buttons_attr = { 562cb7cf3daSStefan Achatz .attr = { .name = "profile1_buttons", .mode = 0440 }, 563cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 564cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile1_buttons 565cb7cf3daSStefan Achatz }; 566cb7cf3daSStefan Achatz 567cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile2_buttons_attr = { 568cb7cf3daSStefan Achatz .attr = { .name = "profile2_buttons", .mode = 0440 }, 569cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 570cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile2_buttons 571cb7cf3daSStefan Achatz }; 572cb7cf3daSStefan Achatz 573cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile3_buttons_attr = { 574cb7cf3daSStefan Achatz .attr = { .name = "profile3_buttons", .mode = 0440 }, 575cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 576cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile3_buttons 577cb7cf3daSStefan Achatz }; 578cb7cf3daSStefan Achatz 579cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile4_buttons_attr = { 580cb7cf3daSStefan Achatz .attr = { .name = "profile4_buttons", .mode = 0440 }, 581cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 582cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile4_buttons 583cb7cf3daSStefan Achatz }; 584cb7cf3daSStefan Achatz 585cb7cf3daSStefan Achatz static struct bin_attribute pyra_profile5_buttons_attr = { 586cb7cf3daSStefan Achatz .attr = { .name = "profile5_buttons", .mode = 0440 }, 587cb7cf3daSStefan Achatz .size = sizeof(struct pyra_profile_buttons), 588cb7cf3daSStefan Achatz .read = pyra_sysfs_read_profile5_buttons 589cb7cf3daSStefan Achatz }; 590cb7cf3daSStefan Achatz 591cb7cf3daSStefan Achatz static struct bin_attribute pyra_settings_attr = { 592cb7cf3daSStefan Achatz .attr = { .name = "settings", .mode = 0660 }, 593cb7cf3daSStefan Achatz .size = sizeof(struct pyra_settings), 594cb7cf3daSStefan Achatz .read = pyra_sysfs_read_settings, 595cb7cf3daSStefan Achatz .write = pyra_sysfs_write_settings 596cb7cf3daSStefan Achatz }; 597cb7cf3daSStefan Achatz 598cb7cf3daSStefan Achatz static int pyra_create_sysfs_attributes(struct usb_interface *intf) 599cb7cf3daSStefan Achatz { 600cb7cf3daSStefan Achatz int retval; 601cb7cf3daSStefan Achatz 602cb7cf3daSStefan Achatz retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group); 603cb7cf3daSStefan Achatz if (retval) 604cb7cf3daSStefan Achatz goto exit_1; 605cb7cf3daSStefan Achatz 606cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 607cb7cf3daSStefan Achatz &pyra_profile_settings_attr); 608cb7cf3daSStefan Achatz if (retval) 609cb7cf3daSStefan Achatz goto exit_2; 610cb7cf3daSStefan Achatz 611cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 612cb7cf3daSStefan Achatz &pyra_profile1_settings_attr); 613cb7cf3daSStefan Achatz if (retval) 614cb7cf3daSStefan Achatz goto exit_3; 615cb7cf3daSStefan Achatz 616cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 617cb7cf3daSStefan Achatz &pyra_profile2_settings_attr); 618cb7cf3daSStefan Achatz if (retval) 619cb7cf3daSStefan Achatz goto exit_4; 620cb7cf3daSStefan Achatz 621cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 622cb7cf3daSStefan Achatz &pyra_profile3_settings_attr); 623cb7cf3daSStefan Achatz if (retval) 624cb7cf3daSStefan Achatz goto exit_5; 625cb7cf3daSStefan Achatz 626cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 627cb7cf3daSStefan Achatz &pyra_profile4_settings_attr); 628cb7cf3daSStefan Achatz if (retval) 629cb7cf3daSStefan Achatz goto exit_6; 630cb7cf3daSStefan Achatz 631cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 632cb7cf3daSStefan Achatz &pyra_profile5_settings_attr); 633cb7cf3daSStefan Achatz if (retval) 634cb7cf3daSStefan Achatz goto exit_7; 635cb7cf3daSStefan Achatz 636cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 637cb7cf3daSStefan Achatz &pyra_profile_buttons_attr); 638cb7cf3daSStefan Achatz if (retval) 639cb7cf3daSStefan Achatz goto exit_8; 640cb7cf3daSStefan Achatz 641cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 642cb7cf3daSStefan Achatz &pyra_profile1_buttons_attr); 643cb7cf3daSStefan Achatz if (retval) 644cb7cf3daSStefan Achatz goto exit_9; 645cb7cf3daSStefan Achatz 646cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 647cb7cf3daSStefan Achatz &pyra_profile2_buttons_attr); 648cb7cf3daSStefan Achatz if (retval) 649cb7cf3daSStefan Achatz goto exit_10; 650cb7cf3daSStefan Achatz 651cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 652cb7cf3daSStefan Achatz &pyra_profile3_buttons_attr); 653cb7cf3daSStefan Achatz if (retval) 654cb7cf3daSStefan Achatz goto exit_11; 655cb7cf3daSStefan Achatz 656cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 657cb7cf3daSStefan Achatz &pyra_profile4_buttons_attr); 658cb7cf3daSStefan Achatz if (retval) 659cb7cf3daSStefan Achatz goto exit_12; 660cb7cf3daSStefan Achatz 661cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 662cb7cf3daSStefan Achatz &pyra_profile5_buttons_attr); 663cb7cf3daSStefan Achatz if (retval) 664cb7cf3daSStefan Achatz goto exit_13; 665cb7cf3daSStefan Achatz 666cb7cf3daSStefan Achatz retval = sysfs_create_bin_file(&intf->dev.kobj, 667cb7cf3daSStefan Achatz &pyra_settings_attr); 668cb7cf3daSStefan Achatz if (retval) 669cb7cf3daSStefan Achatz goto exit_14; 670cb7cf3daSStefan Achatz 671cb7cf3daSStefan Achatz return 0; 672cb7cf3daSStefan Achatz 673cb7cf3daSStefan Achatz exit_14: 674cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); 675cb7cf3daSStefan Achatz exit_13: 676cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); 677cb7cf3daSStefan Achatz exit_12: 678cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); 679cb7cf3daSStefan Achatz exit_11: 680cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); 681cb7cf3daSStefan Achatz exit_10: 682cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); 683cb7cf3daSStefan Achatz exit_9: 684cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); 685cb7cf3daSStefan Achatz exit_8: 686cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); 687cb7cf3daSStefan Achatz exit_7: 688cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); 689cb7cf3daSStefan Achatz exit_6: 690cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); 691cb7cf3daSStefan Achatz exit_5: 692cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); 693cb7cf3daSStefan Achatz exit_4: 694cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); 695cb7cf3daSStefan Achatz exit_3: 696cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); 697cb7cf3daSStefan Achatz exit_2: 698cb7cf3daSStefan Achatz sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); 699cb7cf3daSStefan Achatz exit_1: 700cb7cf3daSStefan Achatz return retval; 701cb7cf3daSStefan Achatz } 702cb7cf3daSStefan Achatz 703cb7cf3daSStefan Achatz static void pyra_remove_sysfs_attributes(struct usb_interface *intf) 704cb7cf3daSStefan Achatz { 705cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr); 706cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr); 707cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr); 708cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr); 709cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr); 710cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr); 711cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr); 712cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr); 713cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr); 714cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr); 715cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr); 716cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr); 717cb7cf3daSStefan Achatz sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr); 718cb7cf3daSStefan Achatz sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group); 719cb7cf3daSStefan Achatz } 720cb7cf3daSStefan Achatz 721cb7cf3daSStefan Achatz static int pyra_init_pyra_device_struct(struct usb_device *usb_dev, 722cb7cf3daSStefan Achatz struct pyra_device *pyra) 723cb7cf3daSStefan Achatz { 724cb7cf3daSStefan Achatz struct pyra_info *info; 725cb7cf3daSStefan Achatz int retval, i; 726cb7cf3daSStefan Achatz 727cb7cf3daSStefan Achatz mutex_init(&pyra->pyra_lock); 728cb7cf3daSStefan Achatz 729cb7cf3daSStefan Achatz info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL); 730cb7cf3daSStefan Achatz if (!info) 731cb7cf3daSStefan Achatz return -ENOMEM; 732cb7cf3daSStefan Achatz retval = pyra_get_info(usb_dev, info); 733cb7cf3daSStefan Achatz if (retval) { 734cb7cf3daSStefan Achatz kfree(info); 735cb7cf3daSStefan Achatz return retval; 736cb7cf3daSStefan Achatz } 737cb7cf3daSStefan Achatz pyra->firmware_version = info->firmware_version; 738cb7cf3daSStefan Achatz kfree(info); 739cb7cf3daSStefan Achatz 740cb7cf3daSStefan Achatz retval = pyra_get_settings(usb_dev, &pyra->settings); 741cb7cf3daSStefan Achatz if (retval) 742cb7cf3daSStefan Achatz return retval; 743cb7cf3daSStefan Achatz 744cb7cf3daSStefan Achatz for (i = 0; i < 5; ++i) { 745cb7cf3daSStefan Achatz retval = pyra_get_profile_settings(usb_dev, 746cb7cf3daSStefan Achatz &pyra->profile_settings[i], i); 747cb7cf3daSStefan Achatz if (retval) 748cb7cf3daSStefan Achatz return retval; 749cb7cf3daSStefan Achatz 750cb7cf3daSStefan Achatz retval = pyra_get_profile_buttons(usb_dev, 751cb7cf3daSStefan Achatz &pyra->profile_buttons[i], i); 752cb7cf3daSStefan Achatz if (retval) 753cb7cf3daSStefan Achatz return retval; 754cb7cf3daSStefan Achatz } 755cb7cf3daSStefan Achatz 756cb7cf3daSStefan Achatz profile_activated(pyra, pyra->settings.startup_profile); 757cb7cf3daSStefan Achatz 758cb7cf3daSStefan Achatz return 0; 759cb7cf3daSStefan Achatz } 760cb7cf3daSStefan Achatz 761cb7cf3daSStefan Achatz static int pyra_init_specials(struct hid_device *hdev) 762cb7cf3daSStefan Achatz { 763cb7cf3daSStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 764cb7cf3daSStefan Achatz struct usb_device *usb_dev = interface_to_usbdev(intf); 765cb7cf3daSStefan Achatz struct pyra_device *pyra; 766cb7cf3daSStefan Achatz int retval; 767cb7cf3daSStefan Achatz 768cb7cf3daSStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 769cb7cf3daSStefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 770cb7cf3daSStefan Achatz 771cb7cf3daSStefan Achatz pyra = kzalloc(sizeof(*pyra), GFP_KERNEL); 772cb7cf3daSStefan Achatz if (!pyra) { 773cb7cf3daSStefan Achatz dev_err(&hdev->dev, "can't alloc device descriptor\n"); 774cb7cf3daSStefan Achatz return -ENOMEM; 775cb7cf3daSStefan Achatz } 776cb7cf3daSStefan Achatz hid_set_drvdata(hdev, pyra); 777cb7cf3daSStefan Achatz 778cb7cf3daSStefan Achatz retval = pyra_init_pyra_device_struct(usb_dev, pyra); 779cb7cf3daSStefan Achatz if (retval) { 780cb7cf3daSStefan Achatz dev_err(&hdev->dev, 781cb7cf3daSStefan Achatz "couldn't init struct pyra_device\n"); 782cb7cf3daSStefan Achatz goto exit_free; 783cb7cf3daSStefan Achatz } 784cb7cf3daSStefan Achatz 785cb7cf3daSStefan Achatz retval = roccat_connect(hdev); 786cb7cf3daSStefan Achatz if (retval < 0) { 787cb7cf3daSStefan Achatz dev_err(&hdev->dev, "couldn't init char dev\n"); 788cb7cf3daSStefan Achatz } else { 789cb7cf3daSStefan Achatz pyra->chrdev_minor = retval; 790cb7cf3daSStefan Achatz pyra->roccat_claimed = 1; 791cb7cf3daSStefan Achatz } 792cb7cf3daSStefan Achatz 793cb7cf3daSStefan Achatz retval = pyra_create_sysfs_attributes(intf); 794cb7cf3daSStefan Achatz if (retval) { 795cb7cf3daSStefan Achatz dev_err(&hdev->dev, "cannot create sysfs files\n"); 796cb7cf3daSStefan Achatz goto exit_free; 797cb7cf3daSStefan Achatz } 798cb7cf3daSStefan Achatz } else { 799cb7cf3daSStefan Achatz hid_set_drvdata(hdev, NULL); 800cb7cf3daSStefan Achatz } 801cb7cf3daSStefan Achatz 802cb7cf3daSStefan Achatz return 0; 803cb7cf3daSStefan Achatz exit_free: 804cb7cf3daSStefan Achatz kfree(pyra); 805cb7cf3daSStefan Achatz return retval; 806cb7cf3daSStefan Achatz } 807cb7cf3daSStefan Achatz 808cb7cf3daSStefan Achatz static void pyra_remove_specials(struct hid_device *hdev) 809cb7cf3daSStefan Achatz { 810cb7cf3daSStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 811cb7cf3daSStefan Achatz struct pyra_device *pyra; 812cb7cf3daSStefan Achatz 813cb7cf3daSStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 814cb7cf3daSStefan Achatz == USB_INTERFACE_PROTOCOL_MOUSE) { 815cb7cf3daSStefan Achatz pyra_remove_sysfs_attributes(intf); 816cb7cf3daSStefan Achatz pyra = hid_get_drvdata(hdev); 817cb7cf3daSStefan Achatz if (pyra->roccat_claimed) 818cb7cf3daSStefan Achatz roccat_disconnect(pyra->chrdev_minor); 819cb7cf3daSStefan Achatz kfree(hid_get_drvdata(hdev)); 820cb7cf3daSStefan Achatz } 821cb7cf3daSStefan Achatz } 822cb7cf3daSStefan Achatz 823cb7cf3daSStefan Achatz static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id) 824cb7cf3daSStefan Achatz { 825cb7cf3daSStefan Achatz int retval; 826cb7cf3daSStefan Achatz 827cb7cf3daSStefan Achatz retval = hid_parse(hdev); 828cb7cf3daSStefan Achatz if (retval) { 829cb7cf3daSStefan Achatz dev_err(&hdev->dev, "parse failed\n"); 830cb7cf3daSStefan Achatz goto exit; 831cb7cf3daSStefan Achatz } 832cb7cf3daSStefan Achatz 833cb7cf3daSStefan Achatz retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 834cb7cf3daSStefan Achatz if (retval) { 835cb7cf3daSStefan Achatz dev_err(&hdev->dev, "hw start failed\n"); 836cb7cf3daSStefan Achatz goto exit; 837cb7cf3daSStefan Achatz } 838cb7cf3daSStefan Achatz 839cb7cf3daSStefan Achatz retval = pyra_init_specials(hdev); 840cb7cf3daSStefan Achatz if (retval) { 841cb7cf3daSStefan Achatz dev_err(&hdev->dev, "couldn't install mouse\n"); 842cb7cf3daSStefan Achatz goto exit_stop; 843cb7cf3daSStefan Achatz } 844cb7cf3daSStefan Achatz return 0; 845cb7cf3daSStefan Achatz 846cb7cf3daSStefan Achatz exit_stop: 847cb7cf3daSStefan Achatz hid_hw_stop(hdev); 848cb7cf3daSStefan Achatz exit: 849cb7cf3daSStefan Achatz return retval; 850cb7cf3daSStefan Achatz } 851cb7cf3daSStefan Achatz 852cb7cf3daSStefan Achatz static void pyra_remove(struct hid_device *hdev) 853cb7cf3daSStefan Achatz { 854cb7cf3daSStefan Achatz pyra_remove_specials(hdev); 855cb7cf3daSStefan Achatz hid_hw_stop(hdev); 856cb7cf3daSStefan Achatz } 857cb7cf3daSStefan Achatz 858cb7cf3daSStefan Achatz static void pyra_keep_values_up_to_date(struct pyra_device *pyra, 859cb7cf3daSStefan Achatz u8 const *data) 860cb7cf3daSStefan Achatz { 861cb7cf3daSStefan Achatz struct pyra_mouse_event_button const *button_event; 862cb7cf3daSStefan Achatz 863cb7cf3daSStefan Achatz switch (data[0]) { 864cb7cf3daSStefan Achatz case PYRA_MOUSE_REPORT_NUMBER_BUTTON: 865cb7cf3daSStefan Achatz button_event = (struct pyra_mouse_event_button const *)data; 866cb7cf3daSStefan Achatz switch (button_event->type) { 867cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: 868cb7cf3daSStefan Achatz profile_activated(pyra, button_event->data1 - 1); 869cb7cf3daSStefan Achatz break; 870cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: 871cb7cf3daSStefan Achatz pyra->actual_cpi = button_event->data1; 872cb7cf3daSStefan Achatz break; 873cb7cf3daSStefan Achatz } 874cb7cf3daSStefan Achatz break; 875cb7cf3daSStefan Achatz } 876cb7cf3daSStefan Achatz } 877cb7cf3daSStefan Achatz 878cb7cf3daSStefan Achatz static void pyra_report_to_chrdev(struct pyra_device const *pyra, 879cb7cf3daSStefan Achatz u8 const *data) 880cb7cf3daSStefan Achatz { 881cb7cf3daSStefan Achatz struct pyra_roccat_report roccat_report; 882cb7cf3daSStefan Achatz struct pyra_mouse_event_button const *button_event; 883cb7cf3daSStefan Achatz 884cb7cf3daSStefan Achatz if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON) 885cb7cf3daSStefan Achatz return; 886cb7cf3daSStefan Achatz 887cb7cf3daSStefan Achatz button_event = (struct pyra_mouse_event_button const *)data; 888cb7cf3daSStefan Achatz 889cb7cf3daSStefan Achatz switch (button_event->type) { 890cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2: 891cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI: 892cb7cf3daSStefan Achatz roccat_report.type = button_event->type; 893cb7cf3daSStefan Achatz roccat_report.value = button_event->data1; 894cb7cf3daSStefan Achatz roccat_report.key = 0; 895cb7cf3daSStefan Achatz roccat_report_event(pyra->chrdev_minor, 896cb7cf3daSStefan Achatz (uint8_t const *)&roccat_report, 897cb7cf3daSStefan Achatz sizeof(struct pyra_roccat_report)); 898cb7cf3daSStefan Achatz break; 899cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO: 900cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT: 901cb7cf3daSStefan Achatz case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH: 902cb7cf3daSStefan Achatz if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) { 903cb7cf3daSStefan Achatz roccat_report.type = button_event->type; 904cb7cf3daSStefan Achatz roccat_report.key = button_event->data1; 905d2b570a5SStefan Achatz /* 906d2b570a5SStefan Achatz * pyra reports profile numbers with range 1-5. 907d2b570a5SStefan Achatz * Keeping this behaviour. 908d2b570a5SStefan Achatz */ 909d2b570a5SStefan Achatz roccat_report.value = pyra->actual_profile + 1; 910cb7cf3daSStefan Achatz roccat_report_event(pyra->chrdev_minor, 911cb7cf3daSStefan Achatz (uint8_t const *)&roccat_report, 912cb7cf3daSStefan Achatz sizeof(struct pyra_roccat_report)); 913cb7cf3daSStefan Achatz } 914cb7cf3daSStefan Achatz break; 915cb7cf3daSStefan Achatz } 916cb7cf3daSStefan Achatz } 917cb7cf3daSStefan Achatz 918cb7cf3daSStefan Achatz static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, 919cb7cf3daSStefan Achatz u8 *data, int size) 920cb7cf3daSStefan Achatz { 921cb7cf3daSStefan Achatz struct usb_interface *intf = to_usb_interface(hdev->dev.parent); 922cb7cf3daSStefan Achatz struct pyra_device *pyra = hid_get_drvdata(hdev); 923cb7cf3daSStefan Achatz 924cb7cf3daSStefan Achatz if (intf->cur_altsetting->desc.bInterfaceProtocol 925cb7cf3daSStefan Achatz != USB_INTERFACE_PROTOCOL_MOUSE) 926cb7cf3daSStefan Achatz return 0; 927cb7cf3daSStefan Achatz 928cb7cf3daSStefan Achatz pyra_keep_values_up_to_date(pyra, data); 929cb7cf3daSStefan Achatz 930cb7cf3daSStefan Achatz if (pyra->roccat_claimed) 931cb7cf3daSStefan Achatz pyra_report_to_chrdev(pyra, data); 932cb7cf3daSStefan Achatz 933cb7cf3daSStefan Achatz return 0; 934cb7cf3daSStefan Achatz } 935cb7cf3daSStefan Achatz 936cb7cf3daSStefan Achatz static const struct hid_device_id pyra_devices[] = { 937cb7cf3daSStefan Achatz { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, 938cb7cf3daSStefan Achatz USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, 939cb7cf3daSStefan Achatz /* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */ 940cb7cf3daSStefan Achatz { } 941cb7cf3daSStefan Achatz }; 942cb7cf3daSStefan Achatz 943cb7cf3daSStefan Achatz MODULE_DEVICE_TABLE(hid, pyra_devices); 944cb7cf3daSStefan Achatz 945cb7cf3daSStefan Achatz static struct hid_driver pyra_driver = { 946cb7cf3daSStefan Achatz .name = "pyra", 947cb7cf3daSStefan Achatz .id_table = pyra_devices, 948cb7cf3daSStefan Achatz .probe = pyra_probe, 949cb7cf3daSStefan Achatz .remove = pyra_remove, 950cb7cf3daSStefan Achatz .raw_event = pyra_raw_event 951cb7cf3daSStefan Achatz }; 952cb7cf3daSStefan Achatz 953cb7cf3daSStefan Achatz static int __init pyra_init(void) 954cb7cf3daSStefan Achatz { 955cb7cf3daSStefan Achatz return hid_register_driver(&pyra_driver); 956cb7cf3daSStefan Achatz } 957cb7cf3daSStefan Achatz 958cb7cf3daSStefan Achatz static void __exit pyra_exit(void) 959cb7cf3daSStefan Achatz { 960cb7cf3daSStefan Achatz hid_unregister_driver(&pyra_driver); 961cb7cf3daSStefan Achatz } 962cb7cf3daSStefan Achatz 963cb7cf3daSStefan Achatz module_init(pyra_init); 964cb7cf3daSStefan Achatz module_exit(pyra_exit); 965cb7cf3daSStefan Achatz 966cb7cf3daSStefan Achatz MODULE_AUTHOR("Stefan Achatz"); 967cb7cf3daSStefan Achatz MODULE_DESCRIPTION("USB Roccat Pyra driver"); 968cb7cf3daSStefan Achatz MODULE_LICENSE("GPL v2"); 969