static void ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { UCOM_MTX_LOCK(ucom_cons_softc); ucom_close(ucom_cons_softc); sc->sc_flag &= ~UCOM_FLAG_CONSOLE; UCOM_MTX_UNLOCK(ucom_cons_softc); ucom_cons_softc = NULL; } /* the config thread has been stopped when we get here */ UCOM_MTX_LOCK(sc); sc->sc_flag |= UCOM_FLAG_GONE; sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY); UCOM_MTX_UNLOCK(sc); if (tp) { lockmgr(&ucom_lock, LK_EXCLUSIVE); ucom_close_refs++; lockmgr(&ucom_lock, LK_RELEASE); /* tty_lock(tp); */ ucom_close(sc); /* close, if any */ /*tty_rel_gone(tp); */ UCOM_MTX_LOCK(sc); /* * make sure that read and write transfers are stopped */ if (sc->sc_callback->ucom_stop_read) { (sc->sc_callback->ucom_stop_read) (sc); } if (sc->sc_callback->ucom_stop_write) { (sc->sc_callback->ucom_stop_write) (sc); } UCOM_MTX_UNLOCK(sc); } ucom_unref(ssc); }
static void ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; 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); sc->sc_flag &= ~UCOM_FLAG_CONSOLE; UCOM_MTX_UNLOCK(ucom_cons_softc); ucom_cons_softc = NULL; } /* the config thread has been stopped when we get here */ UCOM_MTX_LOCK(sc); sc->sc_flag |= UCOM_FLAG_GONE; sc->sc_flag &= ~(UCOM_FLAG_HL_READY | UCOM_FLAG_LL_READY); UCOM_MTX_UNLOCK(sc); if (tp) { mtx_lock(&ucom_mtx); ucom_close_refs++; mtx_unlock(&ucom_mtx); tty_lock(tp); ucom_close(tp); /* close, if any */ tty_rel_gone(tp); UCOM_MTX_LOCK(sc); /* * make sure that read and write transfers are stopped */ if (sc->sc_callback->ucom_stop_read) (sc->sc_callback->ucom_stop_read) (sc); if (sc->sc_callback->ucom_stop_write) (sc->sc_callback->ucom_stop_write) (sc); UCOM_MTX_UNLOCK(sc); } }
static int ucom_cngetc(struct consdev *cd) { struct ucom_softc *sc = ucom_cons_softc; int c; if (sc == NULL) return (-1); UCOM_MTX_LOCK(sc); if (ucom_cons_rx_low != ucom_cons_rx_high) { c = ucom_cons_rx_buf[ucom_cons_rx_low]; ucom_cons_rx_low ++; ucom_cons_rx_low %= UCOM_CONS_BUFSIZE; } else { c = -1; } /* start USB transfers */ ucom_outwakeup(sc->sc_tty); UCOM_MTX_UNLOCK(sc); /* poll if necessary */ if (kdb_active && sc->sc_callback->ucom_poll) (sc->sc_callback->ucom_poll) (sc); return (c); }
static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp; char buf[32]; /* temporary TTY device name buffer */ tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx); if (tp == NULL) return (ENOMEM); /* Check if the client has a custom TTY name */ buf[0] = '\0'; if (sc->sc_callback->ucom_tty_name) { sc->sc_callback->ucom_tty_name(sc, buf, sizeof(buf), ssc->sc_unit, sc->sc_subunit); } if (buf[0] == 0) { /* Use default TTY name */ if (ssc->sc_subunits > 1) { /* multiple modems in one */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u", ssc->sc_unit, sc->sc_subunit); } else { /* single modem */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u", ssc->sc_unit); } } tty_makedev(tp, NULL, "%s", buf); sc->sc_tty = tp; DPRINTF("ttycreate: %s\n", buf); /* Check if this device should be a console */ if ((ucom_cons_softc == NULL) && (ssc->sc_unit == ucom_cons_unit) && (sc->sc_subunit == ucom_cons_subunit)) { DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit); ucom_cons_softc = sc; tty_init_console(tp, ucom_cons_baud); UCOM_MTX_LOCK(ucom_cons_softc); ucom_cons_rx_low = 0; ucom_cons_rx_high = 0; ucom_cons_tx_low = 0; ucom_cons_tx_high = 0; sc->sc_flag |= UCOM_FLAG_CONSOLE; ucom_open(ucom_cons_softc->sc_tty); ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in); UCOM_MTX_UNLOCK(ucom_cons_softc); } return (0); }
static int ucom_dev_close(struct dev_close_args *ap) { cdev_t dev = ap->a_head.a_dev; struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1; int error; UCOM_MTX_LOCK(sc); error = ucom_close(sc); UCOM_MTX_UNLOCK(sc); return error; }
static void ucom_cnputc(void *cd, int c) /* ucom_cnputc(struct consdev *cd, int c) */ { struct ucom_softc *sc = ucom_cons_softc; unsigned int temp; if (sc == NULL) return; repeat: UCOM_MTX_LOCK(sc); /* compute maximum TX length */ temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_tx_high + ucom_cons_tx_low; temp %= UCOM_CONS_BUFSIZE; if (temp) { ucom_cons_tx_buf[ucom_cons_tx_high] = c; ucom_cons_tx_high ++; ucom_cons_tx_high %= UCOM_CONS_BUFSIZE; } /* start USB transfers */ ucom_outwakeup(sc->sc_tty); UCOM_MTX_UNLOCK(sc); /* poll if necessary */ #if 0 /* XXX */ if (kdb_active && sc->sc_callback->ucom_poll) { (sc->sc_callback->ucom_poll) (sc); /* simple flow control */ if (temp == 0) goto repeat; } #endif }
static int ucom_dev_ioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; struct ucom_softc *sc = (struct ucom_softc *)dev->si_drv1; u_long cmd = ap->a_cmd; caddr_t data = ap->a_data; struct tty *tp = sc->sc_tty; int error; UCOM_MTX_LOCK(sc); lwkt_gettoken(&tty_token); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { lwkt_reltoken(&tty_token); return (EIO); } DPRINTF("cmd = 0x%08lx\n", cmd); error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred); if (error != ENOIOCTL) { DPRINTF("ucomioctl: l_ioctl: error = %d\n", error); lwkt_reltoken(&tty_token); UCOM_MTX_UNLOCK(sc); return (error); } crit_enter(); error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag); /*disc_optim(tp, &tp->t_termios, sc); */ if (error != ENOIOCTL) { crit_exit(); DPRINTF("ucomioctl: ttioctl: error = %d\n", error); lwkt_reltoken(&tty_token); UCOM_MTX_UNLOCK(sc); return (error); } switch (cmd) { #if 0 /* XXXDF */ case TIOCSRING: ucom_ring(sc, 1); error = 0; break; case TIOCCRING: ucom_ring(sc, 0); error = 0; break; #endif case TIOCSBRK: ucom_break(sc, 1); error = 0; break; case TIOCCBRK: ucom_break(sc, 0); error = 0; break; default: if (sc->sc_callback->ucom_ioctl) { error = (sc->sc_callback->ucom_ioctl) (sc, cmd, data, 0, curthread); if (error>=0) { crit_exit(); lwkt_reltoken(&tty_token); UCOM_MTX_UNLOCK(sc); return(error); } } else { error = ENOIOCTL; } break; } crit_exit(); lwkt_reltoken(&tty_token); UCOM_MTX_UNLOCK(sc); return (error); }
static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp; char buf[32]; /* temporary TTY device name buffer */ cdev_t dev; kprintf("attach tty\n"); lwkt_gettoken(&tty_token); kprintf("malloc: "); sc->sc_tty = tp = ttymalloc(sc->sc_tty); tp->t_oproc = ucom_start; tp->t_param = ucom_param; tp->t_stop = ucom_stop; if (tp == NULL) { lwkt_reltoken(&tty_token); return (ENOMEM); } /* Check if the client has a custom TTY name */ buf[0] = '\0'; if (sc->sc_callback->ucom_tty_name) { sc->sc_callback->ucom_tty_name(sc, buf, sizeof(buf), ssc->sc_unit, sc->sc_subunit); } if (buf[0] == 0) { /* Use default TTY name */ if (ssc->sc_subunits > 1) { /* multiple modems in one */ ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u", ssc->sc_unit, sc->sc_subunit); } else { /* single modem */ ksnprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u", ssc->sc_unit); } } dev = make_dev(&ucom_ops, ssc->sc_unit | 0x80, // XXX UCOM_CALLOUT_MASK, UID_UUCP, GID_DIALER, 0660, buf, ssc->sc_unit); dev->si_tty = tp; sc->sc_tty = tp; dev->si_drv1 = sc; DPRINTF("ttycreate: %s\n", buf); /* Check if this device should be a console */ if ((ucom_cons_softc == NULL) && (ssc->sc_unit == ucom_cons_unit) && (sc->sc_subunit == ucom_cons_subunit)) { DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit); ucom_cons_softc = sc; /* XXXDF tty_init_console(tp, ucom_cons_baud); */ tp->t_termios.c_ispeed = ucom_cons_baud; tp->t_termios.c_ospeed = ucom_cons_baud; UCOM_MTX_LOCK(ucom_cons_softc); ucom_cons_rx_low = 0; ucom_cons_rx_high = 0; ucom_cons_tx_low = 0; ucom_cons_tx_high = 0; sc->sc_flag |= UCOM_FLAG_CONSOLE; ucom_open(ucom_cons_softc); ucom_param(tp, &tp->t_termios); UCOM_MTX_UNLOCK(ucom_cons_softc); } lwkt_reltoken(&tty_token); return (0); }
static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { struct tty *tp; char buf[32]; /* temporary TTY device name buffer */ tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx); if (tp == NULL) return (ENOMEM); /* Check if the client has a custom TTY name */ buf[0] = '\0'; if (sc->sc_callback->ucom_tty_name) { sc->sc_callback->ucom_tty_name(sc, buf, sizeof(buf), ssc->sc_unit, sc->sc_subunit); } if (buf[0] == 0) { /* Use default TTY name */ if (ssc->sc_subunits > 1) { /* multiple modems in one */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u.%u", ssc->sc_unit, sc->sc_subunit); } else { /* single modem */ snprintf(buf, sizeof(buf), UCOM_TTY_PREFIX "%u", ssc->sc_unit); } } tty_makedev(tp, NULL, "%s", buf); sc->sc_tty = tp; sc->sc_pps.ppscap = PPS_CAPTUREBOTH; sc->sc_pps.driver_abi = PPS_ABI_VERSION; sc->sc_pps.driver_mtx = sc->sc_mtx; pps_init_abi(&sc->sc_pps); DPRINTF("ttycreate: %s\n", buf); /* Check if this device should be a console */ if ((ucom_cons_softc == NULL) && (ssc->sc_unit == ucom_cons_unit) && (sc->sc_subunit == ucom_cons_subunit)) { DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit); ucom_cons_softc = sc; tty_init_console(tp, ucom_cons_baud); UCOM_MTX_LOCK(ucom_cons_softc); ucom_cons_rx_low = 0; ucom_cons_rx_high = 0; ucom_cons_tx_low = 0; ucom_cons_tx_high = 0; sc->sc_flag |= UCOM_FLAG_CONSOLE; ucom_open(ucom_cons_softc->sc_tty); ucom_param(ucom_cons_softc->sc_tty, &tp->t_termios_init_in); 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); }