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 19 static inline uint16_t roccat_common2_feature_report(uint8_t report_id) 20 { 21 return 0x300 | report_id; 22 } 23 24 int 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 } 44 EXPORT_SYMBOL_GPL(roccat_common2_receive); 45 46 int 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 } 65 EXPORT_SYMBOL_GPL(roccat_common2_send); 66 67 enum 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 75 static 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 110 int 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 } 123 EXPORT_SYMBOL_GPL(roccat_common2_send_with_status); 124 125 int 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 } 131 EXPORT_SYMBOL_GPL(roccat_common2_device_init_struct); 132 133 ssize_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 = kobj_to_dev(kobj)->parent->parent; 138 struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev)); 139 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 140 int retval; 141 142 if (off >= real_size) 143 return 0; 144 145 if (off != 0 || count != real_size) 146 return -EINVAL; 147 148 mutex_lock(&roccat_dev->lock); 149 retval = roccat_common2_receive(usb_dev, command, buf, real_size); 150 mutex_unlock(&roccat_dev->lock); 151 152 return retval ? retval : real_size; 153 } 154 EXPORT_SYMBOL_GPL(roccat_common2_sysfs_read); 155 156 ssize_t roccat_common2_sysfs_write(struct file *fp, struct kobject *kobj, 157 void const *buf, loff_t off, size_t count, 158 size_t real_size, uint command) 159 { 160 struct device *dev = kobj_to_dev(kobj)->parent->parent; 161 struct roccat_common2_device *roccat_dev = hid_get_drvdata(dev_get_drvdata(dev)); 162 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 163 int retval; 164 165 if (off != 0 || count != real_size) 166 return -EINVAL; 167 168 mutex_lock(&roccat_dev->lock); 169 retval = roccat_common2_send_with_status(usb_dev, command, buf, real_size); 170 mutex_unlock(&roccat_dev->lock); 171 172 return retval ? retval : real_size; 173 } 174 EXPORT_SYMBOL_GPL(roccat_common2_sysfs_write); 175 176 MODULE_AUTHOR("Stefan Achatz"); 177 MODULE_DESCRIPTION("USB Roccat common driver"); 178 MODULE_LICENSE("GPL v2"); 179