1 /* $NetBSD: cons.c,v 1.57 2005/12/11 12:20:53 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 36 * 37 * @(#)cons.c 8.2 (Berkeley) 1/12/94 38 */ 39 40 /* 41 * Copyright (c) 1988 University of Utah. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * the Systems Programming Group of the University of Utah Computer 45 * Science Department. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 76 * 77 * @(#)cons.c 8.2 (Berkeley) 1/12/94 78 */ 79 80 #include <sys/cdefs.h> 81 __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.57 2005/12/11 12:20:53 christos Exp $"); 82 83 #include <sys/param.h> 84 #include <sys/proc.h> 85 #include <sys/user.h> 86 #include <sys/systm.h> 87 #include <sys/buf.h> 88 #include <sys/ioctl.h> 89 #include <sys/poll.h> 90 #include <sys/tty.h> 91 #include <sys/file.h> 92 #include <sys/conf.h> 93 #include <sys/vnode.h> 94 95 #include <dev/cons.h> 96 97 dev_type_open(cnopen); 98 dev_type_close(cnclose); 99 dev_type_read(cnread); 100 dev_type_write(cnwrite); 101 dev_type_ioctl(cnioctl); 102 dev_type_poll(cnpoll); 103 dev_type_kqfilter(cnkqfilter); 104 105 static const struct cdevsw *cn_redirect(dev_t *, int, int *); 106 107 const struct cdevsw cons_cdevsw = { 108 cnopen, cnclose, cnread, cnwrite, cnioctl, 109 nostop, notty, cnpoll, nommap, cnkqfilter, D_TTY 110 }; 111 112 struct tty *constty = NULL; /* virtual console output device */ 113 struct consdev *cn_tab; /* physical console device info */ 114 struct vnode *cn_devvp[2]; /* vnode for underlying device. */ 115 116 int 117 cnopen(dev_t dev, int flag, int mode, struct lwp *l) 118 { 119 const struct cdevsw *cdev; 120 dev_t cndev; 121 int unit; 122 123 unit = minor(dev); 124 if (unit > 1) 125 return ENODEV; 126 127 if (cn_tab == NULL) 128 return (0); 129 130 /* 131 * always open the 'real' console device, so we don't get nailed 132 * later. This follows normal device semantics; they always get 133 * open() calls. 134 */ 135 cndev = cn_tab->cn_dev; 136 if (cndev == NODEV) { 137 /* 138 * This is most likely an error in the console attach 139 * code. Panicking looks better than jumping into nowhere 140 * through cdevsw below.... 141 */ 142 panic("cnopen: no console device"); 143 } 144 if (dev == cndev) { 145 /* 146 * This causes cnopen() to be called recursively, which 147 * is generally a bad thing. It is often caused when 148 * dev == 0 and cn_dev has not been set, but was probably 149 * initialised to 0. 150 */ 151 panic("cnopen: cn_tab->cn_dev == dev"); 152 } 153 cdev = cdevsw_lookup(cndev); 154 if (cdev == NULL) 155 return (ENXIO); 156 157 if (cn_devvp[unit] == NULLVP) { 158 /* try to get a reference on its vnode, but fail silently */ 159 cdevvp(cndev, &cn_devvp[unit]); 160 } 161 return ((*cdev->d_open)(cndev, flag, mode, l)); 162 } 163 164 int 165 cnclose(dev_t dev, int flag, int mode, struct lwp *l) 166 { 167 const struct cdevsw *cdev; 168 struct vnode *vp; 169 int unit; 170 171 unit = minor(dev); 172 173 if (cn_tab == NULL) 174 return (0); 175 176 /* 177 * If the real console isn't otherwise open, close it. 178 * If it's otherwise open, don't close it, because that'll 179 * screw up others who have it open. 180 */ 181 dev = cn_tab->cn_dev; 182 cdev = cdevsw_lookup(dev); 183 if (cdev == NULL) 184 return (ENXIO); 185 if (cn_devvp[unit] != NULLVP) { 186 /* release our reference to real dev's vnode */ 187 vrele(cn_devvp[unit]); 188 cn_devvp[unit] = NULLVP; 189 } 190 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 191 return (0); 192 return ((*cdev->d_close)(dev, flag, mode, l)); 193 } 194 195 int 196 cnread(dev_t dev, struct uio *uio, int flag) 197 { 198 const struct cdevsw *cdev; 199 int error; 200 201 /* 202 * If we would redirect input, punt. This will keep strange 203 * things from happening to people who are using the real 204 * console. Nothing should be using /dev/console for 205 * input (except a shell in single-user mode, but then, 206 * one wouldn't TIOCCONS then). 207 */ 208 cdev = cn_redirect(&dev, 1, &error); 209 if (cdev == NULL) 210 return error; 211 return ((*cdev->d_read)(dev, uio, flag)); 212 } 213 214 int 215 cnwrite(dev_t dev, struct uio *uio, int flag) 216 { 217 const struct cdevsw *cdev; 218 int error; 219 220 /* Redirect output, if that's appropriate. */ 221 cdev = cn_redirect(&dev, 0, &error); 222 if (cdev == NULL) 223 return error; 224 225 return ((*cdev->d_write)(dev, uio, flag)); 226 } 227 228 int 229 cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 230 { 231 const struct cdevsw *cdev; 232 int error; 233 234 /* 235 * Superuser can always use this to wrest control of console 236 * output from the "virtual" console. 237 */ 238 if (cmd == TIOCCONS && constty != NULL) { 239 error = suser(l->l_proc->p_ucred, (u_short *) NULL); 240 if (error) 241 return (error); 242 constty = NULL; 243 return (0); 244 } 245 246 /* 247 * Redirect the ioctl, if that's appropriate. 248 * Note that strange things can happen, if a program does 249 * ioctls on /dev/console, then the console is redirected 250 * out from under it. 251 */ 252 cdev = cn_redirect(&dev, 0, &error); 253 if (cdev == NULL) 254 return error; 255 return ((*cdev->d_ioctl)(dev, cmd, data, flag, l)); 256 } 257 258 /*ARGSUSED*/ 259 int 260 cnpoll(dev_t dev, int events, struct lwp *l) 261 { 262 const struct cdevsw *cdev; 263 int error; 264 265 /* 266 * Redirect the poll, if that's appropriate. 267 * I don't want to think of the possible side effects 268 * of console redirection here. 269 */ 270 cdev = cn_redirect(&dev, 0, &error); 271 if (cdev == NULL) 272 return POLLHUP; 273 return ((*cdev->d_poll)(dev, events, l)); 274 } 275 276 /*ARGSUSED*/ 277 int 278 cnkqfilter(dev_t dev, struct knote *kn) 279 { 280 const struct cdevsw *cdev; 281 int error; 282 283 /* 284 * Redirect the kqfilter, if that's appropriate. 285 * I don't want to think of the possible side effects 286 * of console redirection here. 287 */ 288 cdev = cn_redirect(&dev, 0, &error); 289 if (cdev == NULL) 290 return error; 291 return ((*cdev->d_kqfilter)(dev, kn)); 292 } 293 294 int 295 cngetc(void) 296 { 297 if (cn_tab == NULL) 298 return (0); 299 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 300 } 301 302 int 303 cngetsn(char *cp, int size) 304 { 305 char *lp; 306 int c, len; 307 308 cnpollc(1); 309 310 lp = cp; 311 len = 0; 312 for (;;) { 313 c = cngetc(); 314 switch (c) { 315 case '\n': 316 case '\r': 317 printf("\n"); 318 *lp++ = '\0'; 319 cnpollc(0); 320 return (len); 321 case '\b': 322 case '\177': 323 case '#': 324 if (len) { 325 --len; 326 --lp; 327 printf("\b \b"); 328 } 329 continue; 330 case '@': 331 case 'u'&037: /* CTRL-u */ 332 len = 0; 333 lp = cp; 334 printf("\n"); 335 continue; 336 default: 337 if (len + 1 >= size || c < ' ') { 338 printf("\007"); 339 continue; 340 } 341 printf("%c", c); 342 ++len; 343 *lp++ = c; 344 } 345 } 346 } 347 348 void 349 cnputc(int c) 350 { 351 352 if (cn_tab == NULL) 353 return; 354 355 if (c) { 356 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 357 if (c == '\n') 358 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 359 } 360 } 361 362 void 363 cnpollc(int on) 364 { 365 static int refcount = 0; 366 367 if (cn_tab == NULL) 368 return; 369 if (!on) 370 --refcount; 371 if (refcount == 0) 372 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 373 if (on) 374 ++refcount; 375 } 376 377 void 378 nullcnpollc(dev_t dev, int on) 379 { 380 381 } 382 383 void 384 cnbell(u_int pitch, u_int period, u_int volume) 385 { 386 387 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 388 return; 389 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 390 } 391 392 void 393 cnflush(void) 394 { 395 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 396 return; 397 (*cn_tab->cn_flush)(cn_tab->cn_dev); 398 } 399 400 void 401 cnhalt(void) 402 { 403 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 404 return; 405 (*cn_tab->cn_halt)(cn_tab->cn_dev); 406 } 407 408 static const struct cdevsw * 409 cn_redirect(dev_t *devp, int is_read, int *error) 410 { 411 dev_t dev = *devp; 412 413 /* 414 * Redirect output, if that's appropriate. 415 * If there's no real console, return ENXIO. 416 */ 417 *error = ENXIO; 418 if (constty != NULL && minor(dev) == 0 && 419 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) { 420 if (is_read) { 421 *error = 0; 422 return NULL; 423 } 424 dev = constty->t_dev; 425 } else if (cn_tab == NULL) 426 return NULL; 427 else 428 dev = cn_tab->cn_dev; 429 *devp = dev; 430 return cdevsw_lookup(dev); 431 } 432