USB stack driver options for the receive side question

Nidal Khalil nedmath at gmail.com
Tue Oct 28 03:03:15 UTC 2014


Hello All,
I am setting up usb to transfer 3 frames on the bulk read descriptor but
all I get is one frame transferred? Basically aframe = 1

However if I use .short_frames_ok = 1, then the transfer will pend till the
three frames are received. This code is part of a network driver
I would like to receive the one buffer it is the only one available and at
most three buffers at a time if the transfer is complete.
The one frame a time to respond to ping and three frame at time when the
transfer load is heavy.

Is this a limitation of FreeBSD.
I searched all the drivers in the 9.3 release and I can not find a driver
that is setup to receive multiple buffers?

Below is my sample code:

BWL_BULK_RD] = {

                .type      = UE_BULK,

                .endpoint  = UE_ADDR_ANY,

                .direction = UE_DIR_IN,

                .bufsize   = 2000 * HW_IN_PENDING_FRAMES,

                .flags     = {

                        .pipe_bof = 1, .short_xfer_ok = 1, .ext_buffer = 1

                },

                .callback  = dbus_usbos_recv_callback,

                .timeout   = 0,        /* no timeout */

                .frames    = HW_IN_PENDING_FRAMES

        },





static void

dbus_usbos_recv_callback(CALLBACK_ARGS)

{

        usbos_info_t *usbos_info = usbd_xfer_softc(xfer);

        struct bwl_rx_data *data;

        int actlen, sumlen, aframes, nframes, datalen, nr_frames;

        uint8 *buf;

        struct timespec tp;



        DBUSTRACE(("%s(): Enter \n", __FUNCTION__));

        usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, &nframes);



        switch (USB_GET_STATE(xfer)) {



                case USB_ST_TRANSFERRED:

                        for (nr_frames = 0; nr_frames != aframes;
nr_frames++) {

                                FETCH_LIST_HEAD_ITEM(rx_q_lock, rx_q);

                                if (!data) {

                                        DBUSERR(("got xfer frame but the
rx_q till end ?? \n"));

                                        ASSERT(0);

                                }

                                usbd_xfer_frame_data(xfer, nr_frames,
(void**)&buf, &datalen);

                                kern_clock_gettime(curthread,
CLOCK_UPTIME_PRECISE, &tp);

                                mylog(&glog, "T %p: %d-%d:%u\n", buf,
datalen, tp.tv_sec, tp.tv_nsec);

                                if ((data->rxirb->buf != buf) ||
(data->rxirb->buf_len < datalen)) {

                                        DBUSERR(("the buff or data length
not match ?? \n"));

                                        ASSERT(0);

                                }

                                MUTEX_UNLOCK(usbos_info);

                                dbus_usbos_recv_complete(data, datalen,
DBUS_OK);

                                MUTEX_LOCK(usbos_info);

                        }

                        __transfered += nr_frames;

                        /* no break, FALLTHROUGH */



                case USB_ST_SETUP:

SET_UP_XFER:

                        nr_frames = 0;

                        mtx_lock(&usbos_info->rx_q_lock);

                        STAILQ_FOREACH(data, &usbos_info->rx_q, next) {

                                if (data->rxirb == NULL)

                                        break;

                                kern_clock_gettime(curthread,
CLOCK_UPTIME_PRECISE, &tp);

                                mylog(&glog, "S %p:%d-%d:%u\n",
data->rxirb->buf,

                                        data->rxirb->buf_len, tp.tv_sec,
tp.tv_nsec);

                                usbd_xfer_set_frame_data(xfer, nr_frames,

                                        data->rxirb->buf,
data->rxirb->buf_len);

                                ++nr_frames;

                                if (nr_frames >= BCMWL_HW_IN_PENDING_FRAMES)

                                        break; /* break out from
STAILQ_FOREACH */

                        }

                        mtx_unlock(&usbos_info->rx_q_lock);



                        if (nr_frames) {

                                usbd_xfer_set_frames(xfer, nr_frames);

                                usbd_transfer_submit(xfer);

                        } else {

                                printf("%s(): end of rx_q \n",
__FUNCTION__);

                        }

                        __setup += nr_frames;

                        break;



                default:

                        DBUSERR(("%s(): error = %s with %d bytes
transfered\n",

                                __FUNCTION__, usbd_errstr(error), actlen));



                        if (error == USB_ERR_STALLED || error ==
USB_ERR_IOERROR) {

                                printf("%s(): calling DBUS_STATE_DOWN for
%s\n",

                                        __FUNCTION__, usbd_errstr(error));

                                dbus_usbos_state_change(usbos_info,
DBUS_STATE_DOWN);

                        }



                        if ((error != USB_ERR_CANCELLED) && (error !=
USB_ERR_STALLED)) {

                                usbd_xfer_set_stall(xfer);

                                goto SET_UP_XFER;

                        } else {

                                /* return all rxirb in the queue */

                                MUTEX_UNLOCK(usbos_info);

                                mtx_lock(&usbos_info->rx_q_lock);

                                while ((data =
STAILQ_FIRST(&usbos_info->rx_q)) != NULL) {


STAILQ_REMOVE_HEAD(&usbos_info->rx_q, next);

                                        dbus_usbos_recv_complete(data, 0,
DBUS_ERR_RXFAIL);

                                }

                                STAILQ_INIT(&usbos_info->rx_q);

                                mtx_unlock(&usbos_info->rx_q_lock);

                                MUTEX_LOCK(usbos_info);

                        }



                        break;

        }



}


More information about the freebsd-usb mailing list