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