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