1/* 2 * Roccat common functions for device specific drivers 3 * 4 * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net> 5 */ 6 7/* 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the Free 10 * Software Foundation; either version 2 of the License, or (at your option) 11 * any later version. 12 */ 13 14#include <linux/hid.h> 15#include <linux/slab.h> 16#include <linux/module.h> 17#include "hid-roccat-common.h" 18 19static inline uint16_t roccat_common2_feature_report(uint8_t report_id) 20{ 21 return 0x300 | report_id; 22} 23 24int roccat_common2_receive(struct usb_device *usb_dev, uint report_id, 25 void *data, uint size) 26{ 27 char *buf; 28 int len; 29 30 buf = kmalloc(size, GFP_KERNEL); 31 if (buf == NULL) 32 return -ENOMEM; 33 34 len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 35 HID_REQ_GET_REPORT, 36 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, 37 roccat_common2_feature_report(report_id), 38 0, buf, size, USB_CTRL_SET_TIMEOUT); 39 40 memcpy(data, buf, size); 41 kfree(buf); 42 return ((len < 0) ? len : ((len != size) ? -EIO : 0)); 43} 44EXPORT_SYMBOL_GPL(roccat_common2_receive); 45 46int roccat_common2_send(struct usb_device *usb_dev, uint report_id, 47 void const *data, uint size) 48{ 49 char *buf; 50 int len; 51 52 buf = kmemdup(data, size, GFP_KERNEL); 53 if (buf == NULL) 54 return -ENOMEM; 55 56 len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), 57 HID_REQ_SET_REPORT, 58 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, 59 roccat_common2_feature_report(report_id), 60 0, buf, size, USB_CTRL_SET_TIMEOUT); 61 62 kfree(buf); 63 return ((len < 0) ? len : ((len != size) ? -EIO : 0)); 64} 65EXPORT_SYMBOL_GPL(roccat_common2_send); 66 67enum roccat_common2_control_states { 68 ROCCAT_COMMON_CONTROL_STATUS_CRITICAL = 0, 69 ROCCAT_COMMON_CONTROL_STATUS_OK = 1, 70 ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2, 71 ROCCAT_COMMON_CONTROL_STATUS_BUSY = 3, 72 ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW = 4, 73}; 74 75static int roccat_common2_receive_control_status(struct usb_device *usb_dev) 76{ 77 int retval; 78 struct roccat_common2_control control; 79 80 do { 81 msleep(50); 82 retval = roccat_common2_receive(usb_dev, 83 ROCCAT_COMMON_COMMAND_CONTROL, 84 &control, sizeof(struct roccat_common2_control)); 85 86 if (retval) 87 return retval; 88 89 switch (control.value) { 90 case ROCCAT_COMMON_CONTROL_STATUS_OK: 91 return 0; 92 case ROCCAT_COMMON_CONTROL_STATUS_BUSY: 93 msleep(500); 94 continue; 95 case ROCCAT_COMMON_CONTROL_STATUS_INVALID: 96 case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL: 97 case ROCCAT_COMMON_CONTROL_STATUS_CRITICAL_NEW: 98 return -EINVAL; 99 default: 100 dev_err(&usb_dev->dev, 101 "roccat_common2_receive_control_status: " 102 "unknown response value 0x%x\n", 103 control.value); 104 return -EINVAL; 105 } 106 107 } while (1); 108} 109 110int roccat_common2_send_with_status(struct usb_device *usb_dev, 111 uint command, void const *buf, uint size) 112{ 113 int retval; 114 115 retval = roccat_common2_send(usb_dev, command, buf, size); 116 if (retval) 117 return retval; 118 119 msleep(100); 120 121 return roccat_common2_receive_control_status(usb_dev); 122} 123EXPORT_SYMBOL_GPL(roccat_common2_send_with_status); 124 125int roccat_common2_device_init_struct(struct usb_device *usb_dev, 126 struct roccat_common2_device *dev) 127{ 128 mutex_init(&dev->lock); 129 return 0; 130} 131EXPORT_SYMBOL_GPL(roccat_common2_device_init_struct); 132 133ssize_t roccat_common2_sysfs_read(struct file *fp, struct kobject *kobj, 134 char *buf, loff_t off, size_t count, 135 size_t real_size, uint command) 136{ 137 struct device *dev = 138 container_of(kobj, struct device, kobj)->parent->parent; 139 struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev)); 140 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 141 int retval; 142 143 if (off >= real_size) 144 return 0; 145 146 if (off != 0 || count != real_size) 147 return -EINVAL; 148 149 mutex_lock(&roccat_dev->lock); 150 retval = roccat_common2_receive(usb_dev, command, buf, real_size); 151 mutex_unlock(&roccat_dev->lock); 152 153 return retval ? retval : real_size; 154} 155EXPORT_SYMBOL_GPL(roccat_common2_sysfs_read); 156 157ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj, 158 void const *buf, loff_t off, size_t count, 159 size_t real_size, uint command) 160{ 161 struct device *dev = 162 container_of(kobj, struct device, kobj)->parent->parent; 163 struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev)); 164 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 165 int retval; 166 167 if (off != 0 || count != real_size) 168 return -EINVAL; 169 170 mutex_lock(&roccat_dev->lock); 171 retval = roccat_common2_send_with_status(usb_dev, command, buf, real_size); 172 mutex_unlock(&roccat_dev->lock); 173 174 return retval ? retval : real_size; 175} 176EXPORT_SYMBOL_GPL(roccat_common2_sysfs_write); 177 178MODULE_AUTHOR("Stefan Achatz"); 179MODULE_DESCRIPTION("USB Roccat common driver"); 180MODULE_LICENSE("GPL v2"); 181