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_OVERLOAD = 0, 69 ROCCAT_COMMON_CONTROL_STATUS_OK = 1, 70 ROCCAT_COMMON_CONTROL_STATUS_INVALID = 2, 71 ROCCAT_COMMON_CONTROL_STATUS_WAIT = 3, 72 }; 73 74 static int roccat_common2_receive_control_status(struct usb_device *usb_dev) 75 { 76 int retval; 77 struct roccat_common2_control control; 78 79 do { 80 msleep(50); 81 retval = roccat_common2_receive(usb_dev, 82 ROCCAT_COMMON_COMMAND_CONTROL, 83 &control, sizeof(struct roccat_common2_control)); 84 85 if (retval) 86 return retval; 87 88 switch (control.value) { 89 case ROCCAT_COMMON_CONTROL_STATUS_OK: 90 return 0; 91 case ROCCAT_COMMON_CONTROL_STATUS_WAIT: 92 msleep(500); 93 continue; 94 case ROCCAT_COMMON_CONTROL_STATUS_INVALID: 95 96 case ROCCAT_COMMON_CONTROL_STATUS_OVERLOAD: 97 /* seems to be critical - replug necessary */ 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 MODULE_AUTHOR("Stefan Achatz"); 126 MODULE_DESCRIPTION("USB Roccat common driver"); 127 MODULE_LICENSE("GPL v2"); 128