git: 82e38b012cc8 - main - usbhid(4): Implement USB_REQUEST command in hid_ioctl method

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Wed, 02 Mar 2022 23:36:38 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=82e38b012cc832651ba195f5443e7f9fb64ce5d3

commit 82e38b012cc832651ba195f5443e7f9fb64ce5d3
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2022-03-02 23:35:23 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2022-03-02 23:35:23 +0000

    usbhid(4): Implement USB_REQUEST command in hid_ioctl method
    
    This command is intended to be compatible with USB_REQUEST ioctl.
    It is required to perform arbitrary control endpoint requests by device
    drivers which can switch between HID and native non-HID modes.
    
    MFC after:      2 month
---
 sys/dev/usb/input/usbhid.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/sys/dev/usb/input/usbhid.c b/sys/dev/usb/input/usbhid.c
index c6f2a1f24303..ed76f6291a11 100644
--- a/sys/dev/usb/input/usbhid.c
+++ b/sys/dev/usb/input/usbhid.c
@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbhid.h>
 #include <dev/usb/usb_core.h>
+#include <dev/usb/usb_ioctl.h>
 
 #define	USB_DEBUG_VAR usbhid_debug
 #include <dev/usb/usb_debug.h>
@@ -677,6 +678,35 @@ usbhid_set_protocol(device_t dev, uint16_t protocol)
 	return (usbhid_sync_xfer(sc, USBHID_CTRL_DT, &req, NULL));
 }
 
+static int
+usbhid_ioctl(device_t dev, unsigned long cmd, uintptr_t data)
+{
+	struct usbhid_softc* sc = device_get_softc(dev);
+	struct usb_ctl_request *ucr;
+	union usbhid_device_request req;
+	int error;
+
+	switch (cmd) {
+	case USB_REQUEST:
+		ucr = (struct usb_ctl_request *)data;
+		req.ctrl = ucr->ucr_request;
+		error = usbhid_xfer_check_len(
+		    sc, USBHID_CTRL_DT, UGETW(req.ctrl.wLength));
+		if (error)
+			break;
+
+		error = usbhid_sync_xfer(
+		    sc, USBHID_CTRL_DT, &req, ucr->ucr_data);
+		if (error == 0)
+			ucr->ucr_actlen = UGETW(req.ctrl.wLength);
+		break;
+	default:
+		error = EINVAL;
+	}
+
+	return (error);
+}
+
 static void
 usbhid_init_device_info(struct usb_attach_arg *uaa, struct hid_device_info *hw)
 {
@@ -848,6 +878,7 @@ static device_method_t usbhid_methods[] = {
 	DEVMETHOD(hid_set_report,	usbhid_set_report),
 	DEVMETHOD(hid_set_idle,		usbhid_set_idle),
 	DEVMETHOD(hid_set_protocol,	usbhid_set_protocol),
+	DEVMETHOD(hid_ioctl,		usbhid_ioctl),
 
 	DEVMETHOD_END
 };