diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 2b41e80a5..ebb468469 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -1554,19 +1554,66 @@ pci_xhci_deassert_interrupt(struct pci_xhci_vdev *xdev) static struct usb_xfer * pci_xhci_alloc_usb_xfer(struct pci_xhci_dev_emu *dev, int epid) { - int i; struct usb_xfer *xfer; + struct xhci_dev_ctx *dev_ctx; + struct xhci_endp_ctx *ep_ctx; + int dir, max_blk_cnt, i = 0; + uint8_t type; + + if (!dev) + return NULL; + + dev_ctx = dev->dev_ctx; + ep_ctx = &dev_ctx->ctx_ep[epid]; + type = XHCI_EPCTX_1_EPTYPE_GET(ep_ctx->dwEpCtx1); + + /* TODO: + * The following code is still not perfect, due to fixed values are + * not flexible and the overflow risk is still existed. Will try to + * find a dynamic way could work both for Linux and Windows. + */ + switch (type) { + case XHCI_EPTYPE_CTRL: + case XHCI_EPTYPE_INT_IN: + case XHCI_EPTYPE_INT_OUT: + max_blk_cnt = 128; + break; + case XHCI_EPTYPE_BULK_IN: + case XHCI_EPTYPE_BULK_OUT: + max_blk_cnt = 1024; + break; + case XHCI_EPTYPE_ISOC_IN: + case XHCI_EPTYPE_ISOC_OUT: + max_blk_cnt = 2048; + break; + default: + UPRINTF(LFTL, "err: unexpected epid %d type %d dir %d\r\n", + epid, type, dir); + return NULL; + } xfer = calloc(1, sizeof(struct usb_xfer)); if (!xfer) return NULL; - for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) { + xfer->reqs = calloc(max_blk_cnt, sizeof(struct usb_dev_req *)); + if (!xfer->reqs) + goto fail; + + xfer->data = calloc(max_blk_cnt, sizeof(struct usb_block)); + if (!xfer->data) + goto fail; + + for (i = 0; i < max_blk_cnt; ++i) { xfer->data[i].hcb = calloc(1, sizeof(struct xhci_block)); if (!xfer->data[i].hcb) goto fail; } + UPRINTF(LINF, "allocate %d blocks for epid %d type %d dir %d\r\n", + max_blk_cnt, epid, type, dir); + + xfer->max_blk_cnt = max_blk_cnt; xfer->dev = (void *)dev; xfer->epid = epid; return xfer; @@ -1574,6 +1621,9 @@ pci_xhci_alloc_usb_xfer(struct pci_xhci_dev_emu *dev, int epid) fail: for (; i >= 0; i--) free(xfer->data[i].hcb); + + free(xfer->data); + free(xfer->reqs); free(xfer); return NULL; } @@ -1586,15 +1636,12 @@ pci_xhci_free_usb_xfer(struct usb_xfer *xfer) if (!xfer) return; - for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) { + for (i = 0; i < xfer->max_blk_cnt; i++) free(xfer->data[i].hcb); - xfer->data[i].hcb = NULL; - } - if (xfer->ureq) { - free(xfer->ureq); - xfer->ureq = NULL; - } + free(xfer->data); + free(xfer->reqs); + free(xfer->ureq); free(xfer); } @@ -2292,8 +2339,8 @@ pci_xhci_cmd_reset_ep(struct pci_xhci_vdev *xdev, pthread_mutex_lock(&devep->mtx); xfer = devep->ep_xfer; - for (i = 0; i < USB_MAX_XFER_BLOCKS; ++i) { - r = xfer->requests[i]; + for (i = 0; i < xfer->max_blk_cnt; ++i) { + r = xfer->reqs[i]; if (r && r->trn) /* let usb_dev_comp_req to free the memory */ libusb_cancel_transfer(r->trn); @@ -2744,13 +2791,13 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer, xfer->data[i].stat = USB_BLOCK_FREE; xfer->ndata--; - xfer->head = index_inc(xfer->head, USB_MAX_XFER_BLOCKS); + xfer->head = index_inc(xfer->head, xfer->max_blk_cnt); edtla += xfer->data[i].bdone; trb->dwTrb3 = (trb->dwTrb3 & ~0x1) | (hcb->ccs); if (xfer->data[i].type == USB_DATA_PART) { rem_len += xfer->data[i].blen; - i = index_inc(i, USB_MAX_XFER_BLOCKS); + i = index_inc(i, xfer->max_blk_cnt); /* This 'continue' will delay the IOC behavior which * could decrease the number of virtual interrupts. @@ -2769,7 +2816,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer, !((err == XHCI_TRB_ERROR_SHORT_PKT) && (trb->dwTrb3 & XHCI_TRB_3_ISP_BIT))) { - i = index_inc(i, USB_MAX_XFER_BLOCKS); + i = index_inc(i, xfer->max_blk_cnt); continue; } @@ -2794,7 +2841,7 @@ pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev, struct usb_xfer *xfer, if (err != XHCI_TRB_ERROR_SUCCESS) break; - i = index_inc(i, USB_MAX_XFER_BLOCKS); + i = index_inc(i, xfer->max_blk_cnt); rem_len = 0; } diff --git a/devicemodel/hw/platform/usb_mouse.c b/devicemodel/hw/platform/usb_mouse.c index d515e7221..475e3515d 100644 --- a/devicemodel/hw/platform/usb_mouse.c +++ b/devicemodel/hw/platform/usb_mouse.c @@ -336,7 +336,7 @@ umouse_request(void *scarg, struct usb_xfer *xfer) } xfer->data[idx].stat = USB_BLOCK_HANDLED; - idx = index_inc(idx, USB_MAX_XFER_BLOCKS); + idx = index_inc(idx, xfer->max_blk_cnt); } err = USB_ERR_NORMAL_COMPLETION; @@ -716,7 +716,7 @@ umouse_data_handler(void *scarg, struct usb_xfer *xfer, int dir, data->stat = USB_BLOCK_HANDLED; data = NULL; - idx = index_inc(idx, USB_MAX_XFER_BLOCKS); + idx = index_inc(idx, xfer->max_blk_cnt); } if (!data) goto done; diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c index 3a97fb8c4..2b60c7b74 100644 --- a/devicemodel/hw/platform/usb_pmapper.c +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -18,7 +18,6 @@ #define LOG_TAG "USBPM: " static struct usb_dev_sys_ctx_info g_ctx; -static uint8_t usb_dev_get_ep_type(struct usb_dev *udev, int pid, int epnum); static uint16_t usb_dev_get_ep_maxp(struct usb_dev *udev, int pid, int epnum); static bool @@ -246,8 +245,8 @@ usb_dev_comp_cb(struct libusb_transfer *trn) idx = r->blk_head; buf_idx = 0; done = trn->actual_length; - while (index_valid(r->blk_head, r->blk_tail, USB_MAX_XFER_BLOCKS, idx)) - { + + while (index_valid(r->blk_head, r->blk_tail, xfer->max_blk_cnt, idx)) { if (trn->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) { buf_idx = 0; buf = libusb_get_iso_packet_buffer_simple(trn, i); @@ -281,7 +280,7 @@ usb_dev_comp_cb(struct libusb_transfer *trn) block->blen -= d; block->bdone = d; block->stat = USB_BLOCK_HANDLED; - idx = index_inc(idx, USB_MAX_XFER_BLOCKS); + idx = index_inc(idx, xfer->max_blk_cnt); } while (block->type == USB_DATA_PART); } @@ -290,10 +289,10 @@ stall_out: if (is_stalled) { idx = r->blk_head; while (index_valid(r->blk_head, r->blk_tail, - USB_MAX_XFER_BLOCKS, idx)) { + xfer->max_blk_cnt, idx)) { block = &xfer->data[idx]; block->stat = USB_BLOCK_HANDLED; - idx = index_inc(idx, USB_MAX_XFER_BLOCKS); + idx = index_inc(idx, xfer->max_blk_cnt); } } @@ -313,7 +312,7 @@ cancel_out: if (r && r->buffer) free(r->buffer); - xfer->requests[r->blk_head] = NULL; + xfer->reqs[r->blk_head] = NULL; free(r); free_transfer: libusb_free_transfer(trn); @@ -368,11 +367,11 @@ usb_dev_prepare_xfer(struct usb_xfer *xfer, int *head, int *tail) idx = xfer->head; first = -1; size = 0; - if (idx < 0 || idx >= USB_MAX_XFER_BLOCKS) + if (idx < 0 || idx >= xfer->max_blk_cnt) return -1; for (i = 0; i < xfer->ndata; - i++, idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) { + i++, idx = index_inc(idx, xfer->max_blk_cnt)) { block = &xfer->data[idx]; if (block->stat == USB_BLOCK_HANDLED || block->stat == USB_BLOCK_HANDLING) @@ -701,7 +700,7 @@ usb_dev_prepare_ctrl_xfer(struct usb_xfer *xfer) idx = xfer->head; - if (idx < 0 || idx >= USB_MAX_XFER_BLOCKS) + if (idx < 0 || idx >= xfer->max_blk_cnt) return NULL; for (i = 0; i < xfer->ndata; i++) { @@ -714,7 +713,7 @@ usb_dev_prepare_ctrl_xfer(struct usb_xfer *xfer) ret = blk; blk->stat = USB_BLOCK_HANDLED; - idx = index_inc(idx, USB_MAX_XFER_BLOCKS); + idx = index_inc(idx, xfer->max_blk_cnt); } return ret; } @@ -776,8 +775,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx) UPRINTF(LDBG, "iso maxp %u framelen %d\r\n", maxp, framelen); for (idx = head; - index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx); - idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) { + index_valid(head, tail, xfer->max_blk_cnt, idx); + idx = index_inc(idx, xfer->max_blk_cnt)) { if (xfer->data[idx].blen > framelen) UPRINTF(LFTL, "err framelen %d\r\n", framelen); @@ -804,7 +803,7 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx) r->buf_size = size; r->blk_head = head; r->blk_tail = tail; - xfer->requests[head] = r; + xfer->reqs[head] = r; 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__, info->path.bus, usb_dev_path(&info->path), size, epctx, @@ -814,8 +813,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx) if (!dir) { for (idx = head, buf_idx = 0; - index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx); - idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) { + index_valid(head, tail, xfer->max_blk_cnt, idx); + idx = index_inc(idx, xfer->max_blk_cnt)) { b = &xfer->data[idx]; if (b->type == USB_DATA_PART || b->type == USB_DATA_FULL) { @@ -827,8 +826,8 @@ usb_dev_data(void *pdata, struct usb_xfer *xfer, int dir, int epctx) if (type == USB_ENDPOINT_ISOC) { for (i = 0, idx = head; - index_valid(head, tail, USB_MAX_XFER_BLOCKS, idx); - idx = index_inc(idx, USB_MAX_XFER_BLOCKS)) { + index_valid(head, tail, xfer->max_blk_cnt, idx); + idx = index_inc(idx, xfer->max_blk_cnt)) { int len = xfer->data[idx].blen; if (xfer->data[idx].type == USB_DATA_NONE) { diff --git a/devicemodel/hw/usb_core.c b/devicemodel/hw/usb_core.c index c2c7d1e18..e49c9d201 100644 --- a/devicemodel/hw/usb_core.c +++ b/devicemodel/hw/usb_core.c @@ -106,7 +106,7 @@ usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb, { struct usb_block *xb; - if (xfer->ndata >= USB_MAX_XFER_BLOCKS) + if (xfer->ndata >= xfer->max_blk_cnt) return NULL; if (hcb == NULL) @@ -120,7 +120,7 @@ usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb, xb->bdone = 0; xb->type = USB_DATA_NONE; xfer->ndata++; - xfer->tail = index_inc(xfer->tail, USB_MAX_XFER_BLOCKS); + xfer->tail = index_inc(xfer->tail, xfer->max_blk_cnt); return xb; } diff --git a/devicemodel/include/usb_core.h b/devicemodel/include/usb_core.h index 4f8b6b2f8..2ebda3e6b 100644 --- a/devicemodel/include/usb_core.h +++ b/devicemodel/include/usb_core.h @@ -42,8 +42,6 @@ * By default, the native xhci driver use two segments which contain 2 * 256 * trbs, so 1024 is enough currently. */ -#define USB_MAX_XFER_BLOCKS 1024 - #define USB_XFER_OUT 0 #define USB_XFER_IN 1 @@ -164,9 +162,8 @@ struct usb_block { }; struct usb_xfer { - uint64_t magic; - struct usb_block data[USB_MAX_XFER_BLOCKS]; - struct usb_dev_req *requests[USB_MAX_XFER_BLOCKS]; + struct usb_block *data; + struct usb_dev_req **reqs; struct usb_device_request *ureq; /* setup ctl request */ int ndata; /* # of data items */ int head; @@ -174,6 +171,7 @@ struct usb_xfer { void *dev; /* struct pci_xhci_dev_emu *dev */ int epid; /* related endpoint id */ int pid; /* token id */ + int max_blk_cnt; int status; }; diff --git a/devicemodel/include/xhci.h b/devicemodel/include/xhci.h index 4220fcad0..06e5c0c2a 100755 --- a/devicemodel/include/xhci.h +++ b/devicemodel/include/xhci.h @@ -190,6 +190,15 @@ struct xhci_endp_ctx { volatile uint32_t dwEpCtx7; }; +#define XHCI_EPTYPE_INVALID 0 +#define XHCI_EPTYPE_ISOC_OUT 1 +#define XHCI_EPTYPE_BULK_OUT 2 +#define XHCI_EPTYPE_INT_OUT 3 +#define XHCI_EPTYPE_CTRL 4 +#define XHCI_EPTYPE_ISOC_IN 5 +#define XHCI_EPTYPE_BULK_IN 6 +#define XHCI_EPTYPE_INT_IN 7 + struct xhci_input_ctx { #define XHCI_INCTX_NON_CTRL_MASK 0xFFFFFFFCU volatile uint32_t dwInCtx0;