PERFORCE change 163628 for review
Andrew Thompson
thompsa at FreeBSD.org
Sat Jun 6 04:33:11 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=163628
Change 163628 by thompsa at thompsa_burger on 2009/06/06 04:32:19
- Allocate multiple urbs
- Add urb list functions
Affected files ...
.. //depot/projects/usb_buf/src/sys/dev/usb/usb_transfer.c#14 edit
.. //depot/projects/usb_buf/src/sys/dev/usb/usbdi.h#5 edit
Differences ...
==== //depot/projects/usb_buf/src/sys/dev/usb/usb_transfer.c#14 (text+ko) ====
@@ -61,6 +61,11 @@
#include <dev/usb/usb_controller.h>
#include <dev/usb/usb_bus.h>
+enum {
+ REQ_SIZE = 8,
+ MIN_PKT = 8,
+};
+
struct usb2_std_packet_size {
struct {
uint16_t min; /* inclusive */
@@ -114,6 +119,9 @@
static void usb2_get_std_packet_size(struct usb2_std_packet_size *ptr,
uint8_t type, enum usb_dev_speed speed);
static void usb_submit_urb_flags(struct usb_urb *, int);
+static struct usb_urb *urb_alloc(struct usb_pipe *, struct usb_setup_params *,
+ uint8_t, usb_frcount_t, usb_frcount_t);
+static void urb_free(struct usb_urb *);
/*------------------------------------------------------------------------*
@@ -297,6 +305,101 @@
}
#endif
+static struct usb_urb *
+urb_alloc(struct usb_pipe *pipe, struct usb_setup_params *parm,
+ uint8_t type, usb_frcount_t n_frlengths, usb_frcount_t n_frbuffers)
+{
+ const struct usb_config *setup = parm->curr_setup;
+ struct usb_urb *urb;
+ usb_frlength_t bufsiz;
+ usb_frcount_t x;
+
+ bufsiz = setup->flags.ext_buffer == 1 ? 0 : parm->bufsize;
+
+ urb = malloc(sizeof(struct usb_urb) + bufsiz, M_USB,
+ M_WAITOK | M_ZERO);
+ urb->ub_pipe = pipe;
+ urb->ub_buflen = bufsiz;
+ urb->local_buffer = urb + 1;
+
+ urb->frlengths = malloc(sizeof(usb_frlength_t) * n_frlengths,
+ M_USB, M_WAITOK | M_ZERO);
+ urb->frbuffers = malloc(sizeof(struct usb_page_cache) * n_frbuffers,
+ M_USB, M_WAITOK | M_ZERO);
+
+#if USB_HAVE_BUSDMA
+ if (pipe->flags_int.bdma_enable) {
+ /*
+ * Setup "dma_page_ptr".
+ *
+ * Proof for formula below:
+ *
+ * Assume there are three USB frames having length "a",
+ * "b" and "c". These USB frames will at maximum need
+ * "z" "usb_page" structures. "z" is given by:
+ *
+ * z = ((a / USB_PAGE_SIZE) + 2) +
+ * ((b / USB_PAGE_SIZE) + 2) +
+ * ((c / USB_PAGE_SIZE) + 2);
+ *
+ * Constraining "a", "b" and "c" like this:
+ *
+ * (a + b + c) <= parm->bufsize
+ *
+ * We know that:
+ *
+ * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
+ *
+ * Here is the general formula:
+ */
+ urb->dma_page_ptr = malloc(sizeof(struct usb_page) *
+ ((2 * n_frbuffers) + (parm->bufsize / USB_PAGE_SIZE)),
+ M_USB, M_WAITOK | M_ZERO);
+ }
+#endif
+ /* initialize frame buffers */
+ for (x = 0; x < n_frbuffers; x++) {
+ urb->frbuffers[x].tag_parent =
+ &pipe->xroot->dma_parent_tag;
+#if USB_HAVE_BUSDMA
+ if (pipe->flags_int.bdma_enable &&
+ (parm->bufsize_max > 0)) {
+
+ if (usb2_pc_dmamap_create(
+ urb->frbuffers + x,
+ parm->bufsize_max)) {
+ goto error;
+ }
+ }
+#endif
+ }
+
+ if (bufsiz > 0) {
+ usb2_set_frame_offset(urb, 0, 0);
+ if ((type == UE_CONTROL) && (n_frbuffers > 1))
+ usb2_set_frame_offset(urb, REQ_SIZE, 1);
+ }
+ /* initialize max frame count */
+ urb->max_frame_count = pipe->nframes;
+ urb->nframes = pipe->nframes;
+
+ return (urb);
+
+error:
+ urb_free(urb);
+ return (NULL);
+}
+
+static void
+urb_free(struct usb_urb *urb)
+{
+
+ free(urb->dma_page_ptr, M_USB);
+ free(urb->frbuffers, M_USB);
+ free(urb->frlengths, M_USB);
+ free(urb, M_USB);
+}
+
/*------------------------------------------------------------------------*
* usb2_transfer_setup_sub - transfer setup subroutine
*
@@ -309,10 +412,6 @@
void
usb2_transfer_setup_sub(struct usb_setup_params *parm)
{
- enum {
- REQ_SIZE = 8,
- MIN_PKT = 8,
- };
struct usb_pipe *pipe = parm->curr_pipe;
const struct usb_config *setup = parm->curr_setup;
struct usb_endpoint_descriptor *edesc;
@@ -320,9 +419,9 @@
struct usb_urb *urb;
usb_frcount_t n_frlengths;
usb_frcount_t n_frbuffers;
- usb_frcount_t x;
uint8_t type;
uint8_t zmps;
+ int i;
/*
* Sanity check. The following parameters must be initialized before
@@ -338,15 +437,9 @@
type = (edesc->bmAttributes & UE_XFERTYPE);
- /* XXX */
TAILQ_INIT(&pipe->urb_hc_q);
TAILQ_INIT(&pipe->urb_pending_q);
TAILQ_INIT(&pipe->urb_free_q);
- urb = &pipe->urb0;
- urb->ub_pipe = pipe;
- TAILQ_INSERT_TAIL(&pipe->urb_free_q, urb, ub_next);
- pipe->urb_nfree = 1;
- pipe->urb_nurb = 1;
pipe->flags = setup->flags;
pipe->nframes = setup->frames;
@@ -602,80 +695,30 @@
}
pipe->max_data_length -= REQ_SIZE;
}
- /* setup "frlengths" */
-
- pipe->urb0.frlengths = parm->xfer_length_ptr;
- parm->xfer_length_ptr += n_frlengths;
-
- /* setup "frbuffers" */
-
- pipe->urb0.frbuffers = parm->xfer_page_cache_ptr;
-
- parm->xfer_page_cache_ptr += n_frbuffers;
-
/*
- * check if we need to setup
- * a local buffer:
+ * Compute maximum buffer size
*/
- if (!pipe->flags.ext_buffer) {
+ if (parm->bufsize_max < parm->bufsize) {
+ parm->bufsize_max = parm->bufsize;
+ }
- /* align data */
- parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
-
- if (parm->buf) {
-
- pipe->urb0.local_buffer =
- USB_ADD_BYTES(parm->buf, parm->size[0]);
-
- usb2_set_frame_offset(pipe, 0, 0);
-
- if ((type == UE_CONTROL) && (n_frbuffers > 1)) {
- usb2_set_frame_offset(pipe, REQ_SIZE, 1);
+ /* Allocate the URBs */
+ if (parm->buf) {
+ pipe->urb_nurb = setup->urb_count ? setup->urb_count : 1;
+ for (i = 0; i < pipe->urb_nurb; i++) {
+ urb = urb_alloc(pipe, parm, type, n_frlengths,
+ n_frbuffers);
+ if (urb == NULL) {
+ parm->err = USB_ERR_NOMEM;
+ goto done;
}
+ TAILQ_INSERT_TAIL(&pipe->urb_free_q, urb, ub_next);
+ pipe->urb_nfree++;
}
- parm->size[0] += parm->bufsize;
-
- /* align data again */
- parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
}
- /*
- * Compute maximum buffer size
- */
- if (parm->bufsize_max < parm->bufsize) {
- parm->bufsize_max = parm->bufsize;
- }
-#if USB_HAVE_BUSDMA
- if (pipe->flags_int.bdma_enable) {
- /*
- * Setup "dma_page_ptr".
- *
- * Proof for formula below:
- *
- * Assume there are three USB frames having length "a", "b" and
- * "c". These USB frames will at maximum need "z"
- * "usb_page" structures. "z" is given by:
- *
- * z = ((a / USB_PAGE_SIZE) + 2) + ((b / USB_PAGE_SIZE) + 2) +
- * ((c / USB_PAGE_SIZE) + 2);
- *
- * Constraining "a", "b" and "c" like this:
- *
- * (a + b + c) <= parm->bufsize
- *
- * We know that:
- *
- * z <= ((parm->bufsize / USB_PAGE_SIZE) + (3*2));
- *
- * Here is the general formula:
- */
- pipe->urb0.dma_page_ptr = parm->dma_page_ptr;
- parm->dma_page_ptr += (2 * n_frbuffers);
- parm->dma_page_ptr += (parm->bufsize / USB_PAGE_SIZE);
- }
-#endif
if (zmps) {
/* correct maximum data length */
pipe->max_data_length = 0;
@@ -690,31 +733,7 @@
parm->err = USB_ERR_INVAL;
goto done;
}
- /* initialize max frame count */
- pipe->urb0.max_frame_count = pipe->nframes;
-
- /* initialize frame buffers */
-
- if (parm->buf) {
- for (x = 0; x != n_frbuffers; x++) {
- pipe->urb0.frbuffers[x].tag_parent =
- &pipe->xroot->dma_parent_tag;
-#if USB_HAVE_BUSDMA
- if (pipe->flags_int.bdma_enable &&
- (parm->bufsize_max > 0)) {
-
- if (usb2_pc_dmamap_create(
- pipe->urb0.frbuffers + x,
- parm->bufsize_max)) {
- parm->err = USB_ERR_NOMEM;
- goto done;
- }
- }
-#endif
- }
- }
- pipe->urb0.nframes = pipe->nframes;
done:
if (parm->err) {
/*
@@ -724,8 +743,6 @@
pipe->max_frame_size = 1;
pipe->max_packet_size = 1;
pipe->max_data_length = 0;
- pipe->urb0.nframes = 0;
- pipe->urb0.max_frame_count = 0;
}
}
@@ -783,6 +800,10 @@
parm.err = USB_ERR_BAD_BUFSIZE;
DPRINTF("invalid bufsize\n");
}
+ if (setup->urb_count > 4) {
+ parm.err = USB_ERR_BAD_BUFSIZE;
+ DPRINTF("too many urbs requested\n");
+ }
if (setup->callback == NULL) {
parm.err = USB_ERR_NO_CALLBACK;
DPRINTF("no callback\n");
@@ -1128,6 +1149,7 @@
usb_pipe_close(struct usb_pipe **pxfer, int n_setup)
{
struct usb_pipe *pipe;
+ struct usb_urb *urb;
struct usb_xfer_root *info;
uint8_t needs_delay = 0;
@@ -1171,6 +1193,11 @@
KASSERT (pipe->urb_nfree == pipe->urb_nurb,
("leaked %d urbs", pipe->urb_nurb - pipe->urb_nfree));
+ while ((urb = TAILQ_FIRST(&pipe->urb_free_q)) != NULL) {
+ TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
+ urb_free(urb);
+ }
+
#if USB_HAVE_BUSDMA
if (pipe->flags_int.bdma_enable)
needs_delay = 1;
@@ -1421,8 +1448,6 @@
printf("pipe halted, queuing %p\n", urb);
TAILQ_INSERT_TAIL(&pipe->urb_pending_q, urb, ub_next);
return;
- } else {
- KASSERT(TAILQ_FIRST(&pipe->urb_pending_q) == NULL, ("odd"));
}
/* Only open the USB transfer once! */
@@ -1657,6 +1682,10 @@
usb_pipe_halt(struct usb_pipe *pipe)
{
+ if (pipe == NULL) {
+ printf("%s: null pipe!!?!\n", __func__);
+ return;
+ }
USB_PIPE_LOCK(pipe);
pipe->flags_int.halted = 1;
@@ -1742,10 +1771,10 @@
* than zero gives undefined results!
*------------------------------------------------------------------------*/
void
-usb2_set_frame_data(struct usb_pipe *pipe, void *ptr, usb_frcount_t frindex)
+usb2_set_frame_data(struct usb_urb *urb, void *ptr, usb_frcount_t frindex)
{
/* set virtual address to load and length */
- (&pipe->urb0)->frbuffers[frindex].buffer = ptr;
+ urb->frbuffers[frindex].buffer = ptr;
}
/*------------------------------------------------------------------------*
@@ -1755,15 +1784,19 @@
* of the USB DMA buffer allocated for this USB transfer.
*------------------------------------------------------------------------*/
void
-usb2_set_frame_offset(struct usb_pipe *pipe, usb_frlength_t offset,
+usb2_set_frame_offset(struct usb_urb *urb, usb_frlength_t offset,
usb_frcount_t frindex)
{
+ struct usb_pipe *pipe = urb->ub_pipe;
+
USB_ASSERT(!pipe->flags.ext_buffer, ("Cannot offset data frame "
"when the USB buffer is external!\n"));
+ /* USB_ASSERT(offset < urb->ub_buflen,
+ ("frame overflow %d > %d", offset, urb->ub_buflen)); */
/* set virtual address to load */
- (&pipe->urb0)->frbuffers[frindex].buffer =
- USB_ADD_BYTES((&pipe->urb0)->local_buffer, offset);
+ urb->frbuffers[frindex].buffer =
+ USB_ADD_BYTES(urb->local_buffer, offset);
}
/*------------------------------------------------------------------------*
@@ -2743,15 +2776,14 @@
USB_PIPE_LOCK(pipe);
urb = TAILQ_FIRST(&pipe->urb_free_q);
- if (urb == NULL)
- panic("out of urbs");
+ if (urb != NULL) {
+ TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
+ pipe->urb_nfree--;
+ KASSERT(pipe->urb_nfree >= 0, ("negative count"));
- TAILQ_REMOVE(&pipe->urb_free_q, urb, ub_next);
- pipe->urb_nfree--;
- KASSERT(pipe->urb_nfree >= 0, ("negative count"));
+ usb_init_urb(urb);
+ }
USB_PIPE_UNLOCK(pipe);
-
- usb_init_urb(urb);
return (urb);
}
@@ -2808,7 +2840,7 @@
if (ptr != NULL)
*ptr = urb->frbuffers->buffer;
if (len != NULL)
- *len = urb->sumlen;
+ *len = urb->ub_pipe->max_data_length;
if (alen != NULL)
*alen = urb->actlen;
if (err != NULL)
@@ -2816,8 +2848,52 @@
}
void
-urb_set_framelen(struct usb_urb *urb, int frame, int len)
+urb_set_framelen(struct usb_urb *urb, usb_frcount_t frame, usb_frlength_t len)
{
- /* XXX checking */
+ KASSERT(len <= urb->ub_pipe->max_data_length,
+ ("%s: urb buffer overflow", __func__));
urb->frlengths[frame] = len;
}
+
+void
+urb_list_init(usb_urb_list *list)
+{
+
+ TAILQ_INIT(&list->head);
+ list->count = 0;
+}
+
+void
+urb_list_insert(usb_urb_list *list, struct usb_urb *urb)
+{
+
+ KASSERT(urb->on_queue == 0, ("urb already qeueued"));
+ TAILQ_INSERT_TAIL(&list->head, urb, ub_next);
+ list->count++;
+ urb->on_queue = 1;
+}
+
+void
+urb_list_remove(usb_urb_list *list, struct usb_urb *urb)
+{
+
+ KASSERT(urb->on_queue == 1, ("urb not on qeueue"));
+ KASSERT(list->count > 0, ("list count corrupt"));
+ TAILQ_REMOVE(&list->head, urb, ub_next);
+ list->count--;
+ urb->on_queue = 0;
+}
+
+struct usb_urb *
+urb_list_dequeue(usb_urb_list *list)
+{
+ struct usb_urb *urb;
+
+ urb = TAILQ_FIRST(&list->head);
+ if (urb != NULL)
+ urb_list_remove(list, urb);
+
+ KASSERT(urb != NULL || list->count == 0, ("list count corrupt"));
+
+ return (urb);
+}
==== //depot/projects/usb_buf/src/sys/dev/usb/usbdi.h#5 (text+ko) ====
@@ -93,6 +93,11 @@
typedef usb_error_t (usb_handle_req_t)(struct usb_device *,
struct usb_device_request *, const void **, uint16_t *);
+typedef struct {
+ TAILQ_HEAD(, usb_urb) head;
+ int count;
+} usb_urb_list;
+
/*
* The following structure defines a set of USB transfer flags.
*/
@@ -132,6 +137,7 @@
uint8_t direction; /* pipe direction */
uint8_t ep_index; /* pipe index match to use */
uint8_t if_index; /* "ifaces" index to use */
+ uint8_t urb_count; /* number if urbs avaialble */
};
/*
@@ -300,7 +306,13 @@
void *urb_get_softc(struct usb_urb *urb);
void *urb_get_priv(struct usb_urb *urb);
void urb_set_priv(struct usb_urb *urb, void *);
-void urb_set_framelen(struct usb_urb *urb, int frame, int len);
+void urb_set_framelen(struct usb_urb *urb, usb_frcount_t frame,
+ usb_frlength_t len);
+
+void urb_list_init(usb_urb_list *);
+void urb_list_insert(usb_urb_list *, struct usb_urb *);
+void urb_list_remove(usb_urb_list *, struct usb_urb *);
+struct usb_urb *urb_list_dequeue(usb_urb_list *);
void device_set_usb_desc(device_t dev);
void usb_pause_mtx(struct mtx *mtx, int _ticks);
More information about the p4-projects
mailing list