1 /* $OpenBSD: cons.c,v 1.26 2016/05/17 23:43:47 bluhm Exp $ */ 2 /* $NetBSD: cons.c,v 1.30 1996/04/08 19:57:30 jonathan Exp $ */ 3 4 /* 5 * Copyright (c) 1988 University of Utah. 6 * Copyright (c) 1990, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * the Systems Programming Group of the University of Utah Computer 11 * Science Department. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: Utah $Hdr: cons.c 1.7 92/01/21$ 38 * 39 * @(#)cons.c 8.2 (Berkeley) 1/12/94 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/ioctl.h> 45 #include <sys/tty.h> 46 #include <sys/file.h> 47 #include <sys/conf.h> 48 #include <sys/vnode.h> 49 #include <sys/poll.h> 50 51 #include <dev/cons.h> 52 53 struct tty *constty = NULL; /* virtual console output device */ 54 struct vnode *cn_devvp = NULLVP; /* vnode for underlying device. */ 55 56 int 57 cnopen(dev_t dev, int flag, int mode, struct proc *p) 58 { 59 dev_t cndev; 60 61 if (cn_tab == NULL) 62 return (0); 63 64 /* 65 * always open the 'real' console device, so we don't get nailed 66 * later. This follows normal device semantics; they always get 67 * open() calls. 68 */ 69 cndev = cn_tab->cn_dev; 70 if (cndev == NODEV) 71 return (ENXIO); 72 #ifdef DIAGNOSTIC 73 if (cndev == dev) 74 panic("cnopen: recursive"); 75 #endif 76 if (cn_devvp == NULLVP) { 77 /* try to get a reference on its vnode, but fail silently */ 78 cdevvp(cndev, &cn_devvp); 79 } 80 return ((*cdevsw[major(cndev)].d_open)(cndev, flag, mode, p)); 81 } 82 83 int 84 cnclose(dev_t dev, int flag, int mode, struct proc *p) 85 { 86 struct vnode *vp; 87 88 if (cn_tab == NULL) 89 return (0); 90 91 /* 92 * If the real console isn't otherwise open, close it. 93 * If it's otherwise open, don't close it, because that'll 94 * screw up others who have it open. 95 */ 96 dev = cn_tab->cn_dev; 97 if (cn_devvp != NULLVP) { 98 /* release our reference to real dev's vnode */ 99 vrele(cn_devvp); 100 cn_devvp = NULLVP; 101 } 102 if (vfinddev(dev, VCHR, &vp) && vcount(vp)) 103 return (0); 104 return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p)); 105 } 106 107 int 108 cnread(dev_t dev, struct uio *uio, int flag) 109 { 110 111 /* 112 * If we would redirect input, punt. This will keep strange 113 * things from happening to people who are using the real 114 * console. Nothing should be using /dev/console for 115 * input (except a shell in single-user mode, but then, 116 * one wouldn't TIOCCONS then). 117 */ 118 if (constty != NULL) 119 return 0; 120 else if (cn_tab == NULL) 121 return ENXIO; 122 123 dev = cn_tab->cn_dev; 124 return ((*cdevsw[major(dev)].d_read)(dev, uio, flag)); 125 } 126 127 int 128 cnwrite(dev_t dev, struct uio *uio, int flag) 129 { 130 131 /* 132 * Redirect output, if that's appropriate. 133 * If there's no real console, return ENXIO. 134 */ 135 if (constty != NULL) 136 dev = constty->t_dev; 137 else if (cn_tab == NULL) 138 return ENXIO; 139 else 140 dev = cn_tab->cn_dev; 141 return ((*cdevsw[major(dev)].d_write)(dev, uio, flag)); 142 } 143 144 int 145 cnstop(struct tty *tp, int flag) 146 { 147 return (0); 148 } 149 150 int 151 cnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 152 struct proc *p) 153 { 154 int error; 155 156 /* 157 * Superuser can always use this to wrest control of console 158 * output from the "virtual" console. 159 */ 160 if (cmd == TIOCCONS && constty != NULL) { 161 error = suser(p, SUSER_NOACCT); 162 if (error) 163 return (error); 164 constty = NULL; 165 return (0); 166 } 167 168 /* 169 * Redirect the ioctl, if that's appropriate. 170 * Note that strange things can happen, if a program does 171 * ioctls on /dev/console, then the console is redirected 172 * out from under it. 173 */ 174 if (constty != NULL) 175 dev = constty->t_dev; 176 else if (cn_tab == NULL) 177 return ENXIO; 178 else 179 dev = cn_tab->cn_dev; 180 return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p)); 181 } 182 183 /*ARGSUSED*/ 184 int 185 cnpoll(dev_t dev, int rw, struct proc *p) 186 { 187 188 /* 189 * Redirect the poll, if that's appropriate. 190 * I don't want to think of the possible side effects 191 * of console redirection here. 192 */ 193 if (constty != NULL) 194 dev = constty->t_dev; 195 else if (cn_tab == NULL) 196 return POLLERR; 197 else 198 dev = cn_tab->cn_dev; 199 return (ttpoll(dev, rw, p)); 200 } 201 202 203 int 204 cnkqfilter(dev_t dev, struct knote *kn) 205 { 206 207 /* 208 * Redirect output, if that's appropriate. 209 * If there's no real console, return 1. 210 */ 211 if (constty != NULL) 212 dev = constty->t_dev; 213 else if (cn_tab == NULL) 214 return (ENXIO); 215 else 216 dev = cn_tab->cn_dev; 217 if (cdevsw[major(dev)].d_kqfilter) 218 return ((*cdevsw[major(dev)].d_kqfilter)(dev, kn)); 219 return (ENXIO); 220 } 221 222 int 223 cngetc(void) 224 { 225 226 if (cn_tab == NULL) 227 return (0); 228 return ((*cn_tab->cn_getc)(cn_tab->cn_dev)); 229 } 230 231 void 232 cnputc(int c) 233 { 234 235 if (cn_tab == NULL) 236 return; 237 238 if (c) { 239 (*cn_tab->cn_putc)(cn_tab->cn_dev, c); 240 if (c == '\n') 241 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); 242 } 243 } 244 245 void 246 cnpollc(int on) 247 { 248 static int refcount = 0; 249 250 if (cn_tab == NULL) 251 return; 252 if (!on) 253 --refcount; 254 if (refcount == 0) 255 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on); 256 if (on) 257 ++refcount; 258 } 259 260 void 261 nullcnpollc(dev_t dev, int on) 262 { 263 264 } 265 266 void 267 cnbell(u_int pitch, u_int period, u_int volume) 268 { 269 if (cn_tab == NULL || cn_tab->cn_bell == NULL) 270 return; 271 272 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume); 273 } 274