Home | History | Annotate | Line # | Download | only in kern
tty_conf.c revision 1.55
      1 /*	$NetBSD: tty_conf.c,v 1.55 2008/04/28 20:24:05 martin Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*-
     33  * Copyright (c) 1982, 1986, 1991, 1993
     34  *	The Regents of the University of California.  All rights reserved.
     35  * (c) UNIX System Laboratories, Inc.
     36  * All or some portions of this file are derived from material licensed
     37  * to the University of California by American Telephone and Telegraph
     38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     39  * the permission of UNIX System Laboratories, Inc.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. Neither the name of the University nor the names of its contributors
     50  *    may be used to endorse or promote products derived from this software
     51  *    without specific prior written permission.
     52  *
     53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     63  * SUCH DAMAGE.
     64  *
     65  *	@(#)tty_conf.c	8.5 (Berkeley) 1/9/95
     66  */
     67 
     68 #include <sys/cdefs.h>
     69 __KERNEL_RCSID(0, "$NetBSD: tty_conf.c,v 1.55 2008/04/28 20:24:05 martin Exp $");
     70 
     71 #include <sys/param.h>
     72 #include <sys/systm.h>
     73 #include <sys/poll.h>
     74 #include <sys/proc.h>
     75 #include <sys/tty.h>
     76 #include <sys/ttycom.h>
     77 #include <sys/conf.h>
     78 #include <sys/mutex.h>
     79 #include <sys/queue.h>
     80 
     81 static struct linesw termios_disc = {
     82 	.l_name = "termios",
     83 	.l_open = ttylopen,
     84 	.l_close = ttylclose,
     85 	.l_read = ttread,
     86 	.l_write = ttwrite,
     87 	.l_ioctl = ttynullioctl,
     88 	.l_rint = ttyinput,
     89 	.l_start = ttstart,
     90 	.l_modem = ttymodem,
     91 	.l_poll = ttpoll
     92 };
     93 
     94 /*
     95  * This is for the benefit of old BSD TTY compatbility, but since it is
     96  * identical to termios (except for the name), don't bother conditionalizing
     97  * it.
     98  */
     99 static struct linesw ntty_disc = {	/* old NTTYDISC */
    100 	.l_name = "ntty",
    101 	.l_open = ttylopen,
    102 	.l_close = ttylclose,
    103 	.l_read = ttread,
    104 	.l_write = ttwrite,
    105 	.l_ioctl = ttynullioctl,
    106 	.l_rint = ttyinput,
    107 	.l_start = ttstart,
    108 	.l_modem = ttymodem,
    109 	.l_poll = ttpoll
    110 };
    111 
    112 static LIST_HEAD(, linesw) ttyldisc_list = LIST_HEAD_INITIALIZER(ttyldisc_head);
    113 
    114 /*
    115  * Note: We don't bother refcounting termios_disc and ntty_disc; they can't
    116  * be removed from the list, and termios_disc is likely to have very many
    117  * references (could we overflow the count?).
    118  */
    119 #define	TTYLDISC_ISSTATIC(disc)					\
    120 	((disc) == &termios_disc || (disc) == &ntty_disc)
    121 
    122 #define	TTYLDISC_HOLD(disc)					\
    123 do {								\
    124 	if (! TTYLDISC_ISSTATIC(disc)) {			\
    125 		KASSERT((disc)->l_refcnt != UINT_MAX);		\
    126 		(disc)->l_refcnt++;				\
    127 	}							\
    128 } while (/*CONSTCOND*/0)
    129 
    130 #define	TTYLDISC_RELE(disc)					\
    131 do {								\
    132 	if (! TTYLDISC_ISSTATIC(disc)) {			\
    133 		KASSERT((disc)->l_refcnt != 0);			\
    134 		(disc)->l_refcnt--;				\
    135 	}							\
    136 } while (/*CONSTCOND*/0)
    137 
    138 #define	TTYLDISC_ISINUSE(disc)					\
    139 	(TTYLDISC_ISSTATIC(disc) || (disc)->l_refcnt != 0)
    140 
    141 /*
    142  * Do nothing specific version of line
    143  * discipline specific ioctl command.
    144  */
    145 /*ARGSUSED*/
    146 int
    147 ttynullioctl(struct tty *tp, u_long cmd, void *data, int flags, struct lwp *l)
    148 {
    149 
    150 	return (EPASSTHROUGH);
    151 }
    152 
    153 /*
    154  * Return error to line discipline
    155  * specific poll call.
    156  */
    157 /*ARGSUSED*/
    158 int
    159 ttyerrpoll(struct tty *tp, int events, struct lwp *l)
    160 {
    161 
    162 	return (POLLERR);
    163 }
    164 
    165 void
    166 ttyldisc_init(void)
    167 {
    168 
    169 	if (ttyldisc_attach(&termios_disc) != 0)
    170 		panic("ttyldisc_init: termios_disc");
    171 	if (ttyldisc_attach(&ntty_disc) != 0)
    172 		panic("ttyldisc_init: ntty_disc");
    173 }
    174 
    175 static struct linesw *
    176 ttyldisc_lookup_locked(const char *name)
    177 {
    178 	struct linesw *disc;
    179 
    180 	LIST_FOREACH(disc, &ttyldisc_list, l_list) {
    181 		if (strcmp(name, disc->l_name) == 0)
    182 			return (disc);
    183 	}
    184 
    185 	return (NULL);
    186 }
    187 
    188 /*
    189  * Look up a line discipline by its name.  Caller holds a reference on
    190  * the returned line discipline.
    191  */
    192 struct linesw *
    193 ttyldisc_lookup(const char *name)
    194 {
    195 	struct linesw *disc;
    196 
    197 	mutex_spin_enter(&tty_lock);
    198 	disc = ttyldisc_lookup_locked(name);
    199 	if (disc != NULL)
    200 		TTYLDISC_HOLD(disc);
    201 	mutex_spin_exit(&tty_lock);
    202 
    203 	return (disc);
    204 }
    205 
    206 /*
    207  * Look up a line discipline by its legacy number.  Caller holds a
    208  * reference on the returned line discipline.
    209  */
    210 struct linesw *
    211 ttyldisc_lookup_bynum(int num)
    212 {
    213 	struct linesw *disc;
    214 
    215 	mutex_spin_enter(&tty_lock);
    216 
    217 	LIST_FOREACH(disc, &ttyldisc_list, l_list) {
    218 		if (disc->l_no == num) {
    219 			TTYLDISC_HOLD(disc);
    220 			mutex_spin_exit(&tty_lock);
    221 			return (disc);
    222 		}
    223 	}
    224 
    225 	mutex_spin_exit(&tty_lock);
    226 	return (NULL);
    227 }
    228 
    229 /*
    230  * Release a reference on a line discipline previously added by
    231  * ttyldisc_lookup() or ttyldisc_lookup_bynum().
    232  */
    233 void
    234 ttyldisc_release(struct linesw *disc)
    235 {
    236 
    237 	if (disc == NULL)
    238 		return;
    239 
    240 	mutex_spin_enter(&tty_lock);
    241 	TTYLDISC_RELE(disc);
    242 	mutex_spin_exit(&tty_lock);
    243 }
    244 
    245 #define	TTYLDISC_LEGACY_NUMBER_MIN	10
    246 #define	TTYLDISC_LEGACY_NUMBER_MAX	INT_MAX
    247 
    248 static void
    249 ttyldisc_assign_legacy_number(struct linesw *disc)
    250 {
    251 	static const struct {
    252 		const char *name;
    253 		int num;
    254 	} table[] = {
    255 		{ "termios",		TTYDISC },
    256 		{ "ntty",		2 /* XXX old NTTYDISC */ },
    257 		{ "tablet",		TABLDISC },
    258 		{ "slip",		SLIPDISC },
    259 		{ "ppp",		PPPDISC },
    260 		{ "strip",		STRIPDISC },
    261 		{ "hdlc",		HDLCDISC },
    262 		{ NULL,			0 }
    263 	};
    264 	struct linesw *ldisc;
    265 	int i;
    266 
    267 	for (i = 0; table[i].name != NULL; i++) {
    268 		if (strcmp(disc->l_name, table[i].name) == 0) {
    269 			disc->l_no = table[i].num;
    270 			return;
    271 		}
    272 	}
    273 
    274 	disc->l_no = TTYLDISC_LEGACY_NUMBER_MIN;
    275 
    276 	LIST_FOREACH(ldisc, &ttyldisc_list, l_list) {
    277 		if (disc->l_no == ldisc->l_no) {
    278 			KASSERT(disc->l_no < TTYLDISC_LEGACY_NUMBER_MAX);
    279 			disc->l_no++;
    280 		}
    281 	}
    282 }
    283 
    284 /*
    285  * Register a line discipline.
    286  */
    287 int
    288 ttyldisc_attach(struct linesw *disc)
    289 {
    290 
    291 	KASSERT(disc->l_name != NULL);
    292 	KASSERT(disc->l_open != NULL);
    293 	KASSERT(disc->l_close != NULL);
    294 	KASSERT(disc->l_read != NULL);
    295 	KASSERT(disc->l_write != NULL);
    296 	KASSERT(disc->l_ioctl != NULL);
    297 	KASSERT(disc->l_rint != NULL);
    298 	KASSERT(disc->l_start != NULL);
    299 	KASSERT(disc->l_modem != NULL);
    300 	KASSERT(disc->l_poll != NULL);
    301 
    302 	/* You are not allowed to exceed TTLINEDNAMELEN */
    303 	if (strlen(disc->l_name) >= TTLINEDNAMELEN)
    304 		return (ENAMETOOLONG);
    305 
    306 	mutex_spin_enter(&tty_lock);
    307 
    308 	if (ttyldisc_lookup_locked(disc->l_name) != NULL) {
    309 		mutex_spin_exit(&tty_lock);
    310 		return (EEXIST);
    311 	}
    312 
    313 	ttyldisc_assign_legacy_number(disc);
    314 	LIST_INSERT_HEAD(&ttyldisc_list, disc, l_list);
    315 
    316 	mutex_spin_exit(&tty_lock);
    317 
    318 	return (0);
    319 }
    320 
    321 /*
    322  * Remove a line discipline.
    323  */
    324 int
    325 ttyldisc_detach(struct linesw *disc)
    326 {
    327 #ifdef DIAGNOSTIC
    328 	struct linesw *ldisc = ttyldisc_lookup(disc->l_name);
    329 
    330 	KASSERT(ldisc != NULL);
    331 	KASSERT(ldisc == disc);
    332 	ttyldisc_release(ldisc);
    333 #endif
    334 
    335 	mutex_spin_enter(&tty_lock);
    336 
    337 	if (TTYLDISC_ISINUSE(disc)) {
    338 		mutex_spin_exit(&tty_lock);
    339 		return (EBUSY);
    340 	}
    341 
    342 	LIST_REMOVE(disc, l_list);
    343 
    344 	mutex_spin_exit(&tty_lock);
    345 
    346 	return (0);
    347 }
    348 
    349 /*
    350  * Return the default line discipline.
    351  */
    352 struct linesw *
    353 ttyldisc_default(void)
    354 {
    355 
    356 	return (&termios_disc);
    357 }
    358