The branch main has been updated by aokblast:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=964823a18e116e86c05e1d6a6fd80b1bb3274e57

commit 964823a18e116e86c05e1d6a6fd80b1bb3274e57
Author:     ShengYi Hung <[email protected]>
AuthorDate: 2025-07-09 10:49:24 +0000
Commit:     ShengYi Hung <[email protected]>
CommitDate: 2026-06-22 13:36:47 +0000

    libusb: implement libusb_get_max_alt_packet_size
    
    The libusb has a function to calculate the size from given interface,
    alt_setting, endpoint. Implementing it by refactoring the calculating
    function for libusb_get_max_iso_packet_size.
    
    Reviewed by:    adrian
    Sponsored By:   FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D51225
---
 lib/libusb/libusb.3   |   6 ++
 lib/libusb/libusb.h   |   4 +-
 lib/libusb/libusb10.c | 161 +++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 141 insertions(+), 30 deletions(-)

diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
index 7b977103eb59..d801f4c8161a 100644
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -224,6 +224,12 @@ Returns the packet size multiplied by the packet 
multiplier on success,
 LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist and
 LIBUSB_ERROR_OTHERS on other failure.
 .Pp
+.Ft int
+.Fn libusb_get_max_alt_packet_size "libusb_device *dev" "int interface_number" 
"int alternate_setting" "unsigned char endpoint"
+Returns the maximum packet size which can be sent/received on this endpoint,
+LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist, or
+LIBUSB_ERROR_OTHER on other failure.
+.Pp
 .Ft libusb_device *
 .Fn libusb_ref_device "libusb_device *dev"
 Increment the reference counter of the device
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index 00255291ebd5..b6853879412c 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -548,7 +548,9 @@ uint8_t     libusb_get_device_address(libusb_device * dev);
 enum libusb_speed libusb_get_device_speed(libusb_device * dev);
 int    libusb_clear_halt(libusb_device_handle *devh, uint8_t endpoint);
 int    libusb_get_max_packet_size(libusb_device * dev, uint8_t endpoint);
-int    libusb_get_max_iso_packet_size(libusb_device * dev, uint8_t endpoint);
+int    libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint);
+int    libusb_get_max_alt_packet_size(libusb_device *dev, int interface_number,
+    int alternate_setting, unsigned char endpoint);
 libusb_device *libusb_ref_device(libusb_device * dev);
 void   libusb_unref_device(libusb_device * dev);
 int    libusb_wrap_sys_device(libusb_context *ctx, intptr_t sys_dev, 
libusb_device_handle **dev_handle);
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
index c00d8ec8be8b..ab92c219409a 100644
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -536,26 +536,17 @@ libusb_get_device_speed(libusb_device *dev)
        return (LIBUSB_SPEED_UNKNOWN);
 }
 
-int
-libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
+static const libusb_endpoint_descriptor *
+libusb_get_endpoint_from_config(libusb_config_descriptor *pdconf,
+    uint8_t endpoint)
 {
-       struct libusb_config_descriptor *pdconf;
        struct libusb_interface *pinf;
        struct libusb_interface_descriptor *pdinf;
-       struct libusb_endpoint_descriptor *pdend;
+       const struct libusb_endpoint_descriptor *pdend;
        int i;
        int j;
        int k;
-       int ret;
-
-       if (dev == NULL)
-               return (LIBUSB_ERROR_NO_DEVICE);
 
-       ret = libusb_get_active_config_descriptor(dev, &pdconf);
-       if (ret < 0)
-               return (ret);
-
-       ret = LIBUSB_ERROR_NOT_FOUND;
        for (i = 0; i < pdconf->bNumInterfaces; i++) {
                pinf = &pdconf->interface[i];
                for (j = 0; j < pinf->num_altsetting; j++) {
@@ -563,39 +554,151 @@ libusb_get_max_packet_size(libusb_device *dev, uint8_t 
endpoint)
                        for (k = 0; k < pdinf->bNumEndpoints; k++) {
                                pdend = &pdinf->endpoint[k];
                                if (pdend->bEndpointAddress == endpoint) {
-                                       ret = pdend->wMaxPacketSize;
-                                       goto out;
+                                       return (pdend);
                                }
                        }
                }
        }
 
-out:
+       return (NULL);
+}
+
+int
+libusb_get_max_packet_size(libusb_device *dev, uint8_t endpoint)
+{
+       struct libusb_config_descriptor *pdconf;
+       const struct libusb_endpoint_descriptor *pdend;
+       int ret;
+
+       if (dev == NULL)
+               return (LIBUSB_ERROR_OTHER);
+
+       ret = libusb_get_active_config_descriptor(dev, &pdconf);
+       if (ret < 0)
+               return (ret);
+
+       ret = LIBUSB_ERROR_NOT_FOUND;
+       if ((pdend = libusb_get_endpoint_from_config(pdconf, endpoint)) != NULL)
+               ret = pdend->wMaxPacketSize;
+
        libusb_free_config_descriptor(pdconf);
        return (ret);
 }
 
