1 /* $NetBSD: cons.c,v 1.53 2004/05/16 15:44:11 wiz 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.53 2004/05/16 15:44:11 wiz 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/tty.h> 90 #include <sys/file.h> 91 #include <sys/conf.h> 92 #include <sys/vnode.h> 93 94 #include <dev/cons.h> 95 96 dev_type_open(cnopen); 97 dev_type_close(cnclose); 98 dev_type_read(cnread); 99 dev_type_write(cnwrite); 100 dev_type_ioctl(cnioctl); 101 dev_type_poll(cnpoll); 102 dev_type_kqfilter(cnkqfilter); 103 104 static const struct cdevsw *cn_redirect(dev_t *, int, int *); 105 106 const struct cdevsw cons_cdevsw = { 107 cnopen, cnclose, cnread, cnwrite, cnioctl, 108 nostop, notty, cnpoll, nommap, cnkqfilter, D_TTY 109 }; 110 111 struct tty *constty = NULL; /* virtual console output device */ 112 struct consdev *cn_tab; /* physical console device info */ 113 struct vnode *cn_devvp[2]; /* vnode for underlying device. */ 114 115 int 116 cnopen(dev_t dev, int flag, int mode, struct proc *p) 117 { 118 const struct cdevsw *cdev; 119 dev_t cndev; 120 int unit; 121 122 unit = minor(dev); 123 if (unit > 1) 124 return ENODEV; 125 126 if (cn_tab == NULL) 127 return (0); 128 129 /* 130 * always open the 'real' console device, so we don't get nailed 131 * later. This follows normal device semantics; they always get 132 * open() calls. 133 */ 134 cndev = cn_tab->cn_dev; 135 if (cndev == NODEV) { 136 /* 137 * This is most likely an error in the console attach 138 * code. Panicking looks better than jumping into nowhere 139 * through cdevsw below.... 140 */ 141 panic("cnopen: no console device"); 142 } 143 if (dev == cndev) { 144 /* 145 * This causes cnopen() to be called recursively, which 146 * is generally a bad thing. It is often caused when 147 * dev == 0 and cn_dev has not been set, but was probably 148 * initialised to 0. 149 */ 150 panic("cnopen: cn_tab->cn_dev == dev"); 151 } 152 cdev = cdevsw_lookup(cndev); 153 if (cdev == NULL) 154 return (ENXIO); 155 156 if (cn_devvp[unit] == NULLVP) { 157 /* try to get a reference on its vnode, but fail silently */ 158 cdevvp(cndev, &cn_devvp[unit]); 159 } 160 return ((*cdev->d_open)(cndev, flag, mode, p)); 161 } 162 163 int 164 cnclose(dev_t dev, int flag, int mode, struct proc *p) 165 { 166 const struct cdevsw *cdev; 167 struct vnode *vp; 168 int unit; 169 170 unit = minor(dev); 171 172 if (cn_tab == NULL) 173 return (0); 174 175 /* 176 * If the real console isn't otherwise open, close it. 177 * If it's otherwise open, don't close it, because that'll 178 * screw up others who have it open. 179 */ 180 dev = cn_tab->cn_dev; 181 cdev = cdevsw_lookup(dev); 182 if (cdev == NULL) 183 return (ENXIO); 184 if (cn_devvp[unit] != NULLVP) { 185 /* release our reference to real dev's vnode */ 186 vrele(cn_devvp[unit]); 187 cn_devvp[unit] = NULLVP; 188 } 189 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 190 return (0); 191 return ((*cdev->d_close)(dev, flag, mode, p)); 192 } 193 194 int 195 cnread(dev_t dev, struct uio *uio, int flag) 196 { 197 const struct cdevsw *cdev; 198 int error; 199 200 /* 201 * If we would redirect input, punt. This will keep strange 202 * things from happening to people who are using the real 203 * console. Nothing should be using /dev/console for 204 * input (except a shell in single-user mode, but then, 205 * one wouldn't TIOCCONS then). 206 */ 207 cdev = cn_redirect(&dev, 1, &error); 208 if (cdev == NULL) 209 return error; 210 return ((*cdev->d_read)(dev, uio, flag)); 211 } 212 213 int 214 cnwrite(dev_t dev, struct uio *uio, int flag) 215 { 216 const struct cdevsw *cdev; 217 int error; 218 219 /* Redirect output, if that's appropriate. */ 220 cdev = cn_redirect(&dev, 0, &error); 221 if (cdev == NULL) 222 return error; 223 224 return ((*cdev->d_write)(dev, uio, flag)); 225 } 226 227 int 228 cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 229 { 230 const struct cdevsw *cdev; 231 int error; 232 233 /* 234 * Superuser can always use this to wrest control of console 235 * output from the "virtual" console. 236 */ 237 if (cmd == TIOCCONS && constty != NULL) { 238 error = suser(p->p_ucred, (u_short *) NULL); 239 if (error) 240 return (error); 241 constty = NULL; 242 return (0); 243 } 244 245 /* 246 * Redirect the ioctl, if that's appropriate. 247 * Note that strange things can happen, if a program does 248 * ioctls on /dev/console, then the console is redirected 249 * out from under it. 250 */ 251 cdev = cn_redirect(&dev, 0, &error); 252 if (cdev == NULL) 253 return error; 254 return ((*cdev->d_ioctl)(dev, cmd, data, flag, p)); 255 } 256 257 /*ARGSUSED*/ 258 int 259 cnpoll(dev_t dev, int events, struct proc *p) 260 { 261 const struct cdevsw *cdev; 262 int error; 263 264 /* 265 * Redirect the poll, if that's appropriate. 266 * I don't want to think of the possible side effects 267 * of console redirection here. 268 */ 269 cdev = cn_redirect(&dev, 0, &error); 270 if (cdev == NULL) 271 return error; 272 return ((*cdev->d_poll)(dev, events, p)); 273 } 274 275 /*ARGSUSED*/ 276 int 277 cnkqfilter(dev_t dev, struct knote *kn) 278 { 279 const struct cdevsw *cdev; 280 int error; 281 282 /* 283 * Redirect the kqfilter, if that's appropriate. 284 * I don't want to think of the possible side effects 285 * of console redirection here. 286 */ 287 cdev = cn_redirect(&dev, 0, &error); 288 if (cdev == NULL) 289 return error; 290 return ((*cdev->d_kqfilter)(dev, kn)); 291 } 292 293 int 294 cngetc(void) 295 { 296 if (cn_tab == NULL) 297 return (0); 298 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 299 } 300 301 int 302 cngetsn(char *cp, int size) 303 { 304 char *lp; 305 int c, len; 306 307 cnpollc(1); 308 309 lp = cp; 310 len = 0; 311 for (;;) { 312 c = cngetc(); 313 switch (c) { 314 case '\n': 315 case '\r': 316 printf("\n"); 317 *lp++ = '\0'; 318 cnpollc(0); 319 return (len); 320 case '\b': 321 case '\177': 322 case '#': 323 if (len) { 324 --len; 325 --lp; 326 printf("\b \b"); 327 } 328 continue; 329 case '@': 330 case 'u'&037: /* CTRL-u */ 331 len = 0; 332 lp = cp; 333 printf("\n"); 334 continue; 335 default: 336 if (len + 1 >= size || c < ' ') { 337 printf("\007"); 338 continue; 339 } 340 printf("%c", c); 341 ++len; 342 *lp++ = c; 343 } 344 } 345 } 346 347 void 348 cnputc(int c) 349 { 350 351 if (cn_tab == NULL) 352 return; 353 354 if (c) { 355 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 356 if (c == '\n') 357 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 358 } 359 } 360 361 void 362 cnpollc(int on) 363 { 364 static int refcount = 0; 365 366 if (cn_tab == NULL) 367 return; 368 if (!on) 369 --refcount; 370 if (refcount == 0) 371 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 372 if (on) 373 ++refcount; 374 } 375 376 void 377 nullcnpollc(dev_t dev, int on) 378 { 379 380 } 381 382 void 383 cnbell(u_int pitch, u_int period, u_int volume) 384 { 385 386 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 387 return; 388 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 389 } 390 391 void 392 cnflush(void) 393 { 394 if (cn_tab == NULL || cn_tab->cn_flush == NULL) 395 return; 396 (*cn_tab->cn_flush)(cn_tab->cn_dev); 397 } 398 399 void 400 cnhalt(void) 401 { 402 if (cn_tab == NULL || cn_tab->cn_halt == NULL) 403 return; 404 (*cn_tab->cn_halt)(cn_tab->cn_dev); 405 } 406 407 static const struct cdevsw * 408 cn_redirect(dev_t *devp, int is_read, int *error) 409 { 410 dev_t dev = *devp; 411 412 /* 413 * Redirect output, if that's appropriate. 414 * If there's no real console, return ENXIO. 415 */ 416 *error = ENXIO; 417 if (constty != NULL && minor(dev) == 0 && 418 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE ))) { 419 if (is_read) { 420 *error = 0; 421 return NULL; 422 } 423 dev = constty->t_dev; 424 } else if (cn_tab == NULL) 425 return NULL; 426 else 427 dev = cn_tab->cn_dev; 428 *devp = dev; 429 return cdevsw_lookup(dev); 430 } 431