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
This commit is contained in:
parent
82a36aefae
commit
0527a869a9
@ -63,43 +63,61 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW,
|
||||
|
||||
#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_config[USLCOM_N_TRANSFER] = {
|
||||
.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_config[USLCOM_N_TRANSFER] = {
|
||||
.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, struct termios *t)
|
||||
{
|
||||
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, struct termios *t)
|
||||
&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
|
||||
@ -598,6 +656,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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user