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