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