From owner-p4-projects@FreeBSD.ORG Sun Sep 23 14:22:58 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id EEE3C16A420; Sun, 23 Sep 2007 14:22:57 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6DA0016A419 for ; Sun, 23 Sep 2007 14:22:57 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 4FA7513C45D for ; Sun, 23 Sep 2007 14:22:57 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l8NEMvAB086180 for ; Sun, 23 Sep 2007 14:22:57 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l8NEMuZo086177 for perforce@freebsd.org; Sun, 23 Sep 2007 14:22:56 GMT (envelope-from hselasky@FreeBSD.org) Date: Sun, 23 Sep 2007 14:22:56 GMT Message-Id: <200709231422.l8NEMuZo086177@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 126732 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Sep 2007 14:22:58 -0000 http://perforce.freebsd.org/chv.cgi?CH=126732 Change 126732 by hselasky@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) <<<