usb/162307: commit references a PR
dfilter service
dfilter at FreeBSD.ORG
Sat Nov 5 12:10:11 UTC 2011
The following reply was made to PR usb/162307; it has been noted by GNATS.
From: dfilter at FreeBSD.ORG (dfilter service)
To: bug-followup at FreeBSD.org
Cc:
Subject: Re: usb/162307: commit references a PR
Date: Sat, 5 Nov 2011 12:02:09 +0000 (UTC)
Author: hselasky
Date: Sat Nov 5 12:01:51 2011
New Revision: 227108
URL: http://svn.freebsd.org/changeset/base/227108
Log:
Implement support for modem control lines.
Don't short terminate transmitted BULK data.
Assume that the chip reads one USB packet at a time.
PR: usb/162307
MFC after: 3 days
Modified:
head/sys/dev/usb/serial/uslcom.c
Modified: head/sys/dev/usb/serial/uslcom.c
==============================================================================
--- head/sys/dev/usb/serial/uslcom.c Sat Nov 5 11:18:46 2011 (r227107)
+++ head/sys/dev/usb/serial/uslcom.c Sat Nov 5 12:01:51 2011 (r227108)
@@ -63,43 +63,61 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, deb
#define USLCOM_SET_DATA_BITS(x) ((x) << 8)
+/* Request types */
#define USLCOM_WRITE 0x41
#define USLCOM_READ 0xc1
+/* Request codes */
#define USLCOM_UART 0x00
#define USLCOM_BAUD_RATE 0x01
#define USLCOM_DATA 0x03
#define USLCOM_BREAK 0x05
#define USLCOM_CTRL 0x07
+#define USLCOM_RCTRL 0x08
+#define USLCOM_SET_FLOWCTRL 0x13
+/* USLCOM_UART values */
#define USLCOM_UART_DISABLE 0x00
#define USLCOM_UART_ENABLE 0x01
+/* USLCOM_CTRL/USLCOM_RCTRL values */
#define USLCOM_CTRL_DTR_ON 0x0001
#define USLCOM_CTRL_DTR_SET 0x0100
#define USLCOM_CTRL_RTS_ON 0x0002
#define USLCOM_CTRL_RTS_SET 0x0200
#define USLCOM_CTRL_CTS 0x0010
#define USLCOM_CTRL_DSR 0x0020
+#define USLCOM_CTRL_RI 0x0040
#define USLCOM_CTRL_DCD 0x0080
+/* USLCOM_BAUD_RATE values */
#define USLCOM_BAUD_REF 0x384000
+/* USLCOM_DATA values */
#define USLCOM_STOP_BITS_1 0x00
#define USLCOM_STOP_BITS_2 0x02
-
#define USLCOM_PARITY_NONE 0x00
#define USLCOM_PARITY_ODD 0x10
#define USLCOM_PARITY_EVEN 0x20
#define USLCOM_PORT_NO 0xFFFF /* XXX think this should be 0 --hps */
+/* USLCOM_BREAK values */
#define USLCOM_BREAK_OFF 0x00
#define USLCOM_BREAK_ON 0x01
+/* USLCOM_SET_FLOWCTRL values - 1st word */
+#define USLCOM_FLOW_DTR_ON 0x00000001
+#define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */
+#define USLCOM_FLOW_RESERVED 0xFFFFFF80
+/* USLCOM_SET_FLOWCTRL values - 2nd word */
+#define USLCOM_FLOW_RTS_ON 0x00000040
+#define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */
+
enum {
USLCOM_BULK_DT_WR,
USLCOM_BULK_DT_RD,
+ USLCOM_CTRL_DT_RD,
USLCOM_N_TRANSFER,
};
@@ -121,6 +139,7 @@ static device_detach_t uslcom_detach;
static usb_callback_t uslcom_write_callback;
static usb_callback_t uslcom_read_callback;
+static usb_callback_t uslcom_control_callback;
static void uslcom_open(struct ucom_softc *);
static void uslcom_close(struct ucom_softc *);
@@ -143,7 +162,7 @@ static const struct usb_config uslcom_co
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = USLCOM_BULK_BUF_SIZE,
- .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+ .flags = {.pipe_bof = 1,},
.callback = &uslcom_write_callback,
},
@@ -155,6 +174,16 @@ static const struct usb_config uslcom_co
.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
.callback = &uslcom_read_callback,
},
+ [USLCOM_CTRL_DT_RD] = {
+ .type = UE_CONTROL,
+ .endpoint = 0x00,
+ .direction = UE_DIR_ANY,
+ .interval = 150, /* poll status every 150 ms */
+ .bufsize = sizeof(struct usb_device_request) + 8,
+ .flags = {.pipe_bof = 1,},
+ .callback = &uslcom_control_callback,
+ .timeout = 1000, /* 1 second timeout */
+ },
};
static struct ucom_callback uslcom_callback = {
@@ -371,6 +400,8 @@ uslcom_open(struct ucom_softc *ucom)
&req, NULL, 0, 1000)) {
DPRINTF("UART enable failed (ignored)\n");
}
+ /* Start polling status */
+ usbd_transfer_start(sc->sc_xfer[USLCOM_CTRL_DT_RD]);
}
static void
@@ -379,13 +410,16 @@ uslcom_close(struct ucom_softc *ucom)
struct uslcom_softc *sc = ucom->sc_parent;
struct usb_device_request req;
+ /* Stop polling status */
+ usbd_transfer_stop(sc->sc_xfer[USLCOM_CTRL_DT_RD]);
+
req.bmRequestType = USLCOM_WRITE;
req.bRequest = USLCOM_UART;
USETW(req.wValue, USLCOM_UART_DISABLE);
USETW(req.wIndex, USLCOM_PORT_NO);
USETW(req.wLength, 0);
- if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
+ if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000)) {
DPRINTF("UART disable failed (ignored)\n");
}
@@ -452,6 +486,7 @@ uslcom_param(struct ucom_softc *ucom, st
{
struct uslcom_softc *sc = ucom->sc_parent;
struct usb_device_request req;
+ uint32_t flowctrl[4];
uint16_t data;
DPRINTF("\n");
@@ -503,7 +538,30 @@ uslcom_param(struct ucom_softc *ucom, st
&req, NULL, 0, 1000)) {
DPRINTF("Set format failed (ignored)\n");
}
- return;
+
+ if (t->c_cflag & CRTSCTS) {
+ flowctrl[0] = htole32(USLCOM_FLOW_RESERVED |
+ USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS);
+ flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS);
+ flowctrl[2] = 0;
+ flowctrl[3] = 0;
+ } else {
+ flowctrl[0] = htole32(USLCOM_FLOW_RESERVED |
+ USLCOM_FLOW_DTR_ON);
+ flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON);
+ flowctrl[2] = 0;
+ flowctrl[3] = 0;
+ }
+ req.bmRequestType = USLCOM_WRITE;
+ req.bRequest = USLCOM_SET_FLOWCTRL;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, USLCOM_PORT_NO);
+ USETW(req.wLength, sizeof(flowctrl));
+
+ if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
+ &req, flowctrl, 0, 1000)) {
+ DPRINTF("Set flowcontrol failed (ignored)\n");
+ }
}
static void
@@ -599,6 +657,63 @@ tr_setup:
}
static void
+uslcom_control_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct uslcom_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ struct usb_device_request req;
+ uint8_t msr = 0;
+ uint8_t buf;
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ pc = usbd_xfer_get_frame(xfer, 1);
+ usbd_copy_out(pc, 0, &buf, sizeof(buf));
+ if (buf & USLCOM_CTRL_CTS)
+ msr |= SER_CTS;
+ if (buf & USLCOM_CTRL_DSR)
+ msr |= SER_DSR;
+ if (buf & USLCOM_CTRL_RI)
+ msr |= SER_RI;
+ if (buf & USLCOM_CTRL_DCD)
+ msr |= SER_DCD;
+
+ if (msr != sc->sc_msr) {
+ DPRINTF("status change msr=0x%02x "
+ "(was 0x%02x)\n", msr, sc->sc_msr);
+ sc->sc_msr = msr;
+ ucom_status_change(&sc->sc_ucom);
+ }
+
+ /* FALLTHROUGH */
+
+ case USB_ST_SETUP:
+tr_setup:
+ req.bmRequestType = USLCOM_READ;
+ req.bRequest = USLCOM_RCTRL;
+ USETW(req.wValue, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, sizeof(buf));
+
+ usbd_xfer_set_frames(xfer, 2);
+ usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
+ usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
+
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_copy_in(pc, 0, &req, sizeof(req));
+ usbd_transfer_submit(xfer);
+ break;
+
+ default: /* error */
+ if (error != USB_ERR_CANCELLED) {
+ DPRINTF("error=%s\n", usbd_errstr(error));
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
uslcom_start_read(struct ucom_softc *ucom)
{
struct uslcom_softc *sc = ucom->sc_parent;
_______________________________________________
svn-src-all at freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe at freebsd.org"
More information about the freebsd-usb
mailing list