65#include <sys/stdint.h>
66#include <sys/stddef.h>
71#include <sys/kernel.h>
73#include <sys/module.h>
76#include <sys/condvar.h>
77#include <sys/sysctl.h>
79#include <sys/unistd.h>
80#include <sys/callout.h>
81#include <sys/malloc.h>
85#include <dev/uart/uart_ppstypes.h>
91#define USB_DEBUG_VAR ucom_debug
100static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
107 "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert");
111SYSCTL_INT(_hw_usb_ucom, OID_AUTO, device_mode_console, CTLFLAG_RW,
113 "set to 1 to mark terminals as consoles when in device mode");
116static int ucom_debug = 0;
119 &ucom_debug, 0,
"ucom debug level");
122#define UCOM_CONS_BUFSIZE 1024
140SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RWTUN,
176 .tsw_flags = TF_INITLOCK | TF_CALLOUT,
191#define UCOM_UNIT_MAX 128
192#define UCOM_TTY_PREFIX "U"
203 mtx_init(&
ucom_mtx,
"UCOM MTX", NULL, MTX_DEF);
236 DPRINTF(
"ucom_unrhdr is NULL\n");
240 DPRINTF(
"unit %d is allocated\n", unit);
252 DPRINTF(
"cannot free unit number\n");
255 DPRINTF(
"unit %d is freed\n", unit);
268 int subunits,
void *parent,
276 (callback == NULL) ||
306 for (subunit = 0; subunit < ssc->
sc_subunits; subunit++) {
325 DPRINTF(
"tp = %p, unit = %d, subunits = %d\n",
355 for (subunit = 0; subunit < ssc->
sc_subunits; subunit++) {
360 sc[subunit].
sc_flag &= ~UCOM_FLAG_ATTACHED;
371 ssc->
sc_flag &= ~UCOM_FLAG_ATTACHED;
379 printf(
"ucom: Waiting for a TTY device to close.\n");
390 printf(
"ucom: Waiting for all detached TTY "
391 "devices to have open fds closed.\n");
443 tty_makedev(tp, NULL,
"%s", buf);
447 sc->
sc_pps.ppscap = PPS_CAPTUREBOTH;
448 sc->
sc_pps.driver_abi = PPS_ABI_VERSION;
450 pps_init_abi(&sc->
sc_pps);
452 DPRINTF(
"ttycreate: %s\n", buf);
458 DPRINTF(
"unit %d subunit %d is console",
481 cp = malloc(
sizeof(
struct consdev), M_USBDEV,
485 cp->cn_pri = CN_NORMAL;
486 strlcpy(cp->cn_name,
"tty",
sizeof(cp->cn_name));
487 strlcat(cp->cn_name, buf,
sizeof(cp->cn_name));
500 struct tty *tp = sc->
sc_tty;
513 sc->
sc_flag &= ~UCOM_FLAG_CONSOLE;
559 uaa = device_get_ivars(
dev);
563 device_printf(
dev,
"Could not set PNP info\n");
571 SYSCTL_CHILDREN(device_get_sysctl_tree(
dev)),
572 OID_AUTO,
"ttyname", CTLFLAG_RD, ssc->
sc_ttyname, 0,
573 "TTY device basename");
577 SYSCTL_CHILDREN(device_get_sysctl_tree(
dev)),
578 OID_AUTO,
"ttyports", CTLFLAG_RD,
592 ssc->
sc_flag &= ~UCOM_FLAG_DEVICE_MODE;
647 struct tty *tp = sc->
sc_tty;
656 if (tp->t_termios.c_cflag & HUPCL) {
772 sc->
sc_flag &= ~UCOM_FLAG_GP_DATA;
796 if (sc->
sc_tty == NULL || (sc->
sc_tty->t_termios.c_cflag & CNO_RTSDTR) == 0)
818 sc->
sc_flag &= ~UCOM_FLAG_LL_READY;
836 DPRINTF(
"tp=%p already closed\n", tp);
865 if (ttydisc_can_bypass(tp) != 0 ||
881 if (ttydisc_rint(tp, c, 0) == -1)
895 sc->
sc_flag &= ~UCOM_FLAG_INWAKEUP;
899ucom_ioctl(
struct tty *tp, u_long cmd, caddr_t data,
struct thread *td)
909 DPRINTF(
"cmd = 0x%08lx\n", cmd);
933 (sc, cmd,
data, 0, td);
937 if (
error == ENOIOCTL)
955 if ((sigon == 0) && (sigoff == 0)) {
956 if (sc->
sc_mcr & SER_DTR) {
959 if (sc->
sc_mcr & SER_RTS) {
962 if (sc->
sc_msr & SER_CTS) {
965 if (sc->
sc_msr & SER_DCD) {
968 if (sc->
sc_msr & SER_DSR) {
971 if (sc->
sc_msr & SER_RI) {
976 if (sigon & SER_DTR) {
979 if (sigoff & SER_DTR) {
982 if (sigon & SER_RTS) {
985 if (sigoff & SER_RTS) {
988 onoff = (sc->
sc_mcr & SER_DTR) ? 1 : 0;
991 onoff = (sc->
sc_mcr & SER_RTS) ? 1 : 0;
1066 uint8_t set_bits, uint8_t clear_bits)
1074 DPRINTF(
"on=0x%02x, off=0x%02x\n", set_bits, clear_bits);
1091 DPRINTF(
"onoff = %d\n", onoff);
1102 DPRINTF(
"onoff = %d\n", onoff);
1113 DPRINTF(
"onoff = %d\n", onoff);
1124 DPRINTF(
"onoff = %d\n", onoff);
1167 msr_delta = (sc->
sc_msr ^ new_msr);
1168 lsr_delta = (sc->
sc_lsr ^ new_lsr);
1178 pps_signal = SER_CTS;
1181 pps_signal = SER_DCD;
1188 if ((sc->
sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) &&
1189 (msr_delta & pps_signal)) {
1190 pps_capture(&sc->
sc_pps);
1191 onoff = (sc->
sc_msr & pps_signal) ? 1 : 0;
1194 pps_event(&sc->
sc_pps, onoff ? PPS_CAPTUREASSERT :
1198 if (msr_delta & SER_DCD) {
1199 onoff = (sc->
sc_msr & SER_DCD) ? 1 : 0;
1201 DPRINTF(
"DCD changed to %d\n", onoff);
1203 ttydisc_modem(tp, onoff);
1209 ttydisc_rint(tp, 0, TRE_BREAK);
1210 ttydisc_rint_done(tp);
1214 DPRINTF(
"Frame error detected\n");
1216 ttydisc_rint(tp, 0, TRE_FRAMING);
1217 ttydisc_rint_done(tp);
1221 DPRINTF(
"Parity error detected\n");
1223 ttydisc_rint(tp, 0, TRE_PARITY);
1224 ttydisc_rint_done(tp);
1294 if (t->c_ispeed && (t->c_ispeed != t->c_ospeed)) {
1296 DPRINTF(
"mismatch ispeed and ospeed\n");
1300 t->c_ispeed = t->c_ospeed;
1312 sc->
sc_flag &= ~UCOM_FLAG_GP_DATA;
1324 if (t->c_cflag & CRTS_IFLOW) {
1327 sc->
sc_flag &= ~UCOM_FLAG_RTS_IFLOW;
1363 DPRINTFN(3,
"sc = %p lsr 0x%02x\n", sc, sc->
sc_lsr);
1371 return ((sc->
sc_lsr & txidle) != txidle);
1385 uint32_t
offset, uint32_t
len, uint32_t *actlen)
1388 struct tty *tp = sc->
sc_tty;
1390 uint32_t offset_orig;
1423 return (temp ? 1 : 0);
1451 actlen[0] =
offset - offset_orig;
1453 DPRINTF(
"cnt=%d\n", actlen[0]);
1455 if (actlen[0] == 0) {
1466 struct tty *tp = sc->
sc_tty;
1524 if (ttydisc_can_bypass(tp)) {
1529 if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) {
1530 DPRINTF(
"tp=%p, data lost\n", tp);
1536 for (cnt = 0; cnt != res.
length; cnt++) {
1538 ttydisc_rint(tp, buf[cnt], 0) == -1) {
1548 for (; cnt != res.
length; cnt++) {
1564 "chars\n", tp, res.
length - cnt);
1569 ttydisc_rint_done(tp);
1593 cp->cn_pri = CN_NORMAL;
1595 cp->cn_pri = CN_DEAD;
1597 strlcpy(cp->cn_name,
"ucom",
sizeof(cp->cn_name));
1717 ssc->
sc_flag &= ~UCOM_FLAG_FREE_UNIT;
1749static gdb_probe_f ucom_gdbprobe;
1750static gdb_init_f ucom_gdbinit;
1751static gdb_term_f ucom_gdbterm;
1752static gdb_getc_f ucom_gdbgetc;
1753static gdb_putc_f ucom_gdbputc;
1755GDB_DBGPORT(ucom, ucom_gdbprobe, ucom_gdbinit, ucom_gdbterm, ucom_gdbgetc, ucom_gdbputc);
void(* ucom_tty_name)(struct ucom_softc *, char *pbuf, uint16_t buflen, uint16_t unit, uint16_t subunit)
void(* ucom_cfg_set_dtr)(struct ucom_softc *, uint8_t)
void(* ucom_stop_read)(struct ucom_softc *)
int(* ucom_pre_open)(struct ucom_softc *)
int(* ucom_pre_param)(struct ucom_softc *, struct termios *)
void(* ucom_cfg_set_rts)(struct ucom_softc *, uint8_t)
void(* ucom_cfg_set_break)(struct ucom_softc *, uint8_t)
void(* ucom_start_write)(struct ucom_softc *)
void(* ucom_cfg_open)(struct ucom_softc *)
void(* ucom_stop_write)(struct ucom_softc *)
void(* ucom_poll)(struct ucom_softc *)
void(* ucom_free)(struct ucom_softc *)
int(* ucom_ioctl)(struct ucom_softc *, uint32_t, caddr_t, int, struct thread *)
void(* ucom_start_read)(struct ucom_softc *)
void(* ucom_cfg_param)(struct ucom_softc *, struct termios *)
void(* ucom_cfg_close)(struct ucom_softc *)
void(* ucom_cfg_get_status)(struct ucom_softc *, uint8_t *plsr, uint8_t *pmsr)
void(* ucom_cfg_set_ring)(struct ucom_softc *, uint8_t)
struct termios termios_copy
struct ucom_cfg_task sc_status_task[2]
struct ucom_param_task sc_param_task[2]
struct ucom_cfg_task sc_line_state_task[2]
struct ucom_super_softc * sc_super
struct ucom_cfg_task sc_close_task[2]
uint16_t sc_jitterbuf_out
uint8_t sc_jitterbuf[UCOM_JITTERBUF_SIZE]
struct consdev * sc_consdev
struct usb_proc_msg * sc_last_start_xfer
const struct ucom_callback * sc_callback
struct ucom_cfg_task sc_start_task[2]
struct ucom_cfg_task sc_open_task[2]
struct sysctl_oid * sc_sysctl_ttyports
struct sysctl_oid * sc_sysctl_ttyname
enum usb_hc_mode usb_mode
struct usbd_lookup_info info
struct usb_device * device
usb_proc_callback_t * pm_callback
void usbd_get_page(struct usb_page_cache *pc, usb_frlength_t offset, struct usb_page_search *res)
void usbd_copy_in(struct usb_page_cache *cache, usb_frlength_t offset, const void *ptr, usb_frlength_t len)
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
usb_error_t usbd_set_pnpinfo(struct usb_device *udev, uint8_t iface_index, const char *pnpinfo)
#define USB_IN_POLLING_MODE_FUNC()
int usb_proc_create(struct usb_process *up, struct mtx *p_mtx, const char *pmesg, uint8_t prio)
uint8_t usb_proc_is_gone(struct usb_process *up)
void usb_proc_mwait(struct usb_process *up, void *_pm0, void *_pm1)
void usb_proc_drain(struct usb_process *up)
void * usb_proc_msignal(struct usb_process *up, void *_pm0, void *_pm1)
void usb_proc_free(struct usb_process *up)
uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen)
static tsw_busy_t ucom_busy
static void ucom_init(void *arg)
#define UCOM_CONS_BUFSIZE
static void ucom_uninit(void *arg)
void ucom_status_change(struct ucom_softc *sc)
static SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB ucom")
static usb_proc_callback_t ucom_cfg_status_change
static void ucom_unit_free(int)
static void ucom_start_transfers(struct ucom_softc *sc)
int ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, int subunits, void *parent, const struct ucom_callback *callback, struct mtx *mtx)
static void ucom_line_state(struct ucom_softc *sc, uint8_t set_bits, uint8_t clear_bits)
int ucom_unref(struct ucom_super_softc *ssc)
uint8_t ucom_cfg_is_gone(struct ucom_softc *sc)
static usb_proc_callback_t ucom_cfg_open
void ucom_ref(struct ucom_super_softc *ssc)
const struct consdev_ops ucom_cnops
static tsw_param_t ucom_param
static void ucom_ring(struct ucom_softc *, uint8_t)
static struct unrhdr * ucom_unrhdr
static cn_ungrab_t ucom_cnungrab
static uint8_t ucom_cons_rx_buf[UCOM_CONS_BUFSIZE]
static int ucom_device_mode_console
static cn_init_t ucom_cninit
static struct mtx ucom_mtx
static tsw_close_t ucom_close
void ucom_drain(struct ucom_super_softc *ssc)
static tsw_outwakeup_t ucom_outwakeup
static int ucom_cons_unit
static usb_proc_callback_t ucom_cfg_close
static void ucom_shutdown(struct ucom_softc *)
static usb_proc_callback_t ucom_cfg_param
static struct ttydevsw ucom_class
void ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
static cn_term_t ucom_cnterm
static int ucom_cons_subunit
static tsw_free_t ucom_free
void ucom_set_usb_mode(struct ucom_super_softc *ssc, enum usb_hc_mode usb_mode)
static unsigned int ucom_cons_rx_high
static void ucom_queue_command(struct ucom_softc *, usb_proc_callback_t *, struct termios *pt, struct usb_proc_msg *t0, struct usb_proc_msg *t1)
SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL)
static unsigned int ucom_cons_rx_low
static tsw_open_t ucom_open
static tsw_inwakeup_t ucom_inwakeup
static struct ucom_softc * ucom_cons_softc
static void ucom_detach_tty(struct ucom_super_softc *, struct ucom_softc *)
static cn_probe_t ucom_cnprobe
static tsw_ioctl_t ucom_ioctl
static uint8_t ucom_cons_tx_buf[UCOM_CONS_BUFSIZE]
static unsigned int ucom_cons_tx_low
SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL)
static cn_putc_t ucom_cnputc
static cn_grab_t ucom_cngrab
void ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
static void ucom_free_unit(struct ucom_super_softc *ssc)
static usb_proc_callback_t ucom_cfg_line_state
static tsw_modem_t ucom_modem
void ucom_drain_all(void *arg)
static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *)
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 usb_proc_callback_t ucom_cfg_start_transfers
static unsigned int ucom_cons_tx_high
MODULE_DEPEND(ucom, usb, 1, 1, 1)
static void ucom_dtr(struct ucom_softc *, uint8_t)
static int ucom_close_refs
static void ucom_break(struct ucom_softc *, uint8_t)
static void ucom_rts(struct ucom_softc *, uint8_t)
static cn_getc_t ucom_cngetc
static int ucom_cons_baud
static int ucom_unit_alloc(void)
void ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len)
#define UCOM_FLAG_GP_DATA
#define UCOM_FLAG_WAIT_REFS
#define UCOM_FLAG_DEVICE_MODE
#define UCOM_FLAG_LSRTXIDLE
#define UCOM_FLAG_FREE_UNIT
#define UCOM_JITTERBUF_SIZE
#define UCOM_FLAG_INWAKEUP
#define UCOM_FLAG_CONSOLE
#define UCOM_MTX_ASSERT(sc, what)
#define UCOM_FLAG_LL_READY
#define UCOM_MTX_UNLOCK(sc)
#define UCOM_MTX_LOCK(sc)
#define UCOM_FLAG_RTS_IFLOW
#define UCOM_FLAG_ATTACHED
#define UCOM_FLAG_HL_READY
void usb_pause_mtx(struct mtx *mtx, int timo)
void() usb_proc_callback_t(struct usb_proc_msg *)