- Add support for software pre-scaling of ISOCHRONOUS transfers.
MFC after: 14 days Approved by: thompsa (mentor)
This commit is contained in:
parent
45caeec249
commit
f6b78c32dc
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user