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
This commit is contained in:
Vladimir Kondratyev
2025-08-18 00:00:45 +03:00
parent 149b9f26d0
commit 37e3b66466
4 changed files with 56 additions and 36 deletions
+4
View File
@@ -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;
}
+48
View File
@@ -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);
}
+1 -36
View File
@@ -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
+3
View File
@@ -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,