diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-11-20 08:57:25 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-11-20 08:57:25 +0000 |
commit | c3a431d7190b3a22732569a0a5eb670c4472448c (patch) | |
tree | e74fa51115d91a6aafc7339f0f35e68ec522dd82 /lib/libusb/libusb10.c | |
parent | b65660166a38e0c0415e1c20a6958b52801f299b (diff) | |
download | FreeBSD-src-c3a431d7190b3a22732569a0a5eb670c4472448c.zip FreeBSD-src-c3a431d7190b3a22732569a0a5eb670c4472448c.tar.gz |
Sync to P4
- fix a transfer cancelling bug/segfault [1]
- correct a return code in the transfer cancel function.
- add new API function, libusb20_tr_bulk_intr_sync().
Submitted by: HPS
Reported by: Robert Jenssen [1]
Diffstat (limited to 'lib/libusb/libusb10.c')
-rw-r--r-- | lib/libusb/libusb10.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c index 55ee1c5..9a5154e 100644 --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -833,8 +833,12 @@ libusb10_complete_transfer(struct libusb20_transfer *pxfer, if (pxfer != NULL) libusb20_tr_set_priv_sc1(pxfer, NULL); + /* set transfer status */ uxfer->status = status; + /* update super transfer state */ + sxfer->state = LIBUSB_SUPER_XFER_ST_NONE; + dev = libusb_get_device(uxfer->dev_handle); TAILQ_INSERT_TAIL(&dev->ctx->tr_done, sxfer, entry); @@ -1111,6 +1115,8 @@ libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) return; case 2: sxfer = libusb20_tr_get_priv_sc1(pxfer1); + if (sxfer == NULL) + return; /* cancelling */ if (sxfer->rem_len) return; /* cannot queue another one */ /* swap transfers */ @@ -1118,6 +1124,8 @@ libusb10_submit_transfer_sub(struct libusb20_device *pdev, uint8_t endpoint) break; case 1: sxfer = libusb20_tr_get_priv_sc1(pxfer0); + if (sxfer == NULL) + return; /* cancelling */ if (sxfer->rem_len) return; /* cannot queue another one */ /* swap transfers */ @@ -1229,12 +1237,18 @@ libusb_submit_transfer(struct libusb_transfer *uxfer) if (pxfer0 == NULL || pxfer1 == NULL) { err = LIBUSB_ERROR_OTHER; } else if ((sxfer->entry.tqe_prev != NULL) || - (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || + (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) || (libusb20_tr_get_priv_sc1(pxfer1) == sxfer)) { err = LIBUSB_ERROR_BUSY; } else { + + /* set pending state */ + sxfer->state = LIBUSB_SUPER_XFER_ST_PEND; + + /* insert transfer into transfer head list */ TAILQ_INSERT_TAIL(&dev->tr_head, sxfer, entry); + /* start work transfers */ libusb10_submit_transfer_sub( uxfer->dev_handle, endpoint); @@ -1258,12 +1272,14 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer) struct libusb_super_transfer *sxfer; struct libusb_device *dev; uint32_t endpoint; + int retval; if (uxfer == NULL) return (LIBUSB_ERROR_INVALID_PARAM); + /* check if not initialised */ if (uxfer->dev_handle == NULL) - return (LIBUSB_ERROR_INVALID_PARAM); + return (LIBUSB_ERROR_NOT_FOUND); endpoint = uxfer->endpoint; @@ -1277,39 +1293,50 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer) sxfer = (struct libusb_super_transfer *)( (uint8_t *)uxfer - sizeof(*sxfer)); + retval = 0; + CTX_LOCK(dev->ctx); pxfer0 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 0); pxfer1 = libusb10_get_transfer(uxfer->dev_handle, endpoint, 1); - if (sxfer->entry.tqe_prev != NULL) { + if (sxfer->state != LIBUSB_SUPER_XFER_ST_PEND) { + /* only update the transfer status */ + uxfer->status = LIBUSB_TRANSFER_CANCELLED; + retval = LIBUSB_ERROR_NOT_FOUND; + } else if (sxfer->entry.tqe_prev != NULL) { /* we are lucky - transfer is on a queue */ TAILQ_REMOVE(&dev->tr_head, sxfer, entry); sxfer->entry.tqe_prev = NULL; - libusb10_complete_transfer(NULL, sxfer, LIBUSB_TRANSFER_CANCELLED); + libusb10_complete_transfer(NULL, + sxfer, LIBUSB_TRANSFER_CANCELLED); } else if (pxfer0 == NULL || pxfer1 == NULL) { /* not started */ + retval = LIBUSB_ERROR_NOT_FOUND; } else if (libusb20_tr_get_priv_sc1(pxfer0) == sxfer) { - libusb10_complete_transfer(pxfer0, sxfer, LIBUSB_TRANSFER_CANCELLED); + libusb10_complete_transfer(pxfer0, + sxfer, LIBUSB_TRANSFER_CANCELLED); libusb20_tr_stop(pxfer0); /* make sure the queue doesn't stall */ libusb10_submit_transfer_sub( uxfer->dev_handle, endpoint); } else if (libusb20_tr_get_priv_sc1(pxfer1) == sxfer) { - libusb10_complete_transfer(pxfer1, sxfer, LIBUSB_TRANSFER_CANCELLED); + libusb10_complete_transfer(pxfer1, + sxfer, LIBUSB_TRANSFER_CANCELLED); libusb20_tr_stop(pxfer1); /* make sure the queue doesn't stall */ libusb10_submit_transfer_sub( uxfer->dev_handle, endpoint); } else { /* not started */ + retval = LIBUSB_ERROR_NOT_FOUND; } CTX_UNLOCK(dev->ctx); DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave"); - return (0); + return (retval); } UNEXPORTED void |