+static int
+libusb_calculate_ep_size(libusb_device *dev,
+    const libusb_endpoint_descriptor *ep)
+{
+       struct libusb_ss_endpoint_companion_descriptor *ss_ep;
+       int multiplier;
+       int speed;
+       int ret = LIBUSB_ERROR_NOT_SUPPORTED;
+       enum libusb_endpoint_transfer_type type;
+
+       speed = libusb_get_device_speed(dev);
+       if (speed >= LIBUSB_SPEED_SUPER) {
+               ret = libusb_get_ss_endpoint_companion_descriptor(dev->ctx, ep,
+                   &ss_ep);
+               if (ret == LIBUSB_SUCCESS) {
+                       ret = ss_ep->wBytesPerInterval;
+                       libusb_free_ss_endpoint_companion_descriptor(ss_ep);
+               }
+       }
+
+       /*
+        * reference:
+        * 
https://www.keil.com/pack/doc/mw/usb/html/_u_s_b__endpoint__descriptor.html
+        */
+       if (ret < 0) {
+               ret = ep->wMaxPacketSize;
+               switch (speed) {
+               case LIBUSB_SPEED_LOW:
+               case LIBUSB_SPEED_FULL:
+                       break;
+               default:
+                       type = ep->bmAttributes & 0x3;
+                       if (type == LIBUSB_ENDPOINT_TRANSFER_TYPE_ISOCHRONOUS ||
+                           type == LIBUSB_ENDPOINT_TRANSFER_TYPE_INTERRUPT) {
+                               multiplier = (1 + ((ret >> 11) & 3));
+                               if (multiplier > 3)
+                                       multiplier = 3;
+                               ret = (ret & 0x7FF) * multiplier;
+                       }
+                       break;
+               }
+       }
+
+       return (ret);
+}
+
 int
 libusb_get_max_iso_packet_size(libusb_device *dev, uint8_t endpoint)
 {
-       int multiplier;
+       struct libusb_config_descriptor *pdconf;
+       const struct libusb_endpoint_descriptor *pdend;
        int ret;
 
-       ret = libusb_get_max_packet_size(dev, endpoint);
+       if (dev == NULL)
+               return (LIBUSB_ERROR_OTHER);
 
-       switch (libusb20_dev_get_speed(dev->os_priv)) {
-       case LIBUSB20_SPEED_LOW:
-       case LIBUSB20_SPEED_FULL:
-               break;
-       default:
-               if (ret > -1) {
-                       multiplier = (1 + ((ret >> 11) & 3));
-                       if (multiplier > 3)
-                               multiplier = 3;
-                       ret = (ret & 0x7FF) * multiplier;
+       ret = libusb_get_active_config_descriptor(dev, &pdconf);
+       if (ret < 0)
+               return (LIBUSB_ERROR_OTHER);
+
+       pdend = libusb_get_endpoint_from_config(pdconf, endpoint);
+       if (pdend == NULL) {
+               libusb_free_config_descriptor(pdconf);
+               return (LIBUSB_ERROR_NOT_FOUND);
+       }
+
+       ret = libusb_calculate_ep_size(dev, pdend);
+       libusb_free_config_descriptor(pdconf);
+       return (ret);
+}
+
+int
+libusb_get_max_alt_packet_size(libusb_device *dev, int interface_number,
+    int alternate_setting, unsigned char endpoint)
+{
+       struct libusb_config_descriptor *pdconf;
+       struct libusb_interface *pinf;
+       struct libusb_interface_descriptor *pdinf;
+       const struct libusb_endpoint_descriptor *pdend = NULL;
+       const struct libusb_endpoint_descriptor *pdend_tmp;
+       int ret, i;
+
+       if (dev == NULL)
+               return (LIBUSB_ERROR_OTHER);
+
+       ret = libusb_get_active_config_descriptor(dev, &pdconf);
+       if (ret < 0)
+               return (LIBUSB_ERROR_OTHER);
+
+       if (pdconf->bNumInterfaces <= interface_number) {
+               libusb_free_config_descriptor(pdconf);
+               return (LIBUSB_ERROR_NOT_FOUND);
+       }
+       pinf = &pdconf->interface[interface_number];
+
+       if (pinf->num_altsetting <= alternate_setting) {
+               libusb_free_config_descriptor(pdconf);
+               return (LIBUSB_ERROR_NOT_FOUND);
+       }
+       pdinf = &pinf->altsetting[alternate_setting];
+
+       for (i = 0; i < pdinf->bNumEndpoints; ++i) {
+               pdend_tmp = &pdinf->endpoint[i];
+               if (pdend_tmp->bEndpointAddress == endpoint) {
+                       pdend = pdend_tmp;
+                       break;
                }
-               break;
        }
+       if (pdend != NULL)
+               ret = libusb_calculate_ep_size(dev, pdend);
+       else
+               ret = LIBUSB_ERROR_NOT_FOUND;
+       libusb_free_config_descriptor(pdconf);
+
        return (ret);
 }
 

Reply via email to