DM USB: re-implement the data block process logic

In Windows OS, there are many non-data blocks (EVENT DATA) during the USB
data transfer process, which is very different from the Linux conterpart.
To support both OS, the data processing logic is changed with the help of
newly introduced enum usb_block_type.

Tracked-On: #3628
Signed-off-by: Xiaoguang Wu <xiaoguang.wu@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Xiaoguang Wu 2019-09-09 17:31:29 +08:00 committed by wenlingz
parent 236c23e418
commit d58a766556
2 changed files with 109 additions and 116 deletions

View File

@ -172,8 +172,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
struct usb_block *block; struct usb_block *block;
struct usb_native_devinfo *info; struct usb_native_devinfo *info;
int do_intr = 0; int do_intr = 0;
int i, j, idx, buf_idx, done; int i, idx, buf_idx, done;
int bstart, bcount;
int is_stalled = 0; int is_stalled = 0;
int framelen = 0; int framelen = 0;
uint16_t maxp; uint16_t maxp;
@ -196,16 +195,12 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
framelen = USB_EP_MAXP_SZ(maxp) * (1 + USB_EP_MAXP_MT(maxp)); framelen = USB_EP_MAXP_SZ(maxp) * (1 + USB_EP_MAXP_MT(maxp));
UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen); UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen);
} }
bstart = r->blk_start;
bcount = r->blk_count;
UPRINTF(LDBG, "%s: %d-%s: actlen %d ep%d-xfr [%d-%d %d] rq-%d " UPRINTF(LDBG, "%s: %d-%s: actlen %d ep%d-xfr [%d-%d %d] rq-%d "
"[%d-%d %d] st %d\r\n", __func__, info->path.bus, "[%d-%d %d] st %d\r\n", __func__, info->path.bus,
usb_dev_path(&info->path), trn->actual_length, usb_dev_path(&info->path), trn->actual_length,
xfer->epid, xfer->head, xfer->epid, xfer->head, xfer->tail, xfer->ndata,
(xfer->tail - 1) % USB_MAX_XFER_BLOCKS, r->seq, r->blk_head, r->blk_tail, r->buf_size,
xfer->ndata, r->seq, bstart, trn->status);
(bstart + bcount - 1) % USB_MAX_XFER_BLOCKS,
r->buf_length, trn->status);
/* lock for protecting the transfer */ /* lock for protecting the transfer */
xfer->status = USB_ERR_NORMAL_COMPLETION; xfer->status = USB_ERR_NORMAL_COMPLETION;
@ -246,28 +241,28 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
trn->iso_packet_desc[i].actual_length); trn->iso_packet_desc[i].actual_length);
/* handle the blocks belong to this request */ /* handle the blocks belong to this request */
i = j = 0; i = 0;
buf_idx = 0;
idx = r->blk_start;
buf = r->buffer; buf = r->buffer;
idx = r->blk_head;
buf_idx = 0;
done = trn->actual_length; done = trn->actual_length;
while (i < r->blk_count) { while ((r->blk_head <= r->blk_tail && idx >= r->blk_head &&
idx < r->blk_tail) || ((r->blk_head > r->blk_tail) &&
((idx >= r->blk_head && idx < USB_MAX_XFER_BLOCKS) ||
(idx >= 0 && idx < r->blk_tail)))) {
if (trn->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { if (trn->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
buf_idx = 0; buf_idx = 0;
buf = libusb_get_iso_packet_buffer_simple(trn, j); buf = libusb_get_iso_packet_buffer_simple(trn, i);
done = trn->iso_packet_desc[j].actual_length; done = trn->iso_packet_desc[i].actual_length;
j++; i++;
} }
do { do {
int d; int d;
if (i >= r->blk_count) block = &xfer->data[idx];
break; if (block->stat == USB_BLOCK_FREE &&
block->type != USB_DATA_NONE)
block = &xfer->data[idx % USB_MAX_XFER_BLOCKS];
if (block->stat == USB_BLOCK_FREE)
UPRINTF(LFTL, "error: found free block\r\n"); UPRINTF(LFTL, "error: found free block\r\n");
d = done; d = done;
@ -283,7 +278,6 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
} else { } else {
/* Link TRB */ /* Link TRB */
i--; i--;
j--;
} }
done -= d; done -= d;
@ -291,16 +285,21 @@ usb_dev_comp_cb(struct libusb_transfer *trn)
block->bdone = d; block->bdone = d;
block->stat = USB_BLOCK_HANDLED; block->stat = USB_BLOCK_HANDLED;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
i++;
} while (block->type == USB_DATA_PART); } while (block->type == USB_DATA_PART);
} }
stall_out: stall_out:
if (is_stalled) { if (is_stalled) {
for (i = 0, idx = r->blk_start; i < r->blk_count; ++i) { idx = r->blk_head;
block = &xfer->data[idx % USB_MAX_XFER_BLOCKS];
while ((r->blk_head <= r->blk_tail && idx >= r->blk_head &&
idx < r->blk_tail) || ((r->blk_head > r->blk_tail) &&
((idx >= r->blk_head && idx < USB_MAX_XFER_BLOCKS) ||
(idx >= 0 && idx < r->blk_tail)))) {
block = &xfer->data[idx];
block->stat = USB_BLOCK_HANDLED; block->stat = USB_BLOCK_HANDLED;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
} }
} }
@ -320,7 +319,7 @@ cancel_out:
if (r && r->buffer) if (r && r->buffer)
free(r->buffer); free(r->buffer);
xfer->requests[r->blk_start] = NULL; xfer->requests[r->blk_head] = NULL;
free(r); free(r);
free_transfer: free_transfer:
libusb_free_transfer(trn); libusb_free_transfer(trn);
@ -367,53 +366,44 @@ errout:
} }
static int static int
usb_dev_prepare_xfer(struct usb_xfer *xfer, int *count, int *size) usb_dev_prepare_xfer(struct usb_xfer *xfer, int *head, int *tail)
{ {
int found, i, idx, c, s, first; int i, idx, size, first;
struct usb_block *block = NULL; struct usb_block *block = NULL;
idx = xfer->head; idx = xfer->head;
found = 0;
first = -1; first = -1;
c = s = 0; size = 0;
if (!count || !size || idx < 0 || idx >= USB_MAX_XFER_BLOCKS) if (idx < 0 || idx >= USB_MAX_XFER_BLOCKS)
return -1; return -1;
for (i = 0; i < xfer->ndata; i++) { for (i = 0; i < xfer->ndata; i++, idx = (idx + 1) % USB_MAX_XFER_BLOCKS)
{
block = &xfer->data[idx]; block = &xfer->data[idx];
if (block->stat == USB_BLOCK_HANDLED || if (block->stat == USB_BLOCK_HANDLED ||
block->stat == USB_BLOCK_HANDLING) { block->stat == USB_BLOCK_HANDLING)
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue; continue;
}
if (block->type == USB_DATA_PART || first = (first < 0) ? idx : first;
block->type == USB_DATA_FULL) {
if (!found) { switch (block->type) {
found = 1; case USB_DATA_PART:
first = idx; case USB_DATA_FULL:
} size += block->blen;
c++;
s += block->blen;
} else if (block->type == USB_DATA_NONE) {
/* there are two cases:
* 1. LINK trb is in the middle of trbs.
* 2. LINK trb is a single trb.
*/
block->stat = USB_BLOCK_HANDLED;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue;
} else if (found) {
UPRINTF(LWRN, "find a NULL data. %d total %d\n",
i, xfer->ndata);
}
block->stat = USB_BLOCK_HANDLING; block->stat = USB_BLOCK_HANDLING;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; break;
case USB_DATA_NONE:
block->stat = USB_BLOCK_HANDLED;
continue;
default:
UPRINTF(LFTL, "%s error stat %d\r\n",
__func__, block->type);
}
} }
*count = c; *head = first;
*size = s; *tail = xfer->tail;
return first; return size;
} }
static inline int static inline int
@ -757,8 +747,7 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
struct usb_native_devinfo *info; struct usb_native_devinfo *info;
int rc = 0, epid; int rc = 0, epid;
uint8_t type; uint8_t type;
int blk_start, data_size, blk_count; int i, idx, buf_idx, head, tail, size;
int i, j, idx, buf_idx;
struct usb_block *b; struct usb_block *b;
static const char * const type_str[] = {"CTRL", "ISO", "BULK", "INT"}; static const char * const type_str[] = {"CTRL", "ISO", "BULK", "INT"};
static const char * const dir_str[] = {"OUT", "IN"}; static const char * const dir_str[] = {"OUT", "IN"};
@ -768,9 +757,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
udev = pdata; udev = pdata;
info = &udev->info; info = &udev->info;
xfer->status = USB_ERR_NORMAL_COMPLETION; xfer->status = USB_ERR_NORMAL_COMPLETION;
size = usb_dev_prepare_xfer(xfer, &head, &tail);
blk_start = usb_dev_prepare_xfer(xfer, &blk_count, &data_size); if (size <= 0)
if (blk_start < 0)
goto done; goto done;
type = usb_dev_get_ep_type(udev, dir ? TOKEN_IN : TOKEN_OUT, epctx); type = usb_dev_get_ep_type(udev, dir ? TOKEN_IN : TOKEN_OUT, epctx);
@ -793,97 +781,102 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx)
framelen = USB_EP_MAXP_SZ(maxp) * (1 + USB_EP_MAXP_MT(maxp)); framelen = USB_EP_MAXP_SZ(maxp) * (1 + USB_EP_MAXP_MT(maxp));
UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen); UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen);
for (i = 0, idx = blk_start; i < blk_count; i++) { idx = head;
while (((head <= tail && idx >= head && idx < tail) ||
((idx >= head && idx < USB_MAX_XFER_BLOCKS) ||
(idx >= 0 && idx < tail)))) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
if (xfer->data[idx].blen > framelen) if (xfer->data[idx].blen > framelen)
UPRINTF(LFTL, "err framelen %d\r\n", framelen); UPRINTF(LFTL, "err framelen %d\r\n", framelen);
if (xfer->data[idx].blen <= 0) { if (xfer->data[idx].type == USB_DATA_NONE ||
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; xfer->data[idx].type == USB_DATA_PART)
i--;
continue; continue;
} else if (xfer->data[idx].type == USB_DATA_FULL)
if (xfer->data[idx].type == USB_DATA_PART) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
continue;
}
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
framecnt++; framecnt++;
else
UPRINTF(LFTL, "%s:%d error\r\n", __func__, __LINE__);
} }
UPRINTF(LDBG, "iso maxp %u framelen %d, framecnt %d\r\n", maxp, UPRINTF(LDBG, "iso maxp %u framelen %d, framecnt %d\r\n", maxp,
framelen, framecnt); framelen, framecnt);
} }
if (data_size <= 0) r = usb_dev_alloc_req(udev, xfer, dir, size, type ==
goto done;
r = usb_dev_alloc_req(udev, xfer, dir, data_size, type ==
USB_ENDPOINT_ISOC ? framecnt : 0); USB_ENDPOINT_ISOC ? framecnt : 0);
if (!r) { if (!r) {
xfer->status = USB_ERR_IOERROR; xfer->status = USB_ERR_IOERROR;
goto done; goto done;
} }
r->buf_length = data_size; r->buf_size = size;
r->blk_start = blk_start; r->blk_head = head;
r->blk_count = blk_count; r->blk_tail = tail;
xfer->requests[blk_start] = r; xfer->requests[head] = r;
UPRINTF(LDBG, "%s: %d-%s: explen %d ep%d-xfr [%d-%d %d] rq-%d " UPRINTF(LDBG, "%s: %d-%s: explen %d ep%d-xfr [%d-%d %d] rq-%d "
"[%d-%d %d] dir %s type %s\r\n", __func__, "[%d-%d %d] dir %s type %s\r\n", __func__,
info->path.bus, usb_dev_path(&info->path), info->path.bus, usb_dev_path(&info->path), size, epctx,
data_size, epctx, xfer->head, (xfer->tail - 1) % xfer->head, xfer->tail, xfer->ndata, r->seq,
USB_MAX_XFER_BLOCKS, xfer->ndata, r->seq, blk_start, r->blk_head, r->blk_tail, r->buf_size, dir_str[dir],
(blk_start + blk_count - 1) % USB_MAX_XFER_BLOCKS, type_str[type]);
data_size, dir_str[dir], type_str[type]);
if (!dir) { if (!dir) {
for (i = 0, j = 0, buf_idx = 0; j < blk_count; ++i) { idx = head;
b = &xfer->data[(blk_start + i) % USB_MAX_XFER_BLOCKS]; buf_idx = 0;
if (b->type == USB_DATA_FULL || while (((head <= tail && idx >= head && idx < tail) ||
b->type == USB_DATA_PART) { ((idx >= head && idx < USB_MAX_XFER_BLOCKS) ||
(idx >= 0 && idx < tail)))) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
b = &xfer->data[idx];
if (b->type == USB_DATA_PART ||
b->type == USB_DATA_FULL) {
memcpy(&r->buffer[buf_idx], b->buf, b->blen); memcpy(&r->buffer[buf_idx], b->buf, b->blen);
buf_idx += b->blen; buf_idx += b->blen;
j++;
} }
} }
} }
if (type == USB_ENDPOINT_ISOC) { if (type == USB_ENDPOINT_ISOC) {
for (i = 0, j = 0, idx = blk_start; i < blk_count; ++i) { idx = head;
int len = xfer->data[idx].blen; while ((head <= tail && idx >= head && idx < tail) ||
((idx >= head && idx < USB_MAX_XFER_BLOCKS) ||
(idx >= 0 && idx < tail))) {
int len;
i = 0;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
len = xfer->data[idx].blen;
if (xfer->data[idx].type == USB_DATA_NONE) { if (xfer->data[idx].type == USB_DATA_NONE) {
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
i--;
continue; continue;
} else if (xfer->data[idx].type == USB_DATA_PART) {
r->trn->iso_packet_desc[i].length += len;
continue;
} else if (xfer->data[idx].type == USB_DATA_FULL) {
r->trn->iso_packet_desc[i].length += len;
} else {
UPRINTF(LFTL, "%s:%d error\r\n",
__func__, __LINE__);
} }
if (xfer->data[idx].type == USB_DATA_PART) { UPRINTF(LDBG, "desc[%d].length %d\r\n", i,
r->trn->iso_packet_desc[j].length += len; r->trn->iso_packet_desc[i].length);
idx = (idx + 1) % USB_MAX_XFER_BLOCKS; i++;
continue;
}
r->trn->iso_packet_desc[j].length += len;
idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
UPRINTF(LDBG, "desc[%d].length %d\r\n", j,
r->trn->iso_packet_desc[j].length);
j++;
} }
} }
if (type == USB_ENDPOINT_BULK) { if (type == USB_ENDPOINT_BULK) {
libusb_fill_bulk_transfer(r->trn, udev->handle, epid, libusb_fill_bulk_transfer(r->trn, udev->handle, epid,
r->buffer, data_size, usb_dev_comp_cb, r, 0); r->buffer, size, usb_dev_comp_cb, r, 0);
} else if (type == USB_ENDPOINT_INT) { } else if (type == USB_ENDPOINT_INT) {
libusb_fill_interrupt_transfer(r->trn, udev->handle, epid, libusb_fill_interrupt_transfer(r->trn, udev->handle, epid,
r->buffer, data_size, usb_dev_comp_cb, r, 0); r->buffer, size, usb_dev_comp_cb, r, 0);
} else if (type == USB_ENDPOINT_ISOC) { } else if (type == USB_ENDPOINT_ISOC) {
libusb_fill_iso_transfer(r->trn, udev->handle, epid, libusb_fill_iso_transfer(r->trn, udev->handle, epid,
r->buffer, data_size, framecnt, r->buffer, size, framecnt,
usb_dev_comp_cb, r, 0); usb_dev_comp_cb, r, 0);
} else { } else {

View File

@ -73,9 +73,9 @@ struct usb_dev_req {
* so here need some data to record it. * so here need some data to record it.
*/ */
uint8_t *buffer; uint8_t *buffer;
int buf_length; int buf_size;
int blk_start; int blk_head;
int blk_count; int blk_tail;
struct usb_xfer *xfer; struct usb_xfer *xfer;
struct libusb_transfer *trn; struct libusb_transfer *trn;