aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2011-02-28 17:23:15 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2011-02-28 17:23:15 +0000
commit1c49736857cfe0b562e2f1e100ab2307e882a9e6 (patch)
tree47ed63016899826a83fbbc10b56bb53c1b6d65cd
parent898899d9ddbd15925a9d3c6b1da0d426dbc6351b (diff)
downloadsrc-1c49736857cfe0b562e2f1e100ab2307e882a9e6.tar.gz
src-1c49736857cfe0b562e2f1e100ab2307e882a9e6.zip
- Add support for software pre-scaling of ISOCHRONOUS transfers.
MFC after: 14 days Approved by: thompsa (mentor)
Notes
Notes: svn path=/head/; revision=219100
-rw-r--r--lib/libusb/libusb10.c18
-rw-r--r--lib/libusb/libusb20.310
-rw-r--r--lib/libusb/libusb20.c14
-rw-r--r--lib/libusb/libusb20.h3
-rw-r--r--lib/libusb/libusb20_int.h2
-rw-r--r--lib/libusb/libusb20_ugen20.c5
-rw-r--r--share/man/man9/usbdi.94
-rw-r--r--sys/dev/usb/usb_generic.c15
-rw-r--r--sys/dev/usb/usb_ioctl.h5
-rw-r--r--sys/dev/usb/usb_transfer.c2
-rw-r--r--sys/dev/usb/usbdi.h10
11 files changed, 63 insertions, 25 deletions
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.
+ */
};
/*