From 7762e8a12e3fd264096bdebea0613235599910df Mon Sep 17 00:00:00 2001 From: Edward Tomasz Napierala Date: Wed, 25 Apr 2018 15:28:46 +0000 Subject: [PATCH] Make it possible (controlled via sysctl, enabled by default) to mark device-side (and only device-side) "virtual USB serial adapters" - the ones you can get with an OTG-capable board - as consoles. It boils down to adding the device name to kern.console sysctl, although doing that requires jumping through some hoops. It doesn't change the actual operation of those virtual devices. The point is to make it possible for init(8) to recognize them as console devices and to launch getty(8) for them, when configured as "onifconsole" in ttys(5). The point of that, in turn, is to add such entries to the default ttys(5), so that init(8) will launch gettys for device-side "virtual serial adapters", but not for actual USB serial dongles. Reviewed by: hselasky@ No objections: imp@ MFC after: 2 weeks Sponsored by: The FreeBSD Foundation --- share/man/man4/ucom.4 | 7 +++- sys/dev/usb/serial/umodem.c | 2 + sys/dev/usb/serial/usb_serial.c | 72 ++++++++++++++++++++++++++++----- sys/dev/usb/serial/usb_serial.h | 3 ++ 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/share/man/man4/ucom.4 b/share/man/man4/ucom.4 index e7dc77fb6243..4eb2d12c217c 100644 --- a/share/man/man4/ucom.4 +++ b/share/man/man4/ucom.4 @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 24, 2018 +.Dd April 25, 2018 .Dt UCOM 4 .Os .Sh NAME @@ -74,6 +74,11 @@ tunables: Debug output level, where 0 is debugging disabled and larger values increase debug message verbosity. Default is 0. +.It Va hw.usb.ucom.device_mode_console +When set to 1, the +.Nm +driver will mark terminals as console devices when operating in device mode. +Default is 1. .It Va hw.usb.ucom.pps_mode Enables and configure PPS capture mode as described below. .Sh Pulse Per Second (PPS) Timing Interface diff --git a/sys/dev/usb/serial/umodem.c b/sys/dev/usb/serial/umodem.c index 11bd375113fb..567fbe3fd417 100644 --- a/sys/dev/usb/serial/umodem.c +++ b/sys/dev/usb/serial/umodem.c @@ -457,6 +457,8 @@ umodem_attach(device_t dev) mtx_unlock(&sc->sc_mtx); } + ucom_set_usb_mode(&sc->sc_super_ucom, uaa->usb_mode); + error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &umodem_callback, &sc->sc_mtx); if (error) { diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c index 96c2c45c5ee6..445c9f2127b8 100644 --- a/sys/dev/usb/serial/usb_serial.c +++ b/sys/dev/usb/serial/usb_serial.c @@ -105,6 +105,12 @@ SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN, &ucom_pps_mode, 0, "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert"); +static int ucom_device_mode_console = 1; + +SYSCTL_INT(_hw_usb_ucom, OID_AUTO, device_mode_console, CTLFLAG_RW, + &ucom_device_mode_console, 0, + "set to 1 to mark terminals as consoles when in device mode"); + #ifdef USB_DEBUG static int ucom_debug = 0; @@ -288,7 +294,7 @@ ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, } ssc->sc_subunits = subunits; ssc->sc_flag = UCOM_FLAG_ATTACHED | - UCOM_FLAG_FREE_UNIT; + UCOM_FLAG_FREE_UNIT | (ssc->sc_flag & UCOM_FLAG_DEVICE_MODE); if (callback->ucom_free == NULL) ssc->sc_flag |= UCOM_FLAG_WAIT_REFS; @@ -388,6 +394,24 @@ ucom_drain_all(void *arg) mtx_unlock(&ucom_mtx); } +static cn_probe_t ucom_cnprobe; +static cn_init_t ucom_cninit; +static cn_term_t ucom_cnterm; +static cn_getc_t ucom_cngetc; +static cn_putc_t ucom_cnputc; +static cn_grab_t ucom_cngrab; +static cn_ungrab_t ucom_cnungrab; + +const struct consdev_ops ucom_cnops = { + .cn_probe = ucom_cnprobe, + .cn_init = ucom_cninit, + .cn_term = ucom_cnterm, + .cn_getc = ucom_cngetc, + .cn_putc = ucom_cnputc, + .cn_grab = ucom_cngrab, + .cn_ungrab = ucom_cnungrab, +}; + static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { @@ -450,6 +474,24 @@ ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) UCOM_MTX_UNLOCK(ucom_cons_softc); } + if ((ssc->sc_flag & UCOM_FLAG_DEVICE_MODE) != 0 && + ucom_device_mode_console > 0 && + ucom_cons_softc == NULL) { + struct consdev *cp; + + cp = malloc(sizeof(struct consdev), M_USBDEV, + M_WAITOK|M_ZERO); + cp->cn_ops = &ucom_cnops; + cp->cn_arg = NULL; + cp->cn_pri = CN_NORMAL; + strlcpy(cp->cn_name, "tty", sizeof(cp->cn_name)); + strlcat(cp->cn_name, buf, sizeof(cp->cn_name)); + + sc->sc_consdev = cp; + + cnadd(cp); + } + return (0); } @@ -460,6 +502,12 @@ ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); + if (sc->sc_consdev != NULL) { + cnremove(sc->sc_consdev); + free(sc->sc_consdev, M_USBDEV); + sc->sc_consdev = NULL; + } + if (sc->sc_flag & UCOM_FLAG_CONSOLE) { UCOM_MTX_LOCK(ucom_cons_softc); ucom_close(ucom_cons_softc->sc_tty); @@ -533,6 +581,20 @@ ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev) } } +void +ucom_set_usb_mode(struct ucom_super_softc *ssc, enum usb_hc_mode usb_mode) +{ + + switch (usb_mode) { + case USB_MODE_DEVICE: + ssc->sc_flag |= UCOM_FLAG_DEVICE_MODE; + break; + default: + ssc->sc_flag &= ~UCOM_FLAG_DEVICE_MODE; + break; + } +} + static void ucom_queue_command(struct ucom_softc *sc, usb_proc_callback_t *fn, struct termios *pt, @@ -1533,14 +1595,6 @@ ucom_free(void *xsc) mtx_unlock(&ucom_mtx); } -static cn_probe_t ucom_cnprobe; -static cn_init_t ucom_cninit; -static cn_term_t ucom_cnterm; -static cn_getc_t ucom_cngetc; -static cn_putc_t ucom_cnputc; -static cn_grab_t ucom_cngrab; -static cn_ungrab_t ucom_cnungrab; - CONSOLE_DRIVER(ucom); static void diff --git a/sys/dev/usb/serial/usb_serial.h b/sys/dev/usb/serial/usb_serial.h index 9a5e043e2474..cd60bcfb97a2 100644 --- a/sys/dev/usb/serial/usb_serial.h +++ b/sys/dev/usb/serial/usb_serial.h @@ -165,6 +165,7 @@ struct ucom_softc { const struct ucom_callback *sc_callback; struct ucom_super_softc *sc_super; struct tty *sc_tty; + struct consdev *sc_consdev; struct mtx *sc_mtx; void *sc_parent; int sc_subunit; @@ -183,6 +184,7 @@ struct ucom_softc { #define UCOM_FLAG_FREE_UNIT 0x0200 /* set if we must free the unit */ #define UCOM_FLAG_INWAKEUP 0x0400 /* set if we are in the tsw_inwakeup callback */ #define UCOM_FLAG_LSRTXIDLE 0x0800 /* set if sc_lsr bits ULSR_TSRE+TXRDY work */ +#define UCOM_FLAG_DEVICE_MODE 0x1000 /* set if we're an USB device, not a host */ uint8_t sc_lsr; uint8_t sc_msr; uint8_t sc_mcr; @@ -211,6 +213,7 @@ int ucom_attach(struct ucom_super_softc *, const struct ucom_callback *callback, struct mtx *); void ucom_detach(struct ucom_super_softc *, struct ucom_softc *); void ucom_set_pnpinfo_usb(struct ucom_super_softc *, device_t); +void ucom_set_usb_mode(struct ucom_super_softc *, enum usb_hc_mode); void ucom_status_change(struct ucom_softc *); uint8_t ucom_get_data(struct ucom_softc *, struct usb_page_cache *, uint32_t, uint32_t, uint32_t *);