Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Nov 2012 21:57:22 -0500
From:      Mark Johnston <markjdb@gmail.com>
To:        freebsd-usb@freebsd.org
Subject:   [patch] fix uplcom(4) clear stall logic for PL2303HX
Message-ID:  <20121120025722.GA3338@oddish>

next in thread | raw e-mail | index | archive | help
Hello all,

I recently bought a PL-2303 USB to serial converter (VID 0x067b, DID
0x2303) to use with an ARM board. When I start cu(1) and power on the
board no messages show up, and if I enter any input, cu exits without
printing anything and uplcom detaches and reinitializes itself. No error
messages are printed by the kernel - all I see is that uplcom(4)
disconnects and reattaches.

After some debugging I found that when the USB stack sends a
ENDPOINT_HALT clear to the OUT bulk endpoint, the hw seems to respond
with an endpoint stalled error, and after that, the uplcom callbacks are
called with error set to USB_ERROR_CANCELLED. I looked at the Linux
driver for this device and found the following code in pl2303.c:

	if (priv->type != HX) {
		usb_clear_halt(serial->dev, port->write_urb->pipe);
		usb_clear_halt(serial->dev, port->read_urb->pipe);
	} else {
		/* reset upstream data pipes */
		pl2303_vendor_write(8, 0, serial);
		pl2303_vendor_write(9, 0, serial);
	}

Unfortunately, I couldn't find any datasheets which indicate what these
vendor-specific commands mean. However I ended up with the patch below,
and now the device works perfectly. :)
In particular, it seems that we don't want to send a clear ENDPOINT_HALT
request to the HX variant of the device, which is what I have.

I noticed that the device still seems to work if I omit the vendor
commands, and being a total USB newbie I thought I'd ask the following
questions:

1. What exactly is the purpose of clearing ENDPOINT_HALT when a
userspace program attaches to a device? Is it just to make sure that the
device fw is in some known good state before starting to transmit data?

2. uplcom(4) tries to clear any stalls after an error in its r/w and
intr callbacks. Is there some way I can trigger an error so that I can
test and fix that code too?

I'm happy to test alternative fixes, provide debug output, etc., etc.

Thanks,
-Mark

diff --git a/sys/dev/usb/serial/uplcom.c b/sys/dev/usb/serial/uplcom.c
index 4549bad..4d9ac32 100644
--- a/sys/dev/usb/serial/uplcom.c
+++ b/sys/dev/usb/serial/uplcom.c
@@ -433,10 +433,18 @@ uplcom_attach(device_t dev)
 		goto detach;
 	}
 	/* clear stall at first run */
-	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);
+	if (sc->sc_chiptype != TYPE_PL2303HX) {
+		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 (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
+		    UPLCOM_SET_REQUEST, 8, 0, 0) ||
+		    uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
+		    UPLCOM_SET_REQUEST, 9, 0, 0))
+			goto detach;
+	}
 
 	error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
 	    &uplcom_callback, &sc->sc_mtx);
@@ -555,9 +563,6 @@ uplcom_pl2303_init(struct usb_device *udev, uint8_t chiptype)
 	if (err)
 		return (EIO);
 	
-	if (uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 8, 0, 0)
-	    || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 9, 0, 0))
-		return (EIO);
 	return (0);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20121120025722.GA3338>