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);
}
예제 #2
0
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);
	}
}
예제 #3
0
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);
}
예제 #4
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;

	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);
}
예제 #5
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;
}
예제 #6
0
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
}
예제 #7
0
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);
}
예제 #8
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 */
	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);
}
예제 #9
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);
}