diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c index 3b8d567dae9b..fa50ea784dfb 100644 --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -51,7 +51,6 @@ struct libusb_context *usbi_default_context = NULL; /* Prototypes */ static struct libusb20_transfer *libusb10_get_transfer(struct libusb20_device *, uint8_t, uint8_t); -static int libusb10_get_maxframe(struct libusb20_device *, libusb_transfer *); static int libusb10_get_buffsize(struct libusb20_device *, libusb_transfer *); static int libusb10_convert_error(uint8_t status); static void libusb10_complete_transfer(struct libusb20_transfer *, struct libusb_super_transfer *, int); @@ -810,25 +809,14 @@ libusb_free_transfer(struct libusb_transfer *uxfer) free(sxfer); } -static int +static uint32_t libusb10_get_maxframe(struct libusb20_device *pdev, libusb_transfer *xfer) { - int ret; - int usb_speed; - - usb_speed = libusb20_dev_get_speed(pdev); + uint32_t ret; switch (xfer->type) { case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - switch (usb_speed) { - case LIBUSB20_SPEED_LOW: - case LIBUSB20_SPEED_FULL: - ret = 60 * 1; - break; - default: - ret = 60 * 8; - break; - } + ret = 60 | LIBUSB20_MAX_FRAME_PRE_SCALE; /* 60ms */ break; case LIBUSB_TRANSFER_TYPE_CONTROL: ret = 2; diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3 index a6dc890a70b4..93dfe18cf5be 100644 --- a/lib/libusb/libusb20.3 +++ b/lib/libusb/libusb20.3 @@ -261,6 +261,16 @@ The actual buffer size can be greater than and is returned by .Fn libusb20_tr_get_max_total_length . . +If +.Fa max_frame_count +is OR'ed with LIBUSB20_MAX_FRAME_PRE_SCALE the remaining part of the +argument is converted from milliseconds into the actual number of +frames rounded up, when this function returns. +This flag is only valid for ISOCHRONOUS transfers and has no effect +for other transfer types. +The actual number of frames setup is found by calling +.Fn libusb20_tr_get_max_frames . +. This function returns zero upon success. . Non-zero return values indicate a LIBUSB20_ERROR value. diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c index f8edfc38d343..bcaa1e47ff13 100644 --- a/lib/libusb/libusb20.c +++ b/lib/libusb/libusb20.c @@ -156,14 +156,20 @@ libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no) { uint32_t size; + uint8_t pre_scale; int error; - if (xfer->is_opened) { + if (xfer->is_opened) return (LIBUSB20_ERROR_BUSY); + if (MaxFrameCount & LIBUSB20_MAX_FRAME_PRE_SCALE) { + MaxFrameCount &= ~LIBUSB20_MAX_FRAME_PRE_SCALE; + pre_scale = 1; + } else { + pre_scale = 0; } - if (MaxFrameCount == 0) { + if (MaxFrameCount == 0) return (LIBUSB20_ERROR_INVALID_PARAM); - } + xfer->maxFrames = MaxFrameCount; size = MaxFrameCount * sizeof(xfer->pLength[0]); @@ -182,7 +188,7 @@ libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, memset(xfer->ppBuffer, 0, size); error = xfer->pdev->methods->tr_open(xfer, MaxBufSize, - MaxFrameCount, ep_no); + MaxFrameCount, ep_no, pre_scale); if (error) { free(xfer->ppBuffer); diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h index d16c6a628ea6..958a379ed254 100644 --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -197,8 +197,9 @@ struct libusb20_quirk { char quirkname[64 - 12]; }; -/* USB transfer operations */ +#define LIBUSB20_MAX_FRAME_PRE_SCALE (1U << 31) +/* USB transfer operations */ int libusb20_tr_close(struct libusb20_transfer *xfer); int libusb20_tr_open(struct libusb20_transfer *xfer, uint32_t max_buf_size, uint32_t max_frame_count, uint8_t ep_no); struct libusb20_transfer *libusb20_tr_get_pointer(struct libusb20_device *pdev, uint16_t tr_index); diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h index 64885f28877e..2ecfb4770a39 100644 --- a/lib/libusb/libusb20_int.h +++ b/lib/libusb/libusb20_int.h @@ -110,7 +110,7 @@ typedef int (libusb20_set_config_index_t)(struct libusb20_device *pdev, uint8_t typedef int (libusb20_check_connected_t)(struct libusb20_device *pdev); /* USB transfer specific */ -typedef int (libusb20_tr_open_t)(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no); +typedef int (libusb20_tr_open_t)(struct libusb20_transfer *xfer, uint32_t MaxBufSize, uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale); typedef int (libusb20_tr_close_t)(struct libusb20_transfer *xfer); typedef int (libusb20_tr_clear_stall_sync_t)(struct libusb20_transfer *xfer); typedef void (libusb20_tr_submit_t)(struct libusb20_transfer *xfer); diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c index 5b7d5e85a063..933d7286b679 100644 --- a/lib/libusb/libusb20_ugen20.c +++ b/lib/libusb/libusb20_ugen20.c @@ -736,11 +736,14 @@ ugen20_process(struct libusb20_device *pdev) static int ugen20_tr_open(struct libusb20_transfer *xfer, uint32_t MaxBufSize, - uint32_t MaxFrameCount, uint8_t ep_no) + uint32_t MaxFrameCount, uint8_t ep_no, uint8_t pre_scale) { struct usb_fs_open temp; struct usb_fs_endpoint *fsep; + if (pre_scale) + MaxFrameCount |= USB_FS_MAX_FRAMES_PRE_SCALE; + memset(&temp, 0, sizeof(temp)); fsep = xfer->pdev->privBeData; diff --git a/share/man/man9/usbdi.9 b/share/man/man9/usbdi.9 index 501c39f4c492..0e9f9f2e94a6 100644 --- a/share/man/man9/usbdi.9 +++ b/share/man/man9/usbdi.9 @@ -593,6 +593,10 @@ use the "usbd_xfer_set_stall()" and "usbd_transfer_clear_stall()" functions! This flag is automatically cleared after that the stall or clear stall has been executed. . +.It pre_scale_frames +If this flag is set the number of frames specified is assumed to give the buffering time in milliseconds instead of frames. +During transfer setup the frames field is pre scaled with the corresponding value for the endpoint and rounded to the nearest number of frames greater than zero. +This option only has effect for ISOCHRONOUS transfers. .El .Pp .Fa bufsize diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index da9b1d8ac055..8f197531bc46 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -1397,6 +1397,7 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags) uint8_t iface_index; uint8_t isread; uint8_t ep_index; + uint8_t pre_scale; u.addr = addr; @@ -1448,6 +1449,12 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags) if (u.popen->max_bufsize > USB_FS_MAX_BUFSIZE) { u.popen->max_bufsize = USB_FS_MAX_BUFSIZE; } + if (u.popen->max_frames & USB_FS_MAX_FRAMES_PRE_SCALE) { + pre_scale = 1; + u.popen->max_frames &= ~USB_FS_MAX_FRAMES_PRE_SCALE; + } else { + pre_scale = 0; + } if (u.popen->max_frames > USB_FS_MAX_FRAMES) { u.popen->max_frames = USB_FS_MAX_FRAMES; break; @@ -1468,13 +1475,15 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags) } iface_index = ep->iface_index; - bzero(usb_config, sizeof(usb_config)); + memset(usb_config, 0, sizeof(usb_config)); usb_config[0].type = ed->bmAttributes & UE_XFERTYPE; usb_config[0].endpoint = ed->bEndpointAddress & UE_ADDR; usb_config[0].direction = ed->bEndpointAddress & (UE_DIR_OUT | UE_DIR_IN); usb_config[0].interval = USB_DEFAULT_INTERVAL; usb_config[0].flags.proxy_buffer = 1; + if (pre_scale != 0) + usb_config[0].flags.pre_scale_frames = 1; usb_config[0].callback = &ugen_ctrl_fs_callback; usb_config[0].timeout = 0; /* no timeout */ usb_config[0].frames = u.popen->max_frames; @@ -1516,6 +1525,10 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr, int fflags) f->fs_xfer[u.popen->ep_index]->max_frame_size; u.popen->max_bufsize = f->fs_xfer[u.popen->ep_index]->max_data_length; + /* update number of frames */ + u.popen->max_frames = + f->fs_xfer[u.popen->ep_index]->nframes; + /* store index of endpoint */ f->fs_xfer[u.popen->ep_index]->priv_fifo = ((uint8_t *)0) + u.popen->ep_index; } else { diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h index 8fe55e18bd2a..452de94a7ab4 100644 --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -183,8 +183,9 @@ struct usb_fs_uninit { struct usb_fs_open { #define USB_FS_MAX_BUFSIZE (1 << 18) uint32_t max_bufsize; -#define USB_FS_MAX_FRAMES (1 << 12) - uint32_t max_frames; +#define USB_FS_MAX_FRAMES (1U << 12) +#define USB_FS_MAX_FRAMES_PRE_SCALE (1U << 31) /* for ISOCHRONOUS transfers */ + uint32_t max_frames; /* read and write */ uint16_t max_packet_length; /* read only */ uint8_t dev_index; /* currently unused */ uint8_t ep_index; diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 3a77c36d9b48..8dd9d1d27ac6 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -471,6 +471,8 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) xfer->fps_shift--; if (xfer->fps_shift > 3) xfer->fps_shift = 3; + if (xfer->flags.pre_scale_frames != 0) + xfer->nframes <<= (3 - xfer->fps_shift); break; } diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 6d4a911b0d13..b88a65557aac 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -195,6 +195,16 @@ struct usb_xfer_flags { uint8_t stall_pipe:1; /* set if the endpoint belonging to * this USB transfer should be stalled * before starting this transfer! */ + uint8_t pre_scale_frames:1; /* "usb_config->frames" is + * assumed to give the + * buffering time in + * milliseconds and is + * converted into the nearest + * number of frames when the + * USB transfer is setup. This + * option only has effect for + * ISOCHRONOUS transfers. + */ }; /*