diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 22e4e8f6b2b..d7d8fd80b42 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -978,8 +978,7 @@ u3g_attach(device_t dev) /* set stall by default */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[nports][U3G_BULK_WR]); - usbd_xfer_set_stall(sc->sc_xfer[nports][U3G_BULK_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[nports][U3G_BULK_WR]); mtx_unlock(&sc->sc_mtx); nports++; /* found one port */ @@ -1100,6 +1099,9 @@ u3g_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_TRANSFERRED: case USB_ST_SETUP: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + for (frame = 0; frame != U3G_TXFRAMES; frame++) { usbd_xfer_set_frame_offset(xfer, frame * U3G_TXSIZE, frame); diff --git a/sys/dev/usb/serial/uark.c b/sys/dev/usb/serial/uark.c index 904977e1ec1..072edf6389c 100644 --- a/sys/dev/usb/serial/uark.c +++ b/sys/dev/usb/serial/uark.c @@ -219,8 +219,7 @@ uark_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UARK_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UARK_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UARK_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -281,13 +280,16 @@ uark_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UARK_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -295,7 +297,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/ubsa.c b/sys/dev/usb/serial/ubsa.c index 10b37984db2..3286df7331b 100644 --- a/sys/dev/usb/serial/ubsa.c +++ b/sys/dev/usb/serial/ubsa.c @@ -320,8 +320,7 @@ ubsa_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UBSA_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UBSA_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -583,13 +582,16 @@ ubsa_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UBSA_BSIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -597,7 +599,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/ubser.c b/sys/dev/usb/serial/ubser.c index 2a35756b0a7..61b9c6c433f 100644 --- a/sys/dev/usb/serial/ubser.c +++ b/sys/dev/usb/serial/ubser.c @@ -293,8 +293,7 @@ ubser_attach(device_t dev) ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UBSER_BULK_DT_WR]); usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_RD]); mtx_unlock(&sc->sc_mtx); @@ -410,6 +409,9 @@ ubser_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); do { if (ucom_get_data(sc->sc_ucom + sc->sc_curr_tx_unit, @@ -430,7 +432,7 @@ tr_setup: } while (sc->sc_curr_tx_unit != first_unit); - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -438,7 +440,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c index 6b17141c6ec..aef1515d358 100644 --- a/sys/dev/usb/serial/uchcom.c +++ b/sys/dev/usb/serial/uchcom.c @@ -350,8 +350,7 @@ uchcom_attach(device_t dev) /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UCHCOM_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UCHCOM_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -828,6 +827,9 @@ uchcom_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, usbd_xfer_max_len(xfer), &actlen)) { diff --git a/sys/dev/usb/serial/ufoma.c b/sys/dev/usb/serial/ufoma.c index bc3f00a7b47..ca52752acca 100644 --- a/sys/dev/usb/serial/ufoma.c +++ b/sys/dev/usb/serial/ufoma.c @@ -438,8 +438,7 @@ ufoma_attach(device_t dev) /* clear stall at first run, if any */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); - usbd_xfer_set_stall(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_READ]); + usbd_xfer_set_zlp(sc->sc_bulk_xfer[UFOMA_BULK_ENDPT_WRITE]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -791,13 +790,16 @@ ufoma_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UFOMA_BULK_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -805,7 +807,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c index 52977352fb9..9dc00e82253 100644 --- a/sys/dev/usb/serial/uftdi.c +++ b/sys/dev/usb/serial/uftdi.c @@ -1117,8 +1117,7 @@ uftdi_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UFTDI_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); /* set a valid "lcr" value */ @@ -1221,6 +1220,9 @@ uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error) /* FALLTHROUGH */ case USB_ST_SETUP: case USB_ST_TRANSFERRED: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + /* * If output packets don't require headers (the common case) we * can just load the buffer up with payload bytes all at once. diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c index ba694e4805b..1d2f1e57ef5 100644 --- a/sys/dev/usb/serial/ugensa.c +++ b/sys/dev/usb/serial/ugensa.c @@ -233,10 +233,8 @@ ugensa_attach(device_t dev) break; } - /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_WR]); - usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_RD]); + usbd_xfer_set_zlp(ssc->sc_xfer[UGENSA_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); /* initialize port number */ @@ -313,13 +311,16 @@ ugensa_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(ssc->sc_ucom_ptr, pc, 0, UGENSA_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -327,7 +328,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uipaq.c b/sys/dev/usb/serial/uipaq.c index 33f2ae4c084..0449a5663c7 100644 --- a/sys/dev/usb/serial/uipaq.c +++ b/sys/dev/usb/serial/uipaq.c @@ -1157,8 +1157,7 @@ uipaq_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UIPAQ_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UIPAQ_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UIPAQ_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -1320,13 +1319,16 @@ uipaq_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UIPAQ_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -1334,7 +1336,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c index c566da92437..56f99519d4c 100644 --- a/sys/dev/usb/serial/ulpt.c +++ b/sys/dev/usb/serial/ulpt.c @@ -218,6 +218,9 @@ ulpt_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_TRANSFERRED: case USB_ST_SETUP: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); max = usbd_xfer_max_len(xfer); if (usb_fifo_get_data(f, pc, 0, max, &actlen, 0)) { @@ -436,10 +439,6 @@ unlpt_open(struct usb_fifo *fifo, int fflags) return (EBUSY); } if (fflags & FREAD) { - /* clear stall first */ - mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[ULPT_BULK_DT_RD]); - mtx_unlock(&sc->sc_mtx); if (usb_fifo_alloc_buffer(fifo, usbd_xfer_max_len(sc->sc_xfer[ULPT_BULK_DT_RD]), ULPT_IFQ_MAXLEN)) { @@ -451,7 +450,7 @@ unlpt_open(struct usb_fifo *fifo, int fflags) if (fflags & FWRITE) { /* clear stall first */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[ULPT_BULK_DT_WR]); + usbd_xfer_set_zlp(sc->sc_xfer[ULPT_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); if (usb_fifo_alloc_buffer(fifo, usbd_xfer_max_len(sc->sc_xfer[ULPT_BULK_DT_WR]), diff --git a/sys/dev/usb/serial/umcs.c b/sys/dev/usb/serial/umcs.c index e3c8f1a764f..76ecd1ffa45 100644 --- a/sys/dev/usb/serial/umcs.c +++ b/sys/dev/usb/serial/umcs.c @@ -382,8 +382,7 @@ umcs7840_attach(device_t dev) /* clear stall at first run */ mtx_lock(&sc->sc_mtx); for (subunit = 0; subunit < sc->sc_numports; ++subunit) { - usbd_xfer_set_stall(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer[UMCS7840_BULK_RD_EP]); - usbd_xfer_set_stall(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer[UMCS7840_BULK_WR_EP]); + usbd_xfer_set_zlp(sc->sc_ports[sc->sc_ucom[subunit].sc_portno].sc_xfer[UMCS7840_BULK_WR_EP]); } mtx_unlock(&sc->sc_mtx); @@ -916,13 +915,16 @@ umcs7840_write_callbackN(struct usb_xfer *xfer, usb_error_t error, uint8_t subun case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(ucom, pc, 0, usbd_xfer_max_len(xfer), &actlen)) { DPRINTF("Port %d write, has %d bytes\n", ucom->sc_portno, actlen); usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -930,7 +932,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/umodem.c b/sys/dev/usb/serial/umodem.c index 573d74cdb52..b8b7ae2f005 100644 --- a/sys/dev/usb/serial/umodem.c +++ b/sys/dev/usb/serial/umodem.c @@ -447,13 +447,10 @@ umodem_attach(device_t dev) goto detach; } - /* clear stall at first run, if USB host mode */ - if (uaa->usb_mode == USB_MODE_HOST) { - mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UMODEM_BULK_RD]); - mtx_unlock(&sc->sc_mtx); - } + /* send a ZLP at first run */ + mtx_lock(&sc->sc_mtx); + usbd_xfer_set_zlp(sc->sc_xfer[UMODEM_BULK_WR]); + mtx_unlock(&sc->sc_mtx); ucom_set_usb_mode(&sc->sc_super_ucom, uaa->usb_mode); @@ -863,13 +860,16 @@ umodem_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UMODEM_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -877,7 +877,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/umoscom.c b/sys/dev/usb/serial/umoscom.c index 724ab7f9409..536772a7f69 100644 --- a/sys/dev/usb/serial/umoscom.c +++ b/sys/dev/usb/serial/umoscom.c @@ -333,8 +333,7 @@ umoscom_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UMOSCOM_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UMOSCOM_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -639,13 +638,16 @@ umoscom_write_callback(struct usb_xfer *xfer, usb_error_t error) tr_setup: DPRINTF("\n"); + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UMOSCOM_BUFSIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -654,7 +656,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uplcom.c b/sys/dev/usb/serial/uplcom.c index 9efac9ff6b7..6808ddd64a4 100644 --- a/sys/dev/usb/serial/uplcom.c +++ b/sys/dev/usb/serial/uplcom.c @@ -507,14 +507,12 @@ uplcom_attach(device_t dev) goto detach; } - if (sc->sc_chiptype == TYPE_PL2303) { - /* HX variants seem to lock up after a clear stall request. */ - mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]); - mtx_unlock(&sc->sc_mtx); - } else if (sc->sc_chiptype == TYPE_PL2303HX || - sc->sc_chiptype == TYPE_PL2303HXD) { + mtx_lock(&sc->sc_mtx); + usbd_xfer_set_zlp(sc->sc_xfer[UPLCOM_BULK_DT_WR]); + mtx_unlock(&sc->sc_mtx); + + if (sc->sc_chiptype == TYPE_PL2303HX || + sc->sc_chiptype == TYPE_PL2303HXD) { /* reset upstream data pipes */ if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0) || @@ -1094,6 +1092,9 @@ uplcom_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UPLCOM_BULK_BUF_SIZE, &actlen)) { @@ -1102,7 +1103,7 @@ tr_setup: usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -1110,7 +1111,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uslcom.c b/sys/dev/usb/serial/uslcom.c index fec18d2a563..8c40a2c2fc3 100644 --- a/sys/dev/usb/serial/uslcom.c +++ b/sys/dev/usb/serial/uslcom.c @@ -443,8 +443,7 @@ uslcom_attach(device_t dev) } /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[USLCOM_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); sc->sc_partnum = uslcom_get_partnum(sc); @@ -819,6 +818,9 @@ uslcom_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, USLCOM_BULK_BUF_SIZE, &actlen)) { @@ -827,7 +829,7 @@ tr_setup: usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -835,7 +837,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/serial/uvscom.c b/sys/dev/usb/serial/uvscom.c index 8bb69e4402c..81fd5334a24 100644 --- a/sys/dev/usb/serial/uvscom.c +++ b/sys/dev/usb/serial/uvscom.c @@ -318,8 +318,7 @@ uvscom_attach(device_t dev) /* clear stall at first run */ mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_WR]); - usbd_xfer_set_stall(sc->sc_xfer[UVSCOM_BULK_DT_RD]); + usbd_xfer_set_zlp(sc->sc_xfer[UVSCOM_BULK_DT_WR]); mtx_unlock(&sc->sc_mtx); error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, @@ -391,13 +390,16 @@ uvscom_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: case USB_ST_TRANSFERRED: tr_setup: + if (usbd_xfer_get_and_clr_zlp(xfer)) + break; + pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom, pc, 0, UVSCOM_BULK_BUF_SIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } - return; + break; default: /* Error */ if (error != USB_ERR_CANCELLED) { @@ -405,7 +407,7 @@ tr_setup: usbd_xfer_set_stall(xfer); goto tr_setup; } - return; + break; } } diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index 436e08db14a..e1582926b08 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -2,7 +2,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2008-2021 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -2689,6 +2689,61 @@ usbd_transfer_start_cb(void *arg) } } +/*------------------------------------------------------------------------* + * usbd_xfer_set_zlp + * + * This function sets the USB transfers ZLP flag. + *------------------------------------------------------------------------*/ +void +usbd_xfer_set_zlp(struct usb_xfer *xfer) +{ + if (xfer == NULL) { + /* tearing down */ + return; + } + USB_XFER_LOCK_ASSERT(xfer, MA_OWNED); + + /* avoid any races by locking the USB mutex */ + USB_BUS_LOCK(xfer->xroot->bus); + xfer->flags.send_zlp = 1; + USB_BUS_UNLOCK(xfer->xroot->bus); +} + +/*------------------------------------------------------------------------* + * usbd_xfer_get_and_clr_zlp + * + * This function gets and clears the USB transfers ZLP flag and + * queues a zero-length USB transfer if the flag was set. + *------------------------------------------------------------------------*/ +uint8_t +usbd_xfer_get_and_clr_zlp(struct usb_xfer *xfer) +{ + uint8_t retval; + + if (xfer == NULL) { + /* tearing down */ + return (0); + } + USB_XFER_LOCK_ASSERT(xfer, MA_OWNED); + + retval = xfer->flags.send_zlp; + + if (retval != 0) { + DPRINTFN(1, "Sending zero-length packet.\n"); + + /* avoid any races by locking the USB mutex */ + USB_BUS_LOCK(xfer->xroot->bus); + xfer->flags.send_zlp = 0; + USB_BUS_UNLOCK(xfer->xroot->bus); + + /* queue up a zero-length packet */ + usbd_xfer_set_frame_len(xfer, 0, 0); + usbd_xfer_set_frames(xfer, 1); + usbd_transfer_submit(xfer); + } + return (retval); +} + /*------------------------------------------------------------------------* * usbd_xfer_set_stall * @@ -2733,9 +2788,7 @@ usbd_transfer_clear_stall(struct usb_xfer *xfer) /* avoid any races by locking the USB mutex */ USB_BUS_LOCK(xfer->xroot->bus); - xfer->flags.stall_pipe = 0; - USB_BUS_UNLOCK(xfer->xroot->bus); } diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 1b3b4af5f71..287e40d5936 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -218,6 +218,7 @@ struct usb_xfer_flags { * option only has effect for * ISOCHRONOUS transfers. */ + uint8_t send_zlp:1; /* send a zero length packet first */ }; /* @@ -655,6 +656,8 @@ void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len); void usbd_xfer_set_timeout(struct usb_xfer *xfer, int timeout); void usbd_xfer_set_frames(struct usb_xfer *xfer, usb_frcount_t n); +void usbd_xfer_set_zlp(struct usb_xfer *xfer); +uint8_t usbd_xfer_get_and_clr_zlp(struct usb_xfer *xfer); void usbd_xfer_set_stall(struct usb_xfer *xfer); int usbd_xfer_is_stalled(struct usb_xfer *xfer); void usbd_xfer_set_flag(struct usb_xfer *xfer, int flag);