PERFORCE change 126732 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sun Sep 23 07:22:58 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=126732
Change 126732 by hselasky at hselasky_laptop001 on 2007/09/23 14:22:45
FYI; The comments follow the P4 diff from top to bottom.
- check that "index" is zero before returning a match on the default pipe.
- define all valid USB packet sizes in the "usbd_std_packet_size[][]" table.
- new internal function "usbd_compute_max_frame_size()" that
computes the frames size from the packet size.
- new global function "usbd_transfer_setup_sub()" which
performs common setup of "struct usbd_xfer" cross all
host/device drivers.
- changes to "usbd_transfer_setup()" are part of the USB
transfer setup refactorisation.
- remove all "usbd_xxx_copy_xxx()" functions.
- new global function "usbd_std_root_transfer()" which is
statemachine wrapper for BULK, CONTROL and INTERRUPT USB
transfers that uses a linear buffer to transfer data for
sake of convenience.
- new internal function "usbd_start_hardware_sub()" which main
purpose is to setup the correct state for split USB control
transfers. Don't confuse this by the USB transaction
translator. Split USB control transfers is here simply a way
to transfer USB control data in smaller parts.
- new internal function "usbd_premature_callback()" which is
simply factored out code.
- remove printing of "xfer->length", hence it does not exist any more.
- transform "USBD_DEV_XXX" flags into "flags_int.xxx"
- the check for "xfer->nframes == 0" has been factored out
into "usbd_start_hardware()"
- the "xfer->usb_mtx" mutex should not be held when calling
"__usbd_callback()".
- "usbd_transfer_done()" is now part of "usbd_transfer_dequeue()"
- "usbd_do_request_callback()" is now an internal function.
- "usbd_do_request()" is now a macro.
- "usbd_do_request_flags()" now allocated a proxy USB transfer
and uses this for all subsequent USB transfer. This also makes
the control transfer function more reliable in low-memory
environment, hence it does no longer depend on any memory
allocation after USB enumeration.
- all USB BULK/ISOC/INTR IN-transfers must setup
"xfer->frlengths[]" before calling "usbd_start_hardware()".
Else the actual length of the previous transfer will be
used for transfer length of the next USB transfer.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#29 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#29 (text+ko) ====
@@ -199,7 +199,8 @@
*/
if((setup->endpoint == 0) &&
(setup->type == 0) &&
- (udev->default_pipe.edesc)) {
+ (udev->default_pipe.edesc) &&
+ (!index)) {
pipe = &udev->default_pipe;
goto found;
}
@@ -220,6 +221,416 @@
return (USBD_NORMAL_COMPLETION);
}
+static const struct usbd_std_packet_size {
+ struct {
+ uint16_t min; /* inclusive */
+ uint16_t max; /* inclusive */
+ } range;
+
+ uint16_t fixed[4];
+
+} usbd_std_packet_size[4][USB_SPEED_MAX] = {
+
+ [UE_INTERRUPT] = {
+ [USB_SPEED_LOW] = { .range = { 0, 8 } },
+ [USB_SPEED_FULL] = { .range = { 0, 64 } },
+ [USB_SPEED_HIGH] = { .range = { 0, 1024 } },
+ [USB_SPEED_VARIABLE] = { .range = { 0, 1024 } },
+ },
+
+ [UE_CONTROL] = {
+ [USB_SPEED_LOW] = { .fixed = { 8, 8, 8, 8 } },
+ [USB_SPEED_FULL] = { .fixed = { 8, 16, 32, 64 } },
+ [USB_SPEED_HIGH] = { .fixed = { 64, 64, 64, 64 } },
+ [USB_SPEED_VARIABLE] = { .fixed = { 512, 512, 512, 512 } },
+ },
+
+ [UE_BULK] = {
+ [USB_SPEED_LOW] = { }, /* invalid (all zero) */
+ [USB_SPEED_FULL] = { .fixed = { 8, 16, 32, 64 } },
+ [USB_SPEED_HIGH] = { .fixed = { 512, 512, 512, 512 } },
+ [USB_SPEED_VARIABLE] = { .fixed = { 512, 1024, 1536 } },
+ },
+
+ [UE_ISOCHRONOUS] = {
+ [USB_SPEED_LOW] = { }, /* invalid (all zero) */
+ [USB_SPEED_FULL] = { .range = { 0, 1023 } },
+ [USB_SPEED_HIGH] = { .range = { 0, 1024 } },
+ [USB_SPEED_VARIABLE] = { .range = { 0, 3584 } },
+ },
+};
+
+static void
+usbd_compute_max_frame_size(struct usbd_xfer *xfer)
+{
+ /* compute maximum frame size */
+
+ if (xfer->max_packet_count == 2) {
+ xfer->max_frame_size = 2 * xfer->max_packet_size;
+ } else if (xfer->max_packet_count == 3) {
+ xfer->max_frame_size = 3 * xfer->max_packet_size;
+ } else {
+ xfer->max_frame_size = xfer->max_packet_size;
+ }
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * usbd_transfer_setup_sub - transfer setup subroutine
+ *------------------------------------------------------------------------*/
+void
+usbd_transfer_setup_sub(struct usbd_setup_params *parm)
+{
+ enum { REQ_SIZE = 8,
+ MIN_PKT = 8 };
+ struct usbd_xfer *xfer = parm->curr_xfer;
+ const struct usbd_config *setup = parm->curr_setup;
+ usb_endpoint_descriptor_t *edesc;
+ struct usbd_std_packet_size std_size;
+ uint16_t n_frlengths;
+ uint16_t n_frbuffers;
+ uint8_t type;
+ uint8_t zmps;
+
+ /* sanity check */
+
+ if ((parm->hc_max_packet_size == 0) ||
+ (parm->hc_max_packet_count == 0) ||
+ (parm->hc_max_frame_size == 0)) {
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+
+ edesc = xfer->pipe->edesc;
+
+ type = (edesc->bmAttributes & UE_XFERTYPE);
+
+ xfer->flags = setup->flags;
+ xfer->nframes = setup->frames;
+ xfer->timeout = setup->timeout;
+ xfer->callback = setup->callback;
+ xfer->interval = setup->interval;
+ xfer->endpoint = edesc->bEndpointAddress;
+ xfer->max_packet_size = UGETW(edesc->wMaxPacketSize);
+ xfer->max_packet_count = 1;
+
+ parm->bufsize = setup->bufsize;
+
+ if (parm->speed == USB_SPEED_HIGH) {
+ xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3;
+ xfer->max_packet_size &= 0x7FF;
+ }
+
+ /* range check "max_packet_count" */
+
+ if (xfer->max_packet_count > parm->hc_max_packet_count) {
+ xfer->max_packet_count = parm->hc_max_packet_count;
+ }
+
+ /* filter "wMaxPacketSize" according to HC capabilities */
+
+ if (xfer->max_packet_size > parm->hc_max_packet_size) {
+ xfer->max_packet_size = parm->hc_max_packet_size;
+ }
+
+ /* filter "wMaxPacketSize" according to standard sizes */
+
+ std_size = usbd_std_packet_size[type][parm->speed];
+
+ if (std_size.range.min || std_size.range.max) {
+
+ if (xfer->max_packet_size < std_size.range.min) {
+ xfer->max_packet_size = std_size.range.min;
+ }
+
+ if (xfer->max_packet_size > std_size.range.max) {
+ xfer->max_packet_size = std_size.range.max;
+ }
+ } else {
+
+ if (xfer->max_packet_size >= std_size.fixed[3]) {
+ xfer->max_packet_size = std_size.fixed[3];
+ } else if (xfer->max_packet_size >= std_size.fixed[2]) {
+ xfer->max_packet_size = std_size.fixed[2];
+ } else if (xfer->max_packet_size >= std_size.fixed[1]) {
+ xfer->max_packet_size = std_size.fixed[1];
+ } else {
+ /* only one possibility left */
+ xfer->max_packet_size = std_size.fixed[0];
+ }
+ }
+
+ /* compute "max_frame_size" */
+
+ usbd_compute_max_frame_size(xfer);
+
+ /* check interrupt interval and transfer pre-delay */
+
+ if (type == UE_ISOCHRONOUS) {
+
+ uint32_t frame_limit;
+
+ xfer->interval = 0; /* not used, must be zero */
+
+ if (xfer->timeout == 0) {
+ /*
+ * set a default timeout in
+ * case something goes wrong!
+ */
+ xfer->timeout = 1000 / 4;
+ }
+
+ if (parm->speed == USB_SPEED_HIGH) {
+ frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER;
+ } else {
+ frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER;
+ }
+
+ if (xfer->nframes > frame_limit) {
+ /*
+ * this is not going to work
+ * cross hardware
+ */
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+
+ n_frlengths = xfer->nframes;
+ n_frbuffers = 1;
+
+ } else {
+
+ /* BSD specific requirement:
+ *
+ * In case we are transferring more than one USB frame
+ * consisting of up to 3 USB packets, make sure that the
+ * USB frame size is divisible by 8. This is supposed to
+ * optimize the USB Host Controller by avoiding unaligned
+ * data accesses!
+ */
+
+ if (parm->bufsize > xfer->max_frame_size) {
+
+ while (xfer->max_frame_size & 7) {
+ if (xfer->max_packet_size == parm->hc_max_packet_size) {
+ /* should not happen */
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+ (xfer->max_packet_size) ++;
+ usbd_compute_max_frame_size(xfer);
+ }
+ }
+
+ /* if a value is specified use that
+ * else check the endpoint descriptor
+ */
+ if (xfer->interval == 0) {
+
+ if (type == UE_INTERRUPT) {
+
+ xfer->interval = edesc->bInterval;
+
+ if (parm->speed == USB_SPEED_HIGH) {
+ xfer->interval /= 8; /* 125us -> 1ms */
+ }
+
+ if (xfer->interval == 0) {
+ /* one millisecond is the smallest interval */
+ xfer->interval = 1;
+ }
+ }
+ }
+
+ if (type == UE_CONTROL) {
+ xfer->flags_int.control_xfr = 1;
+ if (xfer->nframes == 0) {
+ xfer->nframes = 2;
+ }
+ } else {
+ if (xfer->nframes == 0) {
+ xfer->nframes = 1;
+ }
+ }
+
+ n_frlengths = xfer->nframes;
+ n_frbuffers = xfer->nframes;
+ }
+
+ if (xfer->nframes == 0) {
+ parm->err = USBD_ZERO_NFRAMES;
+ goto done;
+ }
+
+ /*
+ * NOTE: we do not allow "max_packet_size" or "max_frame_size"
+ * to be equal to zero when setting up USB transfers, hence
+ * this leads to alot of extra code in the USB kernel.
+ */
+
+ if ((xfer->max_frame_size == 0) ||
+ (xfer->max_packet_size == 0)) {
+
+ zmps = 1;
+
+ if ((parm->bufsize <= MIN_PKT) &&
+ (type != UE_CONTROL) &&
+ (type != UE_BULK)) {
+
+ /* workaround */
+ xfer->max_packet_size = MIN_PKT;
+ xfer->max_packet_count = 1;
+ parm->bufsize = 0; /* automatic setup length */
+ usbd_compute_max_frame_size(xfer);
+
+ } else {
+ parm->err = USBD_ZERO_MAXP;
+ goto done;
+ }
+
+ } else {
+ zmps = 0;
+ }
+
+ /*
+ * check if we should setup a default
+ * length:
+ */
+
+ if (parm->bufsize == 0) {
+
+ parm->bufsize = xfer->max_frame_size;
+
+ if (type == UE_ISOCHRONOUS) {
+ parm->bufsize *= xfer->nframes;
+ }
+ }
+
+ /*
+ * check if we are about to setup a proxy
+ * type of buffer:
+ */
+
+ if (xfer->flags.proxy_buffer) {
+
+ /* round bufsize up */
+
+ parm->bufsize += (xfer->max_frame_size-1);
+
+ if (parm->bufsize < xfer->max_frame_size) {
+ /* length wrapped around */
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+
+ /* subtract remainder */
+
+ parm->bufsize -= (parm->bufsize % xfer->max_frame_size);
+
+ /* add length of USB device request structure, if any */
+
+ if (type == UE_CONTROL) {
+ parm->bufsize += REQ_SIZE; /* SETUP message */
+ }
+ }
+
+ xfer->max_data_length = parm->bufsize;
+
+ /*
+ * check if we have room for the
+ * USB device request structure:
+ */
+
+ if (type == UE_CONTROL) {
+
+ if (xfer->max_data_length < REQ_SIZE) {
+ /* length wrapped around or too small bufsize */
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+
+ xfer->max_data_length -= REQ_SIZE;
+ }
+
+ /* align data */
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN-1));
+
+ xfer->frlengths = USBD_ADD_BYTES(parm->buf,parm->size[0]);
+
+ parm->size[0] += (n_frlengths * sizeof(xfer->frlengths[0]));
+
+ /* align data */
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN-1));
+
+ xfer->frbuffers = USBD_ADD_BYTES(parm->buf,parm->size[0]);
+
+ parm->size[0] += (n_frbuffers * sizeof(xfer->frbuffers[0]));
+
+ /* align data */
+ parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN-1));
+
+ /*
+ * check if we need to setup
+ * a local buffer:
+ */
+
+ if (!xfer->flags.ext_buffer) {
+
+ /* align data */
+ parm->size[1] += ((-parm->size[1]) & (USB_HOST_ALIGN-1));
+
+ if (parm->buf) {
+
+ usbd_page_cache_init
+ (xfer->frbuffers + 0, parm->page_ptr,
+ parm->size[1], parm->bufsize);
+
+ if (type == UE_CONTROL) {
+
+ usbd_page_cache_init
+ (xfer->frbuffers + 1, parm->page_ptr,
+ parm->size[1] + REQ_SIZE, parm->bufsize - REQ_SIZE);
+ }
+
+ /*
+ * make a copy of the page cache that
+ * starts at offset zero:
+ */
+
+ xfer->buf_data = xfer->frbuffers[0];
+ }
+
+ parm->size[1] += parm->bufsize;
+
+ /* align data again */
+ parm->size[1] += ((-parm->size[1]) & (USB_HOST_ALIGN-1));
+ }
+
+ if (zmps) {
+ /* correct maximum data length */
+ xfer->max_data_length = 0;
+ }
+
+ /* subtract USB frame remainder from "hc_max_frame_size" */
+
+ xfer->max_usb_frame_size =
+ (parm->hc_max_frame_size -
+ (parm->hc_max_frame_size % xfer->max_frame_size));
+
+ if (xfer->max_usb_frame_size == 0) {
+ parm->err = USBD_INVAL;
+ goto done;
+ }
+
+ done:
+ if (parm->err) {
+ xfer->max_usb_frame_size = 1; /* XXX avoid division by zero */
+ xfer->max_data_length = 0;
+ xfer->nframes = 0;
+ }
+ return;
+}
+
/*---------------------------------------------------------------------------*
* usbd_transfer_setup - setup an array of USB transfers
*
@@ -233,19 +644,23 @@
usbd_status
usbd_transfer_setup(struct usbd_device *udev,
u_int8_t iface_index,
- struct usbd_xfer **pxfer,
+ struct usbd_xfer **ppxfer,
const struct usbd_config *setup_start,
u_int16_t n_setup,
void *priv_sc,
struct mtx *priv_mtx)
{
+ struct usbd_xfer dummy;
+ struct usbd_setup_params parm;
const struct usbd_config *setup_end = setup_start + n_setup;
const struct usbd_config *setup;
struct usbd_memory_info *info;
struct usbd_xfer *xfer;
- usbd_status error = 0;
+ void *buf = NULL;
u_int16_t n;
+ parm.err = 0;
+
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"usbd_transfer_setup can sleep!");
@@ -263,73 +678,172 @@
priv_mtx = &usb_global_lock;
}
- for(setup = setup_start, n = n_setup; n--; setup++)
+ for (setup = setup_start, n = 0;
+ setup != setup_end; setup++, n++)
{
if(setup->bufsize == 0xffffffff)
{
- error = USBD_BAD_BUFSIZE;
+ parm.err = USBD_BAD_BUFSIZE;
PRINTF(("invalid bufsize\n"));
}
- if(setup->flags &
- (~(0|
- USBD_FORCE_SHORT_XFER|
- USBD_SHORT_XFER_OK|
- USBD_USE_POLLING|
- USBD_PIPE_BOF|
- USBD_USE_DMA|
- 0)))
- {
- error = USBD_BAD_FLAG;
- PRINTF(("invalid flag(s) specified: "
- "0x%08x\n", setup->flags));
- }
if(setup->callback == NULL)
{
- error = USBD_NO_CALLBACK;
+ parm.err = USBD_NO_CALLBACK;
PRINTF(("no callback\n"));
}
- pxfer[n] = NULL;
+ ppxfer[n] = NULL;
}
- if(error)
- {
+ if (parm.err) {
goto done;
}
- error = (udev->bus->methods->xfer_setup)
- (udev,iface_index,pxfer,setup_start,setup_end);
+ bzero(&parm, sizeof(parm));
+
+ parm.udev = udev;
+ parm.speed = usbd_get_speed(udev);
+ parm.hc_max_packet_count = 1;
+
+ if (parm.speed >= USB_SPEED_MAX) {
+ parm.err = USBD_INVAL;
+ goto done;
+ }
+
+ /* setup all transfers */
+
+ while (1) {
+
+ parm.size[0] = 0;
+ parm.size[1] = 0;
+ parm.buf = buf;
+
+ /* align data to 8 byte boundary */
+ parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN-1));
+
+ if (buf) {
+
+ info = USBD_ADD_BYTES(buf,parm.size[0]);
+
+ info->memory_base = buf;
+ info->memory_size = parm.total_size[0];
+
+ info->page_base = parm.page_ptr;
+ info->page_size = parm.total_size[1];
+
+ info->usb_mtx = &(udev->bus->mtx);
+
+ usbd_page_cache_init(&(parm.pc), parm.page_ptr,
+ 0, parm.total_size[1] * USB_PAGE_SIZE);
+ } else {
+ info = NULL;
+ }
+
+ parm.size[0] += sizeof(info[0]);
+
+ for (setup = setup_start, n = 0;
+ setup != setup_end; setup++, n++) {
+
+ /* store current setup pointer */
+ parm.curr_setup = setup;
+ /* align data to 8 byte boundary */
+ parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN-1));
- /* common setup */
+ if (buf) {
- for(setup = setup_start, n = n_setup; n--; setup++)
- {
- xfer = pxfer[n];
+ xfer = USBD_ADD_BYTES(buf,parm.size[0]);
- if(xfer)
- {
+ ppxfer[n] = xfer;
+ xfer->udev = udev;
+ xfer->address = udev->address;
xfer->priv_sc = priv_sc;
xfer->priv_mtx = priv_mtx;
- xfer->udev = udev;
+ xfer->usb_mtx = &(udev->bus->mtx);
+ xfer->usb_root = info;
+ info->memory_refcount++;
+ info->setup_refcount++;
+
+ __callout_init_mtx(&xfer->timeout_handle, xfer->usb_mtx,
+ CALLOUT_RETURNUNLOCKED);
+ } else {
+ /* dummy xfer */
+ xfer = &dummy;
+ bzero(&dummy, sizeof(dummy));
+ }
+
+ parm.size[0] += sizeof(xfer[0]);
+
+ xfer->pipe = usbd_get_pipe(udev, iface_index, setup);
+
+ if (!xfer->pipe) {
+ parm.err = USBD_NO_PIPE;
+ goto done;
+ }
+
+ if (buf) {
+ xfer->pipe->refcount++;
+ }
+
+ parm.methods = xfer->pipe->methods;
+ parm.curr_xfer = xfer;
- if(xfer->pipe)
- {
- xfer->pipe->refcount++;
- }
+ (udev->bus->methods->xfer_setup)(&parm);
- info = xfer->usb_root;
- info->memory_refcount++;
- info->setup_refcount++;
+ if (parm.err) {
+ goto done;
}
+ }
+
+ if (buf || parm.err) {
+ goto done;
+ }
+
+ /* compute number of USB pages required */
+ parm.total_size[1] =
+ (parm.size[1] + USB_PAGE_SIZE - 1) / USB_PAGE_SIZE;
+
+ /* align data to 8 byte boundary */
+ parm.size[0] += ((-parm.size[0]) & (USB_HOST_ALIGN-1));
+
+ /* store offset temporarily */
+ parm.size[2] = parm.size[0];
+
+ parm.size[0] += (sizeof(parm.page_ptr[0]) * parm.total_size[1]);
+
+ /* store total buffer size */
+ parm.total_size[0] = parm.size[0];
+
+ /* allocate zeroed memory */
+ buf = malloc(parm.total_size[0], M_USB, M_WAITOK|M_ZERO);
+
+ if (buf == NULL) {
+ parm.err = USBD_NOMEM;
+ PRINTFN(-1, ("cannot allocate memory block for "
+ "configuration (%d bytes)\n",
+ parm.total_size[0]));
+ goto done;
+ }
+
+ parm.page_ptr = USBD_ADD_BYTES(buf,parm.size[2]);
+
+ if (usbd_page_alloc(udev->bus->dma_tag,
+ parm.page_ptr, parm.total_size[1])) {
+ free(buf, M_USB);
+ parm.err = USBD_NOMEM;
+ PRINTFN(-1, ("cannot allocate memory block for "
+ "configuration (%d USB pages)\n",
+ parm.total_size[1]));
+ goto done;
+ }
}
done:
- if(error)
+ if (parm.err)
{
- usbd_transfer_unsetup(pxfer, n_setup);
+ usbd_transfer_unsetup(ppxfer, n_setup);
}
- return (error);
+ return (parm.err);
}
/*---------------------------------------------------------------------------*
@@ -467,183 +981,278 @@
return;
}
-void
-usbd_std_isoc_copy_in(struct usbd_xfer *xfer)
+/*------------------------------------------------------------------------*
+ * usbd_std_root_transfer - factored out code
+ *
+ * Return values:
+ * 0: Tried to do a callback and unlocked "xfer->usb_mtx"
+ * Else: Did nothing.
+ *------------------------------------------------------------------------*/
+uint8_t
+usbd_std_root_transfer(struct usbd_std_root_transfer *std,
+ struct thread *ctd,
+ usbd_std_root_transfer_func_t *func)
{
- u_int32_t x;
- u_int32_t length;
+ struct usbd_xfer *xlist[2];
+ struct usbd_xfer *xfer;
+ struct thread *td;
+ uint32_t len;
+ uint8_t shortpkt = 0;
+
+ xfer = std->xfer;
+ if (xfer == NULL) {
+ /* the transfer is gone */
+ return 1;
+ }
+
+ mtx_assert(xfer->usb_mtx, MA_OWNED);
- if (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) {
+ if (xfer->usb_thread != ctd) {
+ /* we should not call this transfer back */
+ return 1;
+ }
- length = 0;
+ std->xfer = NULL;
- for (x = 0; x < xfer->nframes; x++) {
- length += xfer->frlengths[x];
+ if (ctd == NULL) {
+ td = curthread;
+ } else {
+ td = ctd;
}
- /* only one copy is needed, hence
- * the frames are back to back:
- */
- usbd_copy_in(&(xfer->buf_data), 0, xfer->buffer, length);
+ /* make sure that the memory does not disappear! */
+ xfer->usb_thread = td;
+ xfer->usb_root->memory_refcount++;
+
+ if (xfer->flags_int.control_xfr &&
+ xfer->flags_int.control_hdr) {
+
+ /* copy out the USB request */
+
+ if (xfer->frlengths[0] == sizeof(std->req)) {
+ usbd_copy_out(xfer->frbuffers + 0, 0,
+ &(std->req), sizeof(std->req));
+ } else {
+ std->err = USBD_INVAL;
+ goto done;
+ }
+
+ xfer->aframes = 1;
+
+ std->err = 0;
+ std->state = USBD_STD_ROOT_TR_SETUP;
+
+ (func)(xfer, std);
- } else {
+ if (xfer->usb_thread != td) {
+ goto done;
+ }
- for (x = 0; x < xfer->nframes; x++) {
- xfer->frlengths_old[x] = xfer->frlengths[x];
+ if (std->err) {
+ goto done;
+ }
}
- }
- return;
-}
+
+ std->err = 0;
+ std->state = USBD_STD_ROOT_TR_PRE_DATA;
+
+ (func)(xfer, std);
-void
-usbd_std_isoc_copy_out(struct usbd_xfer *xfer)
-{
- u_int8_t *ptr;
- u_int32_t x;
- u_int32_t offset;
+ if (xfer->usb_thread != td) {
+ goto done;
+ }
- if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) {
+ if (std->err) {
+ goto done;
+ }
- ptr = xfer->buffer;
- offset = 0;
+ /* transfer data */
- for (x = 0; x < xfer->nframes; x++) {
+ while (xfer->aframes != xfer->nframes) {
- usbd_copy_out(&(xfer->buf_data), offset,
- ptr, xfer->frlengths[x]);
+ len = xfer->frlengths[xfer->aframes];
- ptr += xfer->frlengths_old[x];
- offset += xfer->frlengths_old[x];
- }
- }
- return;
-}
+ if (len > std->len) {
+ len = std->len;
+ shortpkt = 1;
+ }
-void
-usbd_std_bulk_intr_copy_in(struct usbd_xfer *xfer)
-{
- if (UE_GET_DIR(xfer->endpoint) == UE_DIR_OUT) {
+ if (len > 0) {
+ if ((xfer->endpoint & (UE_DIR_IN|UE_DIR_OUT)) == UE_DIR_IN) {
+ usbd_copy_in(xfer->frbuffers + xfer->aframes, 0,
+ std->ptr, len);
+ } else {
+ usbd_copy_out(xfer->frbuffers + xfer->aframes, 0,
+ std->ptr, len);
+ }
+ }
- usbd_copy_in(&(xfer->buf_data), 0,
- xfer->buffer, xfer->length);
- }
- return;
-}
+ std->ptr += len;
+ std->len -= len;
+ xfer->frlengths[xfer->aframes] = len;
+ xfer->aframes ++;
-void
-usbd_std_bulk_intr_copy_out(struct usbd_xfer *xfer)
-{
- if (UE_GET_DIR(xfer->endpoint) == UE_DIR_IN) {
+ if (shortpkt) {
+ break;
+ }
+ }
- usbd_copy_out(&(xfer->buf_data), 0,
- xfer->buffer, xfer->actlen);
- }
- return;
-}
+ std->err = 0;
+ std->state = USBD_STD_ROOT_TR_POST_DATA;
-void
-usbd_std_ctrl_copy_in(struct usbd_xfer *xfer)
-{
- u_int32_t len = xfer->length;
- usb_device_request_t *req;
+ (func)(xfer, std);
- if (xfer->control_remainder == 0) {
- req = xfer->buffer;
- if ((len >= sizeof(*req)) &&
- (req->bmRequestType & UT_READ)) {
- len = sizeof(*req);
+ if (xfer->usb_thread != td) {
+ goto done;
}
- } else {
- if (xfer->control_isread) {
- return;
+
+ if (std->err) {
+ goto done;
}
- }
+
+ if (xfer->flags_int.control_xfr &&
+ !xfer->flags_int.control_act) {
+
+ std->err = 0;
+ std->state = USBD_STD_ROOT_TR_STATUS;
- usbd_copy_in(&(xfer->buf_data), 0,
- xfer->buffer, len);
- return;
-}
+ (func)(xfer, std);
-void
-usbd_std_ctrl_copy_out(struct usbd_xfer *xfer)
-{
- u_int32_t len = xfer->actlen;
- usb_device_request_t *req;
+ if (xfer->usb_thread != td) {
+ goto done;
+ }
- if (xfer->flags & USBD_DEV_CONTROL_HEADER) {
- req = xfer->buffer;
- if ((len >= sizeof(*req)) &&
- (req->bmRequestType & UT_READ)) {
- /* copy out everything, but the header */
- usbd_copy_out(&(xfer->buf_data), sizeof(*req),
- (req+1), len - sizeof(*req));
+ if (std->err) {
+ goto done;
+ }
}
- } else {
- if (xfer->control_isread) {
- /* copy out everything */
- usbd_copy_out(&(xfer->buf_data), 0,
- xfer->buffer, len);
+
+ done:
+ /* check if we are still handling this USB transfer */
+
+ if (xfer->usb_thread == td) {
+ std->state = USBD_STD_ROOT_TR_PRE_CALLBACK;
+ (func)(xfer, std);
}
- }
- return;
+
+ /* queue callback */
+ xlist[0] = xfer;
+ xlist[1] = NULL;
+
+ mtx_unlock(xfer->usb_mtx);
+
+ /*
+ * NOTE: "usbd_do_callback()" will decrement
+ * the "memory_refcount" and must be called.
+ */
+ usbd_do_callback(xlist, td);
+
+ return 0;
}
-uint8_t
-usbd_std_ctrl_enter(struct usbd_xfer *xfer)
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list