summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-09-17 11:43:35 +0000
committerphk <phk@FreeBSD.org>2004-09-17 11:43:35 +0000
commit1b1b81c0fc889ea09bf6e64a5daa027a55855ae5 (patch)
tree2f28eef1d58e8a66b92feb6a39ec91e7f6ed6267
parent198dc4fcc7cf00d82065df01aee83b9c80fc01cf (diff)
downloadFreeBSD-src-1b1b81c0fc889ea09bf6e64a5daa027a55855ae5.zip
FreeBSD-src-1b1b81c0fc889ea09bf6e64a5daa027a55855ae5.tar.gz
Add ttyopen and ttyclose functions which will do the right stuff for
most if not all of our tty drivers in the future. Centralizing this stuff enables us to remove about 100 lines of almost but not quite perfectly copy&paste code from each tty driver.
-rw-r--r--sys/kern/tty.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index f95b9ff..87c7849 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -104,6 +104,7 @@ __FBSDID("$FreeBSD$");
#include <sys/filedesc.h>
#include <sys/sched.h>
#include <sys/sysctl.h>
+#include <sys/timepps.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@@ -2879,6 +2880,102 @@ nottystop(struct tty *tp, int rw)
}
int
+ttyopen(struct cdev *dev, int flag, int mode, struct thread *td)
+{
+ int error;
+ int s;
+ struct tty *tp;
+
+ tp = dev->si_tty;
+ s = spltty();
+ /*
+ * We jump to this label after all non-interrupted sleeps to pick
+ * up any changes of the device state.
+ */
+open_top:
+ if (tp->t_state & TS_GONE)
+ return (ENXIO);
+ error = ttydtrwaitsleep(tp);
+ if (error)
+ goto out;
+ if (tp->t_state & TS_ISOPEN) {
+ /*
+ * The device is open, so everything has been initialized.
+ * Handle conflicts.
+ */
+ if (ISCALLOUT(dev) && !tp->t_actout)
+ return (EBUSY);
+ if (tp->t_actout && !ISCALLOUT(dev)) {
+ if (flag & O_NONBLOCK)
+ return (EBUSY);
+ error = tsleep(&tp->t_actout,
+ TTIPRI | PCATCH, "siobi", 0);
+ if (error != 0 || (tp->t_flags & TS_GONE))
+ goto out;
+ goto open_top;
+ }
+ if (tp->t_state & TS_XCLUDE && suser(td))
+ return (EBUSY);
+ } else {
+ /*
+ * The device isn't open, so there are no conflicts.
+ * Initialize it. Initialization is done twice in many
+ * cases: to preempt sleeping callin opens if we are
+ * callout, and to complete a callin open after DCD rises.
+ */
+ tp->t_termios = ISCALLOUT(dev) ? tp->t_init_out : tp->t_init_in;
+ tp->t_modem(tp, SER_DTR | SER_RTS, 0);
+ ++tp->t_wopeners;
+ error = tp->t_param(tp, &tp->t_termios);
+ --tp->t_wopeners;
+ if (error == 0 && tp->t_open != NULL)
+ error = tp->t_open(tp, dev);
+ if (error != 0)
+ goto out;
+ if (ISCALLOUT(dev) || (tp->t_modem(tp, 0, 0) & SER_DCD))
+ ttyld_modem(tp, 1);
+ }
+ /*
+ * Wait for DCD if necessary.
+ */
+ if (!(tp->t_state & TS_CARR_ON) && !ISCALLOUT(dev)
+ && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
+ ++tp->t_wopeners;
+ error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "ttydcd", 0);
+ --tp->t_wopeners;
+ if (error != 0 || (tp->t_state & TS_GONE))
+ goto out;
+ goto open_top;
+ }
+ error = ttyld_open(tp, dev);
+ ttyldoptim(tp);
+ if (tp->t_state & TS_ISOPEN && ISCALLOUT(dev))
+ tp->t_actout = TRUE;
+out:
+ splx(s);
+ if (!(tp->t_state & TS_ISOPEN) && tp->t_wopeners == 0)
+ tp->t_close(tp);
+ return (error);
+}
+
+int
+ttyclose(struct cdev *dev, int flag, int mode, struct thread *td)
+{
+ struct tty *tp;
+
+ tp = dev->si_tty;
+ ttyld_close(tp, flag);
+ ttyldoptim(tp);
+ tp->t_close(tp);
+ tty_close(tp);
+ tp->t_do_timestamp = 0;
+ if (tp->t_pps != NULL)
+ tp->t_pps->ppsparam.mode = 0;
+ return (0);
+}
+
+
+int
ttyread(struct cdev *dev, struct uio *uio, int flag)
{
struct tty *tp;
OpenPOWER on IntegriCloud