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