Add a jitter buffer in the common USB serial driver code which
temporarily stores characters if the TTY buffer is full when used a as a console. This can happen when a console is suspended. Also properly do the flow stop signalling when this happens and flow start when the condition changes back to normal again. Bump __FreeBSD_version to force external kernel modules to be recompiled. No kernel API changes. MFC after: 1 week Suggested by: ed @
This commit is contained in:
parent
417a0a79d7
commit
d30d96ea57
@ -162,6 +162,7 @@ static tsw_ioctl_t ucom_ioctl;
|
||||
static tsw_modem_t ucom_modem;
|
||||
static tsw_param_t ucom_param;
|
||||
static tsw_outwakeup_t ucom_outwakeup;
|
||||
static tsw_inwakeup_t ucom_inwakeup;
|
||||
static tsw_free_t ucom_free;
|
||||
|
||||
static struct ttydevsw ucom_class = {
|
||||
@ -169,6 +170,7 @@ static struct ttydevsw ucom_class = {
|
||||
.tsw_open = ucom_open,
|
||||
.tsw_close = ucom_close,
|
||||
.tsw_outwakeup = ucom_outwakeup,
|
||||
.tsw_inwakeup = ucom_inwakeup,
|
||||
.tsw_ioctl = ucom_ioctl,
|
||||
.tsw_param = ucom_param,
|
||||
.tsw_modem = ucom_modem,
|
||||
@ -716,6 +718,10 @@ ucom_open(struct tty *tp)
|
||||
sc->sc_pls_set = 0;
|
||||
sc->sc_pls_clr = 0;
|
||||
|
||||
/* reset jitter buffer */
|
||||
sc->sc_jitterbuf_in = 0;
|
||||
sc->sc_jitterbuf_out = 0;
|
||||
|
||||
ucom_queue_command(sc, ucom_cfg_open, NULL,
|
||||
&sc->sc_open_task[0].hdr,
|
||||
&sc->sc_open_task[1].hdr);
|
||||
@ -780,6 +786,47 @@ ucom_close(struct tty *tp)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ucom_inwakeup(struct tty *tp)
|
||||
{
|
||||
struct ucom_softc *sc = tty_softc(tp);
|
||||
uint16_t pos;
|
||||
|
||||
if (sc == NULL)
|
||||
return;
|
||||
|
||||
tty_lock(tp);
|
||||
|
||||
if (ttydisc_can_bypass(tp) != 0 ||
|
||||
(sc->sc_flag & UCOM_FLAG_HL_READY) == 0) {
|
||||
tty_unlock(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = sc->sc_jitterbuf_out;
|
||||
|
||||
while (sc->sc_jitterbuf_in != pos) {
|
||||
int c;
|
||||
|
||||
c = (char)sc->sc_jitterbuf[pos];
|
||||
|
||||
if (ttydisc_rint(tp, c, 0) == -1)
|
||||
break;
|
||||
pos++;
|
||||
if (pos >= UCOM_JITTERBUF_SIZE)
|
||||
pos -= UCOM_JITTERBUF_SIZE;
|
||||
}
|
||||
|
||||
sc->sc_jitterbuf_out = pos;
|
||||
|
||||
/* clear RTS in async fashion */
|
||||
if ((sc->sc_jitterbuf_in == pos) &&
|
||||
(sc->sc_flag & UCOM_FLAG_RTS_IFLOW))
|
||||
ucom_rts(sc, 0);
|
||||
|
||||
tty_unlock(tp);
|
||||
}
|
||||
|
||||
static int
|
||||
ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
{
|
||||
@ -1360,6 +1407,11 @@ ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
|
||||
/* first check if we can pass the buffer directly */
|
||||
|
||||
if (ttydisc_can_bypass(tp)) {
|
||||
|
||||
/* clear any jitter buffer */
|
||||
sc->sc_jitterbuf_in = 0;
|
||||
sc->sc_jitterbuf_out = 0;
|
||||
|
||||
if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
|
||||
DPRINTF("tp=%p, data lost\n", tp);
|
||||
}
|
||||
@ -1368,8 +1420,31 @@ ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
|
||||
/* need to loop */
|
||||
|
||||
for (cnt = 0; cnt != res.length; cnt++) {
|
||||
if (ttydisc_rint(tp, buf[cnt], 0) == -1) {
|
||||
/* XXX what should we do? */
|
||||
if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
|
||||
ttydisc_rint(tp, buf[cnt], 0) == -1) {
|
||||
uint16_t end;
|
||||
uint16_t pos;
|
||||
|
||||
pos = sc->sc_jitterbuf_in;
|
||||
end = sc->sc_jitterbuf_out +
|
||||
UCOM_JITTERBUF_SIZE - 1;
|
||||
if (end >= UCOM_JITTERBUF_SIZE)
|
||||
end -= UCOM_JITTERBUF_SIZE;
|
||||
|
||||
for (; cnt != res.length; cnt++) {
|
||||
if (pos == end)
|
||||
break;
|
||||
sc->sc_jitterbuf[pos] = buf[cnt];
|
||||
pos++;
|
||||
if (pos >= UCOM_JITTERBUF_SIZE)
|
||||
pos -= UCOM_JITTERBUF_SIZE;
|
||||
}
|
||||
|
||||
sc->sc_jitterbuf_in = pos;
|
||||
|
||||
/* set RTS in async fashion */
|
||||
if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)
|
||||
ucom_rts(sc, 1);
|
||||
|
||||
DPRINTF("tp=%p, lost %d "
|
||||
"chars\n", tp, res.length - cnt);
|
||||
|
@ -78,6 +78,7 @@
|
||||
#define UCOM_MINVER 1
|
||||
#define UCOM_PREFVER UCOM_MODVER
|
||||
#define UCOM_MAXVER 1
|
||||
#define UCOM_JITTERBUF_SIZE 128 /* bytes */
|
||||
|
||||
struct usb_device;
|
||||
struct ucom_softc;
|
||||
@ -169,6 +170,8 @@ struct ucom_softc {
|
||||
struct mtx *sc_mtx;
|
||||
void *sc_parent;
|
||||
int sc_subunit;
|
||||
uint16_t sc_jitterbuf_in;
|
||||
uint16_t sc_jitterbuf_out;
|
||||
uint16_t sc_portno;
|
||||
uint16_t sc_flag;
|
||||
#define UCOM_FLAG_RTS_IFLOW 0x01 /* use RTS input flow control */
|
||||
@ -191,6 +194,7 @@ struct ucom_softc {
|
||||
#define UCOM_LS_RTS 0x02
|
||||
#define UCOM_LS_BREAK 0x04
|
||||
#define UCOM_LS_RING 0x08
|
||||
uint8_t sc_jitterbuf[UCOM_JITTERBUF_SIZE];
|
||||
};
|
||||
|
||||
#define UCOM_MTX_ASSERT(sc, what) mtx_assert((sc)->sc_mtx, what)
|
||||
|
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1000022 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1000023 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
Loading…
Reference in New Issue
Block a user