git: 37e3b6646692 - main - usbhid(4): Implement USB_GET_DEVICEINFO ioctl

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Sun, 17 Aug 2025 21:02:30 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=37e3b664669288dc1775a6f8fb0d84b962fc9c5b

commit 37e3b664669288dc1775a6f8fb0d84b962fc9c5b
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2025-08-17 21:00:45 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2025-08-17 21:00:45 +0000

    usbhid(4): Implement USB_GET_DEVICEINFO ioctl
    
    With factoring out of supporting code from ugen(4) driver.
    The ioctl is used in FIDO/U2F security key drivers to get
    USB product and manufacturer strings.
    
    PR:             264843
    Reviewed by:    emaste
    Differential Revision:  https://reviews.freebsd.org/D51609
---
 sys/dev/usb/input/usbhid.c |  4 ++++
 sys/dev/usb/usb_device.c   | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/usb/usb_generic.c  | 37 +----------------------------------
 sys/dev/usb/usbdi.h        |  3 +++
 4 files changed, 56 insertions(+), 36 deletions(-)

diff --git a/sys/dev/usb/input/usbhid.c b/sys/dev/usb/input/usbhid.c
index 255e639621fe..cba3f34053e5 100644
--- a/sys/dev/usb/input/usbhid.c
+++ b/sys/dev/usb/input/usbhid.c
@@ -707,6 +707,10 @@ usbhid_ioctl(device_t dev, device_t child __unused, unsigned long cmd,
 		if (error == 0)
 			ucr->ucr_actlen = UGETW(req.ctrl.wLength);
 		break;
+	case USB_GET_DEVICEINFO:
+		error = usbd_fill_deviceinfo(sc->sc_udev,
+		    (struct usb_device_info *)data);
+		break;
 	default:
 		error = EINVAL;
 	}
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index 60c2d6745b3f..f0989972f49f 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -3111,3 +3111,51 @@ usbd_get_endpoint_mode(struct usb_device *udev, struct usb_endpoint *ep)
 {
 	return (ep->ep_mode);
 }
+
+/*------------------------------------------------------------------------*
+ *	usbd_fill_deviceinfo
+ *
+ * This function dumps information about an USB device to the
+ * structure pointed to by the "di" argument.
+ *
+ * Returns:
+ *    0: Success
+ * Else: Failure
+ *------------------------------------------------------------------------*/
+int
+usbd_fill_deviceinfo(struct usb_device *udev, struct usb_device_info *di)
+{
+	struct usb_device *hub;
+
+	bzero(di, sizeof(di[0]));
+
+	di->udi_bus = device_get_unit(udev->bus->bdev);
+	di->udi_addr = udev->address;
+	di->udi_index = udev->device_index;
+	strlcpy(di->udi_serial, usb_get_serial(udev), sizeof(di->udi_serial));
+	strlcpy(di->udi_vendor, usb_get_manufacturer(udev), sizeof(di->udi_vendor));
+	strlcpy(di->udi_product, usb_get_product(udev), sizeof(di->udi_product));
+	usb_printbcd(di->udi_release, sizeof(di->udi_release),
+	    UGETW(udev->ddesc.bcdDevice));
+	di->udi_vendorNo = UGETW(udev->ddesc.idVendor);
+	di->udi_productNo = UGETW(udev->ddesc.idProduct);
+	di->udi_releaseNo = UGETW(udev->ddesc.bcdDevice);
+	di->udi_class = udev->ddesc.bDeviceClass;
+	di->udi_subclass = udev->ddesc.bDeviceSubClass;
+	di->udi_protocol = udev->ddesc.bDeviceProtocol;
+	di->udi_config_no = udev->curr_config_no;
+	di->udi_config_index = udev->curr_config_index;
+	di->udi_power = udev->flags.self_powered ? 0 : udev->power;
+	di->udi_speed = udev->speed;
+	di->udi_mode = udev->flags.usb_mode;
+	di->udi_power_mode = udev->power_mode;
+	di->udi_suspended = udev->flags.peer_suspended;
+
+	hub = udev->parent_hub;
+	if (hub) {
+		di->udi_hubaddr = hub->address;
+		di->udi_hubindex = hub->device_index;
+		di->udi_hubport = udev->port_no;
+	}
+	return (0);
+}
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index c0af27d77e5d..ccb0b2184ec4 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -831,42 +831,7 @@ ugen_get_iface_driver(struct usb_fifo *f, struct usb_gen_descriptor *ugd)
 int
 ugen_fill_deviceinfo(struct usb_fifo *f, struct usb_device_info *di)
 {
-	struct usb_device *udev;
-	struct usb_device *hub;
-
-	udev = f->udev;
-
-	bzero(di, sizeof(di[0]));
-
-	di->udi_bus = device_get_unit(udev->bus->bdev);
-	di->udi_addr = udev->address;
-	di->udi_index = udev->device_index;
-	strlcpy(di->udi_serial, usb_get_serial(udev), sizeof(di->udi_serial));
-	strlcpy(di->udi_vendor, usb_get_manufacturer(udev), sizeof(di->udi_vendor));
-	strlcpy(di->udi_product, usb_get_product(udev), sizeof(di->udi_product));
-	usb_printbcd(di->udi_release, sizeof(di->udi_release),
-	    UGETW(udev->ddesc.bcdDevice));
-	di->udi_vendorNo = UGETW(udev->ddesc.idVendor);
-	di->udi_productNo = UGETW(udev->ddesc.idProduct);
-	di->udi_releaseNo = UGETW(udev->ddesc.bcdDevice);
-	di->udi_class = udev->ddesc.bDeviceClass;
-	di->udi_subclass = udev->ddesc.bDeviceSubClass;
-	di->udi_protocol = udev->ddesc.bDeviceProtocol;
-	di->udi_config_no = udev->curr_config_no;
-	di->udi_config_index = udev->curr_config_index;
-	di->udi_power = udev->flags.self_powered ? 0 : udev->power;
-	di->udi_speed = udev->speed;
-	di->udi_mode = udev->flags.usb_mode;
-	di->udi_power_mode = udev->power_mode;
-	di->udi_suspended = udev->flags.peer_suspended;
-
-	hub = udev->parent_hub;
-	if (hub) {
-		di->udi_hubaddr = hub->address;
-		di->udi_hubindex = hub->device_index;
-		di->udi_hubport = udev->port_no;
-	}
-	return (0);
+	return (usbd_fill_deviceinfo(f->udev, di));
 }
 
 int
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 08d130aa2868..0826d9f078c4 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -38,6 +38,7 @@ struct usb_process;
 struct usb_proc_msg;
 struct usb_mbuf;
 struct usb_fs_privdata;
+struct usb_device_info;
 struct mbuf;
 
 typedef enum {	/* keep in sync with usb_errstr_table */
@@ -587,6 +588,8 @@ usb_error_t	usbd_set_endpoint_mode(struct usb_device *udev,
 			struct usb_endpoint *ep, uint8_t ep_mode);
 uint8_t		usbd_get_endpoint_mode(struct usb_device *udev,
 			struct usb_endpoint *ep);
+int		usbd_fill_deviceinfo(struct usb_device *udev,
+			struct usb_device_info *di);
 
 const struct usb_device_id *usbd_lookup_id_by_info(
 	    const struct usb_device_id *id, usb_size_t sizeof_id,