- Add support for software pre-scaling of ISOCHRONOUS transfers.

MFC after:	14 days
Approved by:	thompsa (mentor)
This commit is contained in:
Hans Petter Selasky 2011-02-28 17:23:15 +00:00
parent 898899d9dd
commit 1c49736857
11 changed files with 63 additions and 25 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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.
*/
};
/*