176 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Roccat common functions for device specific drivers4 *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");176