USB stack driver options for the receive side question
Nidal Khalil
nedmath at gmail.com
Tue Oct 28 02:50:28 UTC 2014
Hello All,
I am setting up usb to transfer 3 frames on the bulk read desriptor but all
I get is one frame transferred?
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 i the only one availble and at
most three buffers at a time if the transfer is complete.
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 recieve 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-hackers
mailing list