1 From 4b5f5193848808c0d6c730ce37737538e404c218 Mon Sep 17 00:00:00 2001
2 From: "Joshua M. Clulow" <josh@sysmgr.org>
3 Date: Mon, 27 Dec 2021 16:08:40 -0800
4 Subject: [PATCH] illumos: correctly return error conditions
7 libusb/os/illumos_usb.c | 98 ++++++++++++++++++++++++++++++++---------
8 libusb/os/illumos_usb.h | 1 +
9 2 files changed, 79 insertions(+), 20 deletions(-)
11 diff --git a/libusb/os/illumos_usb.c b/libusb/os/illumos_usb.c
12 index db8dcf75..ec4b2721 100644
13 --- a/libusb/os/illumos_usb.c
14 +++ b/libusb/os/illumos_usb.c
15 @@ -1186,7 +1186,6 @@ illumos_async_callback(union sigval arg)
16 struct libusb_transfer *xfer = tpriv->transfer;
17 struct usbi_transfer *ixfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer);
18 struct aiocb *aiocb = &tpriv->aiocb;
20 illumos_dev_handle_priv_t *hpriv;
22 libusb_device_handle *dev_handle;
23 @@ -1196,23 +1195,20 @@ illumos_async_callback(union sigval arg)
27 - hpriv = usbi_get_device_handle_priv(dev_handle);
28 - ep = illumos_usb_ep_index(xfer->endpoint);
29 + if (aio_error(aiocb) != ECANCELED) {
30 + hpriv = usbi_get_device_handle_priv(dev_handle);
31 + ep = illumos_usb_ep_index(xfer->endpoint);
33 - ret = aio_error(aiocb);
35 - xfer->status = illumos_usb_get_status(TRANSFER_CTX(xfer),
37 + * Fetch the status for the last command on this endpoint from
38 + * ugen(7D) so that we can translate and report it later.
40 + tpriv->ugen_status = illumos_usb_get_status(TRANSFER_CTX(xfer),
41 hpriv->eps[ep].statfd);
43 - xfer->actual_length = ixfer->transferred = aio_return(aiocb);
44 + tpriv->ugen_status = USB_LC_STAT_NOERROR;
47 - usb_dump_data(xfer->buffer, xfer->actual_length);
49 - usbi_dbg(TRANSFER_CTX(xfer), "ret=%d, len=%d, actual_len=%d",
50 - ret, xfer->length, xfer->actual_length);
52 - /* async notification */
53 usbi_signal_transfer_completion(ixfer);
56 @@ -1478,10 +1474,6 @@ illumos_cancel_transfer(struct usbi_transfer *itransfer)
57 if (ret != AIO_CANCELED) {
58 ret = _errno_to_libusb(errno);
61 - * we don't need to call usbi_handle_transfer_cancellation(),
62 - * because we'll handle everything in illumos_async_callback.
67 @@ -1489,10 +1481,76 @@ illumos_cancel_transfer(struct usbi_transfer *itransfer)
71 -illumos_handle_transfer_completion(struct usbi_transfer *itransfer)
72 +illumos_handle_transfer_completion(struct usbi_transfer *ixfer)
74 - return (usbi_handle_transfer_completion(itransfer,
75 - LIBUSB_TRANSFER_COMPLETED));
76 + illumos_xfer_priv_t *tpriv = usbi_get_transfer_priv(ixfer);
77 + struct libusb_transfer *xfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(ixfer);
78 + struct aiocb *aiocb = &tpriv->aiocb;
80 + enum libusb_transfer_status status;
82 + if ((ret = aio_error(aiocb)) == 0) {
84 + * The command completed. Update the transferred length:
86 + xfer->actual_length = ixfer->transferred = aio_return(aiocb);
88 + usbi_dbg(TRANSFER_CTX(xfer), "ret=%d, len=%d, actual_len=%d",
89 + ret, xfer->length, xfer->actual_length);
90 + usb_dump_data(xfer->buffer, xfer->actual_length);
92 + status = LIBUSB_TRANSFER_COMPLETED;
94 + } else if (ret == ECANCELED) {
96 + * We used aio_cancel() to cancel this; report cancellation to
97 + * libusb so that timeouts can be handled correctly.
99 + usbi_dbg(TRANSFER_CTX(xfer),
100 + "aio cancelled, len=%d, actual_len=%d",
101 + xfer->length, xfer->actual_length);
103 + status = LIBUSB_TRANSFER_CANCELLED;
107 + * Convert the ugen(7D)-level status to a libusb-level status:
109 + switch (tpriv->ugen_status) {
110 + case USB_LC_STAT_TIMEOUT:
111 + status = LIBUSB_TRANSFER_TIMED_OUT;
113 + case USB_LC_STAT_STALL:
114 + status = LIBUSB_TRANSFER_STALL;
116 + case USB_LC_STAT_DISCONNECTED:
117 + status = LIBUSB_TRANSFER_NO_DEVICE;
119 + case USB_LC_STAT_INTERRUPTED:
120 + status = LIBUSB_TRANSFER_CANCELLED;
122 + case USB_LC_STAT_BUFFER_OVERRUN:
124 + * XXX Is this right? (*_DATA_OVERRUN?)
126 + status = LIBUSB_TRANSFER_OVERFLOW;
130 + * Not every ugen(7D) status maps to a specific
131 + * libusb-level failure case. Nonetheless, we must
132 + * report all failures as failures:
134 + status = LIBUSB_TRANSFER_ERROR;
139 + if (status == LIBUSB_TRANSFER_CANCELLED) {
140 + return (usbi_handle_transfer_cancellation(ixfer));
142 + return (usbi_handle_transfer_completion(ixfer, status));
147 diff --git a/libusb/os/illumos_usb.h b/libusb/os/illumos_usb.h
148 index f24c3707..4f3082c8 100644
149 --- a/libusb/os/illumos_usb.h
150 +++ b/libusb/os/illumos_usb.h
151 @@ -50,6 +50,7 @@ typedef struct illumos_device_handle_priv {
152 typedef struct illumos_transfer_priv {
154 struct libusb_transfer *transfer;
156 } illumos_xfer_priv_t;