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