Date: Mon, 8 Jun 2020 09:27:48 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r361911 - stable/11/sys/dev/usb Message-ID: <202006080927.0589Rm3B029960@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Mon Jun 8 09:27:48 2020 New Revision: 361911 URL: https://svnweb.freebsd.org/changeset/base/361911 Log: MFC r361581: Implement helper function, usbd_get_max_frame_length(), which allows kernel device drivers to correctly predict the default USB transfer frame length. Sponsored by: Mellanox Technologies Modified: stable/11/sys/dev/usb/usb_transfer.c stable/11/sys/dev/usb/usbdi.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/usb/usb_transfer.c ============================================================================== --- stable/11/sys/dev/usb/usb_transfer.c Mon Jun 8 09:26:46 2020 (r361910) +++ stable/11/sys/dev/usb/usb_transfer.c Mon Jun 8 09:27:48 2020 (r361911) @@ -373,6 +373,81 @@ usbd_transfer_setup_sub_malloc(struct usb_setup_params #endif /*------------------------------------------------------------------------* + * usbd_get_max_frame_length + * + * This function returns the maximum single frame length as computed by + * usbd_transfer_setup(). It is useful when computing buffer sizes for + * devices having multiple alternate settings. The SuperSpeed endpoint + * companion pointer is allowed to be NULL. + *------------------------------------------------------------------------*/ +uint32_t +usbd_get_max_frame_length(const struct usb_endpoint_descriptor *edesc, + const struct usb_endpoint_ss_comp_descriptor *ecomp, + enum usb_dev_speed speed) +{ + uint32_t max_packet_size; + uint32_t max_packet_count; + uint8_t type; + + max_packet_size = UGETW(edesc->wMaxPacketSize); + max_packet_count = 1; + type = (edesc->bmAttributes & UE_XFERTYPE); + + switch (speed) { + case USB_SPEED_HIGH: + switch (type) { + case UE_ISOCHRONOUS: + case UE_INTERRUPT: + max_packet_count += + (max_packet_size >> 11) & 3; + + /* check for invalid max packet count */ + if (max_packet_count > 3) + max_packet_count = 3; + break; + default: + break; + } + max_packet_size &= 0x7FF; + break; + case USB_SPEED_SUPER: + max_packet_count += (max_packet_size >> 11) & 3; + + if (ecomp != NULL) + max_packet_count += ecomp->bMaxBurst; + + if ((max_packet_count == 0) || + (max_packet_count > 16)) + max_packet_count = 16; + + switch (type) { + case UE_CONTROL: + max_packet_count = 1; + break; + case UE_ISOCHRONOUS: + if (ecomp != NULL) { + uint8_t mult; + + mult = UE_GET_SS_ISO_MULT( + ecomp->bmAttributes) + 1; + if (mult > 3) + mult = 3; + + max_packet_count *= mult; + } + break; + default: + break; + } + max_packet_size &= 0x7FF; + break; + default: + break; + } + return (max_packet_size * max_packet_count); +} + +/*------------------------------------------------------------------------* * usbd_transfer_setup_sub - transfer setup subroutine * * This function must be called from the "xfer_setup" callback of the Modified: stable/11/sys/dev/usb/usbdi.h ============================================================================== --- stable/11/sys/dev/usb/usbdi.h Mon Jun 8 09:26:46 2020 (r361910) +++ stable/11/sys/dev/usb/usbdi.h Mon Jun 8 09:27:48 2020 (r361911) @@ -552,6 +552,9 @@ uint8_t usbd_get_interface_altindex(struct usb_interfa usb_error_t usbd_set_alt_interface_index(struct usb_device *udev, uint8_t iface_index, uint8_t alt_index); uint32_t usbd_get_isoc_fps(struct usb_device *udev); +uint32_t usbd_get_max_frame_length(const struct usb_endpoint_descriptor *, + const struct usb_endpoint_ss_comp_descriptor *, + enum usb_dev_speed); usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **pxfer, const struct usb_config *setup_start, uint16_t n_setup,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202006080927.0589Rm3B029960>