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