brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 4465ef9 Raw
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