| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1988 University of Utah. | |
| 3 | * Copyright (c) 1991 The Regents of the University of California. | |
| 4 | * All rights reserved. | |
| 5 | * | |
| 6 | * This code is derived from software contributed to Berkeley by | |
| 7 | * the Systems Programming Group of the University of Utah Computer | |
| 8 | * Science Department. | |
| 9 | * | |
| 10 | * Redistribution and use in source and binary forms, with or without | |
| 11 | * modification, are permitted provided that the following conditions | |
| 12 | * are met: | |
| 13 | * 1. Redistributions of source code must retain the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer. | |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 16 | * notice, this list of conditions and the following disclaimer in the | |
| 17 | * documentation and/or other materials provided with the distribution. | |
| 18 | * 3. All advertising materials mentioning features or use of this software | |
| 19 | * must display the following acknowledgement: | |
| 20 | * This product includes software developed by the University of | |
| 21 | * California, Berkeley and its contributors. | |
| 22 | * 4. Neither the name of the University nor the names of its contributors | |
| 23 | * may be used to endorse or promote products derived from this software | |
| 24 | * without specific prior written permission. | |
| 25 | * | |
| 26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 36 | * SUCH DAMAGE. | |
| 37 | * | |
| 38 | * from: @(#)cons.c 7.2 (Berkeley) 5/9/91 | |
| 39 | * $FreeBSD: src/sys/kern/tty_cons.c,v 1.81.2.4 2001/12/17 18:44:41 guido Exp $ | |
| ce81f184 | 40 | * $DragonFly: src/sys/kern/tty_cons.c,v 1.21 2007/05/07 05:21:41 dillon Exp $ |
| 984263bc MD |
41 | */ |
| 42 | ||
| 43 | #include "opt_ddb.h" | |
| 44 | ||
| 45 | #include <sys/param.h> | |
| 46 | #include <sys/systm.h> | |
| 47 | #include <sys/conf.h> | |
| 48 | #include <sys/cons.h> | |
| 49 | #include <sys/kernel.h> | |
| 50 | #include <sys/proc.h> | |
| 895c1f85 | 51 | #include <sys/priv.h> |
| 984263bc MD |
52 | #include <sys/reboot.h> |
| 53 | #include <sys/sysctl.h> | |
| 54 | #include <sys/tty.h> | |
| 55 | #include <sys/uio.h> | |
| 335dda38 MD |
56 | #include <sys/msgport.h> |
| 57 | #include <sys/msgport2.h> | |
| 58 | #include <sys/device.h> | |
| 984263bc MD |
59 | |
| 60 | #include <ddb/ddb.h> | |
| 61 | ||
| 62 | #include <machine/cpu.h> | |
| 63 | ||
| fef8985e MD |
64 | static d_open_t cnopen; |
| 65 | static d_close_t cnclose; | |
| 66 | static d_read_t cnread; | |
| 67 | static d_write_t cnwrite; | |
| 68 | static d_ioctl_t cnioctl; | |
| 69 | static d_poll_t cnpoll; | |
| 70 | static d_kqfilter_t cnkqfilter; | |
| e4c9c0c8 | 71 | |
| fef8985e | 72 | static int cnintercept(struct dev_generic_args *ap); |
| 984263bc MD |
73 | |
| 74 | #define CDEV_MAJOR 0 | |
| fef8985e MD |
75 | static struct dev_ops cn_ops = { |
| 76 | { "console", CDEV_MAJOR, D_TTY | D_KQFILTER }, | |
| 77 | .d_open = cnopen, | |
| 78 | .d_close = cnclose, | |
| 79 | .d_read = cnread, | |
| 80 | .d_write = cnwrite, | |
| 81 | .d_ioctl = cnioctl, | |
| 82 | .d_poll = cnpoll, | |
| 83 | .d_kqfilter = cnkqfilter, | |
| 84 | }; | |
| 85 | ||
| 86 | static struct dev_ops cn_iops = { | |
| 87 | { "intercept", CDEV_MAJOR, D_TTY | D_KQFILTER }, | |
| cd29885a | 88 | .d_default = cnintercept |
| 984263bc MD |
89 | }; |
| 90 | ||
| fef8985e | 91 | static struct dev_ops *cn_fwd_ops; |
| b13267a5 | 92 | static cdev_t cn_dev; |
| cd29885a MD |
93 | |
| 94 | //XXX: get this shit out! (alexh) | |
| 95 | #if 0 | |
| 984263bc | 96 | SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD, |
| 936c90c4 | 97 | &cn_udev, sizeof cn_udev, "T,udev_t", ""); |
| cd29885a | 98 | #endif |
| 984263bc MD |
99 | |
| 100 | static int cn_mute; | |
| 101 | ||
| 102 | int cons_unavail = 0; /* XXX: | |
| 103 | * physical console not available for | |
| 104 | * input (i.e., it is in graphics mode) | |
| 105 | */ | |
| 106 | ||
| 107 | static u_char cn_is_open; /* nonzero if logical console is open */ | |
| 108 | static int openmode, openflag; /* how /dev/console was openned */ | |
| b13267a5 | 109 | static cdev_t cn_devfsdev; /* represents the device private info */ |
| 984263bc | 110 | static u_char cn_phys_is_open; /* nonzero if physical device is open */ |
| 984263bc MD |
111 | static u_char console_pausing; /* pause after each line during probe */ |
| 112 | static char *console_pausestr= | |
| 113 | "<pause; press any key to proceed to next line or '.' to end pause mode>"; | |
| 114 | ||
| ce81f184 MD |
115 | struct consdev *cn_tab; /* physical console device info */ |
| 116 | struct consdev *gdb_tab; /* physical gdb debugger device info */ | |
| 117 | ||
| 118 | CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); | |
| dc62b251 | 119 | SET_DECLARE(cons_set, struct consdev); |
| 984263bc MD |
120 | |
| 121 | void | |
| c972a82f | 122 | cninit(void) |
| 984263bc MD |
123 | { |
| 124 | struct consdev *best_cp, *cp, **list; | |
| 125 | ||
| 126 | /* | |
| cd29885a MD |
127 | * Check if we should mute the console (for security reasons perhaps) |
| 128 | * It can be changes dynamically using sysctl kern.consmute | |
| 129 | * once we are up and going. | |
| 130 | * | |
| 131 | */ | |
| 132 | cn_mute = ((boothowto & (RB_MUTE | |
| 133 | |RB_SINGLE | |
| 134 | |RB_VERBOSE | |
| 135 | |RB_ASKNAME | |
| 136 | |RB_CONFIG)) == RB_MUTE); | |
| 137 | ||
| 138 | /* | |
| 984263bc MD |
139 | * Find the first console with the highest priority. |
| 140 | */ | |
| 141 | best_cp = NULL; | |
| dc62b251 MD |
142 | SET_FOREACH(list, cons_set) { |
| 143 | cp = *list; | |
| 984263bc MD |
144 | if (cp->cn_probe == NULL) |
| 145 | continue; | |
| 146 | (*cp->cn_probe)(cp); | |
| ce81f184 | 147 | if (cp->cn_pri > CN_DEAD && cp->cn_probegood && |
| 984263bc MD |
148 | (best_cp == NULL || cp->cn_pri > best_cp->cn_pri)) |
| 149 | best_cp = cp; | |
| 150 | } | |
| 151 | ||
| 984263bc MD |
152 | |
| 153 | /* | |
| 154 | * If no console, give up. | |
| 155 | */ | |
| 156 | if (best_cp == NULL) { | |
| 157 | if (cn_tab != NULL && cn_tab->cn_term != NULL) | |
| 158 | (*cn_tab->cn_term)(cn_tab); | |
| 159 | cn_tab = best_cp; | |
| 160 | return; | |
| 161 | } | |
| 162 | ||
| 163 | /* | |
| 164 | * Initialize console, then attach to it. This ordering allows | |
| 165 | * debugging using the previous console, if any. | |
| 166 | */ | |
| 167 | (*best_cp->cn_init)(best_cp); | |
| 168 | if (cn_tab != NULL && cn_tab != best_cp) { | |
| 169 | /* Turn off the previous console. */ | |
| 170 | if (cn_tab->cn_term != NULL) | |
| 171 | (*cn_tab->cn_term)(cn_tab); | |
| 172 | } | |
| 173 | if (boothowto & RB_PAUSE) | |
| 174 | console_pausing = 1; | |
| 175 | cn_tab = best_cp; | |
| 176 | } | |
| 177 | ||
| cd29885a | 178 | |
| e4c9c0c8 MD |
179 | /* |
| 180 | * Hook the open and close functions on the selected device. | |
| 181 | */ | |
| 984263bc | 182 | void |
| c972a82f | 183 | cninit_finish(void) |
| 984263bc | 184 | { |
| 984263bc MD |
185 | if ((cn_tab == NULL) || cn_mute) |
| 186 | return; | |
| ce81f184 MD |
187 | if (cn_tab->cn_dev == NULL) { |
| 188 | cn_tab->cn_init_fini(cn_tab); | |
| cd29885a MD |
189 | if (cn_tab->cn_dev == NULL) { |
| 190 | kprintf("Unable to hook console! cn_tab %p\n", cn_tab); | |
| 191 | return; | |
| 192 | } | |
| ce81f184 MD |
193 | } |
| 194 | ||
| cd29885a | 195 | cn_fwd_ops = dev_ops_intercept(cn_tab->cn_dev, &cn_iops); |
| fef8985e | 196 | cn_dev = cn_tab->cn_dev; |
| 984263bc MD |
197 | console_pausing = 0; |
| 198 | } | |
| 199 | ||
| 200 | static void | |
| 201 | cnuninit(void) | |
| 202 | { | |
| 984263bc MD |
203 | if (cn_tab == NULL) |
| 204 | return; | |
| fef8985e MD |
205 | if (cn_fwd_ops) |
| 206 | dev_ops_restore(cn_tab->cn_dev, cn_fwd_ops); | |
| 207 | cn_fwd_ops = NULL; | |
| 208 | cn_dev = NULL; | |
| 984263bc MD |
209 | } |
| 210 | ||
| cd29885a | 211 | |
| 984263bc MD |
212 | /* |
| 213 | * User has changed the state of the console muting. | |
| 214 | * This may require us to open or close the device in question. | |
| 215 | */ | |
| 216 | static int | |
| 217 | sysctl_kern_consmute(SYSCTL_HANDLER_ARGS) | |
| 218 | { | |
| 219 | int error; | |
| 220 | int ocn_mute; | |
| 221 | ||
| 222 | ocn_mute = cn_mute; | |
| 223 | error = sysctl_handle_int(oidp, &cn_mute, 0, req); | |
| 224 | if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) { | |
| 225 | if(ocn_mute && !cn_mute) { | |
| 226 | /* | |
| 227 | * going from muted to unmuted.. open the physical dev | |
| 228 | * if the console has been openned | |
| 229 | */ | |
| 230 | cninit_finish(); | |
| e4c9c0c8 | 231 | if (cn_is_open) { |
| 984263bc | 232 | /* XXX curproc is not what we want really */ |
| fef8985e MD |
233 | error = dev_dopen(cn_dev, openflag, |
| 234 | openmode, curproc->p_ucred); | |
| e4c9c0c8 | 235 | } |
| 984263bc MD |
236 | /* if it failed, back it out */ |
| 237 | if ( error != 0) cnuninit(); | |
| 238 | } else if (!ocn_mute && cn_mute) { | |
| 239 | /* | |
| 240 | * going from unmuted to muted.. close the physical dev | |
| 241 | * if it's only open via /dev/console | |
| 242 | */ | |
| e4c9c0c8 | 243 | if (cn_is_open) { |
| fef8985e | 244 | error = dev_dclose(cn_dev, openflag, |
| cd29885a | 245 | openmode); |
| e4c9c0c8 MD |
246 | } |
| 247 | if (error == 0) | |
| 248 | cnuninit(); | |
| 984263bc MD |
249 | } |
| 250 | if (error != 0) { | |
| 251 | /* | |
| 252 | * back out the change if there was an error | |
| 253 | */ | |
| 254 | cn_mute = ocn_mute; | |
| 255 | } | |
| 256 | } | |
| 257 | return (error); | |
| 258 | } | |
| 259 | ||
| 260 | SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW, | |
| 261 | 0, sizeof cn_mute, sysctl_kern_consmute, "I", ""); | |
| 262 | ||
| cd29885a | 263 | |
| e4c9c0c8 MD |
264 | /* |
| 265 | * We intercept the OPEN and CLOSE calls on the original device, and | |
| 266 | * forward the rest through. | |
| 267 | */ | |
| 268 | static int | |
| fef8985e | 269 | cnintercept(struct dev_generic_args *ap) |
| 335dda38 | 270 | { |
| 335dda38 MD |
271 | int error; |
| 272 | ||
| fef8985e MD |
273 | if (ap->a_desc == &dev_open_desc) { |
| 274 | error = cnopen((struct dev_open_args *)ap); | |
| 275 | } else if (ap->a_desc == &dev_close_desc) { | |
| 276 | error = cnclose((struct dev_close_args *)ap); | |
| 277 | } else if (cn_fwd_ops) { | |
| 278 | error = dev_doperate_ops(cn_fwd_ops, ap); | |
| 279 | } else { | |
| 280 | error = ENXIO; | |
| 335dda38 | 281 | } |
| fef8985e | 282 | return (error); |
| 335dda38 MD |
283 | } |
| 284 | ||
| e4c9c0c8 | 285 | /* |
| fef8985e | 286 | * cnopen() is called as an intercept function (dev will be that of the |
| e4c9c0c8 MD |
287 | * actual physical device representing our console), and also called from |
| 288 | * the muting code and from the /dev/console switch (dev will have the | |
| 289 | * console's cdevsw). | |
| 290 | */ | |
| 335dda38 | 291 | static int |
| fef8985e | 292 | cnopen(struct dev_open_args *ap) |
| 984263bc | 293 | { |
| b13267a5 | 294 | cdev_t dev = ap->a_head.a_dev; |
| fef8985e MD |
295 | int flag = ap->a_oflags; |
| 296 | int mode = ap->a_devtype; | |
| cd29885a MD |
297 | cdev_t cndev; |
| 298 | cdev_t physdev; | |
| 984263bc MD |
299 | int retval = 0; |
| 300 | ||
| fef8985e | 301 | if (cn_tab == NULL || cn_fwd_ops == NULL) |
| 984263bc | 302 | return (0); |
| cd29885a MD |
303 | |
| 304 | cndev = cn_tab->cn_dev; /* actual physical device */ | |
| 305 | physdev = (dev == cn_devfsdev) ? cndev : dev; | |
| e4c9c0c8 | 306 | |
| 984263bc MD |
307 | /* |
| 308 | * If mute is active, then non console opens don't get here | |
| e4c9c0c8 MD |
309 | * so we don't need to check for that. They bypass this and go |
| 310 | * straight to the device. | |
| 311 | * | |
| fef8985e MD |
312 | * It is important to note that due to our intercept and the fact |
| 313 | * that we might be called via the original (intercepted) device, | |
| 314 | * the original device's ops may point to us, so to avoid an | |
| 315 | * infinite recursion we have to forward through cn_fwd_ops. | |
| 316 | * This is a severe hack that really needs to be fixed XXX. | |
| 317 | * | |
| e4c9c0c8 MD |
318 | * XXX at the moment we assume that the port forwarding function |
| 319 | * is synchronous for open. | |
| 984263bc | 320 | */ |
| e4c9c0c8 | 321 | if (!cn_mute) { |
| fef8985e MD |
322 | ap->a_head.a_dev = physdev; |
| 323 | retval = dev_doperate_ops(cn_fwd_ops, &ap->a_head); | |
| e4c9c0c8 | 324 | } |
| 984263bc | 325 | if (retval == 0) { |
| cd29885a MD |
326 | /* |
| 327 | * check if we openned it via /dev/console or | |
| 984263bc MD |
328 | * via the physical entry (e.g. /dev/sio0). |
| 329 | */ | |
| cd29885a | 330 | if (dev == cndev) { |
| 984263bc | 331 | cn_phys_is_open = 1; |
| cd29885a | 332 | } else if (physdev == cndev) { |
| 984263bc MD |
333 | openmode = mode; |
| 334 | openflag = flag; | |
| 335 | cn_is_open = 1; | |
| 336 | } | |
| cd29885a | 337 | dev->si_tty = cndev->si_tty; |
| 984263bc MD |
338 | } |
| 339 | return (retval); | |
| 340 | } | |
| 341 | ||
| e4c9c0c8 MD |
342 | /* |
| 343 | * cnclose() is called as a port intercept function (dev will be that of the | |
| 344 | * actual physical device representing our console), and also called from | |
| 345 | * the muting code and from the /dev/console switch (dev will have the | |
| 346 | * console's cdevsw). | |
| 347 | */ | |
| 984263bc | 348 | static int |
| fef8985e | 349 | cnclose(struct dev_close_args *ap) |
| 984263bc | 350 | { |
| 984263bc | 351 | struct tty *cn_tp; |
| cd29885a MD |
352 | cdev_t cndev; |
| 353 | cdev_t physdev; | |
| 354 | cdev_t dev = ap->a_head.a_dev; | |
| 984263bc | 355 | |
| fef8985e | 356 | if (cn_tab == NULL || cn_fwd_ops == NULL) |
| cd29885a | 357 | return(0); |
| 984263bc MD |
358 | cndev = cn_tab->cn_dev; |
| 359 | cn_tp = cndev->si_tty; | |
| cd29885a MD |
360 | physdev = (dev == cn_devfsdev) ? cndev : dev; |
| 361 | ||
| 984263bc MD |
362 | /* |
| 363 | * act appropriatly depending on whether it's /dev/console | |
| 364 | * or the pysical device (e.g. /dev/sio) that's being closed. | |
| 365 | * in either case, don't actually close the device unless | |
| 366 | * both are closed. | |
| 367 | */ | |
| 368 | if (dev == cndev) { | |
| 369 | /* the physical device is about to be closed */ | |
| 370 | cn_phys_is_open = 0; | |
| 371 | if (cn_is_open) { | |
| 372 | if (cn_tp) { | |
| 373 | /* perform a ttyhalfclose() */ | |
| 374 | /* reset session and proc group */ | |
| 8b90699b | 375 | ttyclearsession(cn_tp); |
| 984263bc | 376 | } |
| cd29885a | 377 | return(0); |
| 984263bc | 378 | } |
| cd29885a | 379 | } else if (physdev == cndev) { |
| 984263bc MD |
380 | /* the logical console is about to be closed */ |
| 381 | cn_is_open = 0; | |
| 382 | if (cn_phys_is_open) | |
| cd29885a | 383 | return(0); |
| 984263bc MD |
384 | dev = cndev; |
| 385 | } | |
| fef8985e MD |
386 | if (cn_fwd_ops) { |
| 387 | ap->a_head.a_dev = dev; | |
| 388 | return (dev_doperate_ops(cn_fwd_ops, &ap->a_head)); | |
| e4c9c0c8 | 389 | } |
| 984263bc MD |
390 | return (0); |
| 391 | } | |
| 392 | ||
| e4c9c0c8 MD |
393 | /* |
| 394 | * The following functions are dispatched solely from the /dev/console | |
| fef8985e | 395 | * device. Their job is primarily to forward the request through. |
| e4c9c0c8 MD |
396 | * If the console is not attached to anything then write()'s are sunk |
| 397 | * to null and reads return 0 (mostly). | |
| 398 | */ | |
| 984263bc | 399 | static int |
| fef8985e | 400 | cnread(struct dev_read_args *ap) |
| 984263bc | 401 | { |
| fef8985e | 402 | if (cn_tab == NULL || cn_fwd_ops == NULL) |
| 984263bc | 403 | return (0); |
| fef8985e MD |
404 | ap->a_head.a_dev = cn_tab->cn_dev; |
| 405 | return (dev_doperate(&ap->a_head)); | |
| 984263bc MD |
406 | } |
| 407 | ||
| 408 | static int | |
| fef8985e | 409 | cnwrite(struct dev_write_args *ap) |
| 984263bc | 410 | { |
| fef8985e | 411 | struct uio *uio = ap->a_uio; |
| b13267a5 | 412 | cdev_t dev; |
| 984263bc | 413 | |
| fef8985e | 414 | if (cn_tab == NULL || cn_fwd_ops == NULL) { |
| 984263bc MD |
415 | uio->uio_resid = 0; /* dump the data */ |
| 416 | return (0); | |
| 417 | } | |
| 418 | if (constty) | |
| 419 | dev = constty->t_dev; | |
| 420 | else | |
| 421 | dev = cn_tab->cn_dev; | |
| 422 | log_console(uio); | |
| fef8985e MD |
423 | ap->a_head.a_dev = dev; |
| 424 | return (dev_doperate(&ap->a_head)); | |
| 984263bc MD |
425 | } |
| 426 | ||
| 427 | static int | |
| fef8985e | 428 | cnioctl(struct dev_ioctl_args *ap) |
| 984263bc MD |
429 | { |
| 430 | int error; | |
| 431 | ||
| fef8985e | 432 | if (cn_tab == NULL || cn_fwd_ops == NULL) |
| 984263bc | 433 | return (0); |
| fef8985e | 434 | KKASSERT(curproc != NULL); |
| 984263bc MD |
435 | /* |
| 436 | * Superuser can always use this to wrest control of console | |
| 437 | * output from the "virtual" console. | |
| 438 | */ | |
| fef8985e MD |
439 | if (ap->a_cmd == TIOCCONS && constty) { |
| 440 | if (ap->a_cred) { | |
| 895c1f85 | 441 | error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0); |
| fef8985e MD |
442 | if (error) |
| 443 | return (error); | |
| 444 | } | |
| 984263bc MD |
445 | constty = NULL; |
| 446 | return (0); | |
| 447 | } | |
| fef8985e MD |
448 | ap->a_head.a_dev = cn_tab->cn_dev; |
| 449 | return (dev_doperate(&ap->a_head)); | |
| 984263bc MD |
450 | } |
| 451 | ||
| 452 | static int | |
| fef8985e | 453 | cnpoll(struct dev_poll_args *ap) |
| 984263bc | 454 | { |
| fef8985e | 455 | if ((cn_tab == NULL) || cn_mute || cn_fwd_ops == NULL) |
| 984263bc | 456 | return (1); |
| fef8985e MD |
457 | ap->a_head.a_dev = cn_tab->cn_dev; |
| 458 | return (dev_doperate(&ap->a_head)); | |
| 984263bc MD |
459 | } |
| 460 | ||
| 461 | static int | |
| fef8985e | 462 | cnkqfilter(struct dev_kqfilter_args *ap) |
| 984263bc | 463 | { |
| fef8985e | 464 | if ((cn_tab == NULL) || cn_mute || cn_fwd_ops == NULL) |
| 984263bc | 465 | return (1); |
| fef8985e MD |
466 | ap->a_head.a_dev = cn_tab->cn_dev; |
| 467 | return (dev_doperate(&ap->a_head)); | |
| 984263bc MD |
468 | } |
| 469 | ||
| e4c9c0c8 MD |
470 | /* |
| 471 | * These synchronous functions are primarily used the kernel needs to | |
| 472 | * access the keyboard (e.g. when running the debugger), or output data | |
| 473 | * directly to the console. | |
| 474 | */ | |
| 984263bc | 475 | int |
| e4c9c0c8 | 476 | cngetc(void) |
| 984263bc MD |
477 | { |
| 478 | int c; | |
| 479 | if ((cn_tab == NULL) || cn_mute) | |
| 480 | return (-1); | |
| 481 | c = (*cn_tab->cn_getc)(cn_tab->cn_dev); | |
| 482 | if (c == '\r') c = '\n'; /* console input is always ICRNL */ | |
| 483 | return (c); | |
| 484 | } | |
| 485 | ||
| 486 | int | |
| e4c9c0c8 | 487 | cncheckc(void) |
| 984263bc MD |
488 | { |
| 489 | if ((cn_tab == NULL) || cn_mute) | |
| 490 | return (-1); | |
| 491 | return ((*cn_tab->cn_checkc)(cn_tab->cn_dev)); | |
| 492 | } | |
| 493 | ||
| 494 | void | |
| e4c9c0c8 | 495 | cnputc(int c) |
| 984263bc MD |
496 | { |
| 497 | char *cp; | |
| 498 | ||
| 499 | if ((cn_tab == NULL) || cn_mute) | |
| 500 | return; | |
| 501 | if (c) { | |
| 502 | if (c == '\n') | |
| 503 | (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); | |
| 504 | (*cn_tab->cn_putc)(cn_tab->cn_dev, c); | |
| 505 | #ifdef DDB | |
| 506 | if (console_pausing && !db_active && (c == '\n')) { | |
| 507 | #else | |
| 508 | if (console_pausing && (c == '\n')) { | |
| 509 | #endif | |
| 510 | for(cp=console_pausestr; *cp != '\0'; cp++) | |
| 511 | (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp); | |
| 512 | if (cngetc() == '.') | |
| 513 | console_pausing = 0; | |
| 514 | (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); | |
| 515 | for(cp=console_pausestr; *cp != '\0'; cp++) | |
| 516 | (*cn_tab->cn_putc)(cn_tab->cn_dev, ' '); | |
| 517 | (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r'); | |
| 518 | } | |
| 519 | } | |
| 520 | } | |
| 521 | ||
| 522 | void | |
| e4c9c0c8 | 523 | cndbctl(int on) |
| 984263bc MD |
524 | { |
| 525 | static int refcount; | |
| 526 | ||
| 527 | if (cn_tab == NULL) | |
| 528 | return; | |
| 529 | if (!on) | |
| 530 | refcount--; | |
| 531 | if (refcount == 0 && cn_tab->cn_dbctl != NULL) | |
| 532 | (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on); | |
| 533 | if (on) | |
| 534 | refcount++; | |
| 535 | } | |
| 536 | ||
| 537 | static void | |
| 538 | cn_drvinit(void *unused) | |
| 539 | { | |
| cd29885a | 540 | cn_devfsdev = make_only_devfs_dev(&cn_ops, 0, UID_ROOT, GID_WHEEL, |
| 3e82b46c | 541 | 0600, "console"); |
| 984263bc MD |
542 | } |
| 543 | ||
| 544 | SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL) |