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