Register keyword removal
[dragonfly.git] / sys / kern / tty_cons.c
CommitLineData
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 $
1fd87d54 40 * $DragonFly: src/sys/kern/tty_cons.c,v 1.7 2003/07/26 19:42:11 rob 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>
51#include <sys/reboot.h>
52#include <sys/sysctl.h>
53#include <sys/tty.h>
54#include <sys/uio.h>
335dda38
MD
55#include <sys/msgport.h>
56#include <sys/msgport2.h>
57#include <sys/device.h>
984263bc
MD
58
59#include <ddb/ddb.h>
60
61#include <machine/cpu.h>
62
63static d_open_t cnopen;
64static d_close_t cnclose;
65static d_read_t cnread;
66static d_write_t cnwrite;
67static d_ioctl_t cnioctl;
68static d_poll_t cnpoll;
69static d_kqfilter_t cnkqfilter;
335dda38 70static int console_putport(lwkt_port_t port, lwkt_msg_t lmsg);
984263bc
MD
71
72#define CDEV_MAJOR 0
73static struct cdevsw cn_cdevsw = {
fabb8ceb
MD
74 /* name */ "console",
75 /* maj */ CDEV_MAJOR,
76 /* flags */ D_TTY | D_KQFILTER,
77 /* port */ NULL,
78 /* autoq */ 0,
79
984263bc
MD
80 /* open */ cnopen,
81 /* close */ cnclose,
82 /* read */ cnread,
83 /* write */ cnwrite,
84 /* ioctl */ cnioctl,
85 /* poll */ cnpoll,
86 /* mmap */ nommap,
87 /* strategy */ nostrategy,
984263bc
MD
88 /* dump */ nodump,
89 /* psize */ nopsize,
fabb8ceb 90 /* kqfilter */ cnkqfilter
984263bc
MD
91};
92
93static dev_t cn_dev_t; /* seems to be never really used */
94static udev_t cn_udev_t;
95SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
96 &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
97
98static int cn_mute;
99
100int cons_unavail = 0; /* XXX:
101 * physical console not available for
102 * input (i.e., it is in graphics mode)
103 */
104
105static u_char cn_is_open; /* nonzero if logical console is open */
106static int openmode, openflag; /* how /dev/console was openned */
107static dev_t cn_devfsdev; /* represents the device private info */
108static u_char cn_phys_is_open; /* nonzero if physical device is open */
984263bc
MD
109 struct consdev *cn_tab; /* physical console device info */
110static u_char console_pausing; /* pause after each line during probe */
111static char *console_pausestr=
112"<pause; press any key to proceed to next line or '.' to end pause mode>";
113
335dda38
MD
114static lwkt_port_t cn_fwd_port;
115static struct lwkt_port cn_port;
116
117
984263bc
MD
118CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
119
120void
121cninit()
122{
123 struct consdev *best_cp, *cp, **list;
124
335dda38
MD
125 /*
126 * Our port intercept
127 */
128 lwkt_init_port(&cn_port, NULL);
129 cn_port.mp_beginmsg = console_putport;
130
984263bc
MD
131 /*
132 * Find the first console with the highest priority.
133 */
134 best_cp = NULL;
135 list = (struct consdev **)cons_set.ls_items;
136 while ((cp = *list++) != NULL) {
137 if (cp->cn_probe == NULL)
138 continue;
139 (*cp->cn_probe)(cp);
140 if (cp->cn_pri > CN_DEAD &&
141 (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
142 best_cp = cp;
143 }
144
145 /*
146 * Check if we should mute the console (for security reasons perhaps)
147 * It can be changes dynamically using sysctl kern.consmute
148 * once we are up and going.
149 *
150 */
151 cn_mute = ((boothowto & (RB_MUTE
152 |RB_SINGLE
153 |RB_VERBOSE
154 |RB_ASKNAME
155 |RB_CONFIG)) == RB_MUTE);
156
157 /*
158 * If no console, give up.
159 */
160 if (best_cp == NULL) {
161 if (cn_tab != NULL && cn_tab->cn_term != NULL)
162 (*cn_tab->cn_term)(cn_tab);
163 cn_tab = best_cp;
164 return;
165 }
166
167 /*
168 * Initialize console, then attach to it. This ordering allows
169 * debugging using the previous console, if any.
170 */
171 (*best_cp->cn_init)(best_cp);
172 if (cn_tab != NULL && cn_tab != best_cp) {
173 /* Turn off the previous console. */
174 if (cn_tab->cn_term != NULL)
175 (*cn_tab->cn_term)(cn_tab);
176 }
177 if (boothowto & RB_PAUSE)
178 console_pausing = 1;
179 cn_tab = best_cp;
180}
181
182void
183cninit_finish()
184{
984263bc
MD
185 if ((cn_tab == NULL) || cn_mute)
186 return;
187
188 /*
189 * Hook the open and close functions.
190 */
335dda38
MD
191 if (dev_dport(cn_tab->cn_dev))
192 cn_fwd_port = cdevsw_dev_override(cn_tab->cn_dev, &cn_port);
984263bc
MD
193 cn_dev_t = cn_tab->cn_dev;
194 cn_udev_t = dev2udev(cn_dev_t);
195 console_pausing = 0;
196}
197
198static void
199cnuninit(void)
200{
984263bc
MD
201 if (cn_tab == NULL)
202 return;
203
204 /*
205 * Unhook the open and close functions.
206 */
335dda38
MD
207 cdevsw_dev_override(cn_tab->cn_dev, NULL);
208 cn_fwd_port = NULL;
984263bc
MD
209 cn_dev_t = NODEV;
210 cn_udev_t = NOUDEV;
211}
212
213/*
214 * User has changed the state of the console muting.
215 * This may require us to open or close the device in question.
216 */
217static int
218sysctl_kern_consmute(SYSCTL_HANDLER_ARGS)
219{
220 int error;
221 int ocn_mute;
222
223 ocn_mute = cn_mute;
224 error = sysctl_handle_int(oidp, &cn_mute, 0, req);
225 if((error == 0) && (cn_tab != NULL) && (req->newptr != NULL)) {
226 if(ocn_mute && !cn_mute) {
227 /*
228 * going from muted to unmuted.. open the physical dev
229 * if the console has been openned
230 */
231 cninit_finish();
232 if(cn_is_open)
233 /* XXX curproc is not what we want really */
234 error = cnopen(cn_dev_t, openflag,
41c20dac 235 openmode, curthread);
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 */
243 if(cn_is_open)
244 error = cnclose(cn_dev_t, openflag,
41c20dac 245 openmode, curthread);
984263bc
MD
246 if ( error == 0) cnuninit();
247 }
248 if (error != 0) {
249 /*
250 * back out the change if there was an error
251 */
252 cn_mute = ocn_mute;
253 }
254 }
255 return (error);
256}
257
258SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
259 0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
260
335dda38
MD
261static int
262console_putport(lwkt_port_t port, lwkt_msg_t lmsg)
263{
264 cdevallmsg_t msg = (cdevallmsg_t)lmsg;
265 int error;
266
267 switch(msg->am_lmsg.ms_cmd) {
268 case CDEV_CMD_OPEN:
269 error = cnopen(
270 msg->am_open.msg.dev,
271 msg->am_open.oflags,
272 msg->am_open.devtype,
273 msg->am_open.td
274 );
275 break;
276 case CDEV_CMD_CLOSE:
277 error = cnclose(
278 msg->am_close.msg.dev,
279 msg->am_close.fflag,
280 msg->am_close.devtype,
281 msg->am_close.td
282 );
283 break;
284 default:
285 error = lwkt_forwardmsg(cn_fwd_port, &msg->am_lmsg);
286 break;
287 }
288 return(error);
289}
290
984263bc 291static int
41c20dac 292cnopen(dev, flag, mode, td)
984263bc
MD
293 dev_t dev;
294 int flag, mode;
41c20dac 295 struct thread *td;
984263bc
MD
296{
297 dev_t cndev, physdev;
298 int retval = 0;
299
335dda38 300 if (cn_tab == NULL || cn_fwd_port == NULL)
984263bc
MD
301 return (0);
302 cndev = cn_tab->cn_dev;
303 physdev = (major(dev) == major(cndev) ? dev : cndev);
304 /*
305 * If mute is active, then non console opens don't get here
306 * so we don't need to check for that. They
307 * bypass this and go straight to the device.
308 */
309 if(!cn_mute)
335dda38 310 retval = dev_port_dopen(cn_fwd_port, physdev, flag, mode, td);
984263bc
MD
311 if (retval == 0) {
312 /*
313 * check if we openned it via /dev/console or
314 * via the physical entry (e.g. /dev/sio0).
315 */
316 if (dev == cndev)
317 cn_phys_is_open = 1;
318 else if (physdev == cndev) {
319 openmode = mode;
320 openflag = flag;
321 cn_is_open = 1;
322 }
323 dev->si_tty = physdev->si_tty;
324 }
325 return (retval);
326}
327
328static int
41c20dac 329cnclose(dev, flag, mode, td)
984263bc
MD
330 dev_t dev;
331 int flag, mode;
41c20dac 332 struct thread *td;
984263bc
MD
333{
334 dev_t cndev;
335 struct tty *cn_tp;
336
335dda38 337 if (cn_tab == NULL || cn_fwd_port == NULL)
984263bc
MD
338 return (0);
339 cndev = cn_tab->cn_dev;
340 cn_tp = cndev->si_tty;
341 /*
342 * act appropriatly depending on whether it's /dev/console
343 * or the pysical device (e.g. /dev/sio) that's being closed.
344 * in either case, don't actually close the device unless
345 * both are closed.
346 */
347 if (dev == cndev) {
348 /* the physical device is about to be closed */
349 cn_phys_is_open = 0;
350 if (cn_is_open) {
351 if (cn_tp) {
352 /* perform a ttyhalfclose() */
353 /* reset session and proc group */
354 cn_tp->t_pgrp = NULL;
355 cn_tp->t_session = NULL;
356 }
357 return (0);
358 }
359 } else if (major(dev) != major(cndev)) {
360 /* the logical console is about to be closed */
361 cn_is_open = 0;
362 if (cn_phys_is_open)
363 return (0);
364 dev = cndev;
365 }
335dda38
MD
366 if (cn_fwd_port)
367 return (dev_port_dclose(cn_fwd_port, dev, flag, mode, td));
984263bc
MD
368 return (0);
369}
370
371static int
372cnread(dev, uio, flag)
373 dev_t dev;
374 struct uio *uio;
375 int flag;
376{
377
335dda38 378 if (cn_tab == NULL || cn_fwd_port == NULL)
984263bc
MD
379 return (0);
380 dev = cn_tab->cn_dev;
335dda38 381 return (dev_port_dread(cn_fwd_port, dev, uio, flag));
984263bc
MD
382}
383
384static int
385cnwrite(dev, uio, flag)
386 dev_t dev;
387 struct uio *uio;
388 int flag;
389{
390
335dda38 391 if (cn_tab == NULL || cn_fwd_port == NULL) {
984263bc
MD
392 uio->uio_resid = 0; /* dump the data */
393 return (0);
394 }
395 if (constty)
396 dev = constty->t_dev;
397 else
398 dev = cn_tab->cn_dev;
399 log_console(uio);
335dda38 400 return (dev_port_dwrite(cn_fwd_port, dev, uio, flag));
984263bc
MD
401}
402
403static int
41c20dac 404cnioctl(dev, cmd, data, flag, td)
984263bc
MD
405 dev_t dev;
406 u_long cmd;
407 caddr_t data;
408 int flag;
41c20dac 409 struct thread *td;
984263bc
MD
410{
411 int error;
412
335dda38 413 if (cn_tab == NULL || cn_fwd_port == NULL)
984263bc 414 return (0);
41c20dac 415 KKASSERT(td->td_proc != NULL);
984263bc
MD
416 /*
417 * Superuser can always use this to wrest control of console
418 * output from the "virtual" console.
419 */
420 if (cmd == TIOCCONS && constty) {
dadab5e9 421 error = suser(td);
984263bc
MD
422 if (error)
423 return (error);
424 constty = NULL;
425 return (0);
426 }
427 dev = cn_tab->cn_dev;
335dda38 428 return (dev_port_dioctl(cn_fwd_port, dev, cmd, data, flag, td));
984263bc
MD
429}
430
431static int
41c20dac 432cnpoll(dev, events, td)
984263bc
MD
433 dev_t dev;
434 int events;
41c20dac 435 struct thread *td;
984263bc 436{
335dda38 437 if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
984263bc
MD
438 return (1);
439
440 dev = cn_tab->cn_dev;
441
335dda38 442 return (dev_port_dpoll(cn_fwd_port, dev, events, td));
984263bc
MD
443}
444
445static int
446cnkqfilter(dev, kn)
447 dev_t dev;
448 struct knote *kn;
449{
335dda38 450 if ((cn_tab == NULL) || cn_mute || cn_fwd_port == NULL)
984263bc
MD
451 return (1);
452
453 dev = cn_tab->cn_dev;
335dda38 454 return (dev_port_dkqfilter(cn_fwd_port, dev, kn));
984263bc
MD
455}
456
457int
458cngetc()
459{
460 int c;
461 if ((cn_tab == NULL) || cn_mute)
462 return (-1);
463 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
464 if (c == '\r') c = '\n'; /* console input is always ICRNL */
465 return (c);
466}
467
468int
469cncheckc()
470{
471 if ((cn_tab == NULL) || cn_mute)
472 return (-1);
473 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
474}
475
476void
477cnputc(c)
1fd87d54 478 int c;
984263bc
MD
479{
480 char *cp;
481
482 if ((cn_tab == NULL) || cn_mute)
483 return;
484 if (c) {
485 if (c == '\n')
486 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
487 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
488#ifdef DDB
489 if (console_pausing && !db_active && (c == '\n')) {
490#else
491 if (console_pausing && (c == '\n')) {
492#endif
493 for(cp=console_pausestr; *cp != '\0'; cp++)
494 (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
495 if (cngetc() == '.')
496 console_pausing = 0;
497 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
498 for(cp=console_pausestr; *cp != '\0'; cp++)
499 (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
500 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
501 }
502 }
503}
504
505void
506cndbctl(on)
507 int on;
508{
509 static int refcount;
510
511 if (cn_tab == NULL)
512 return;
513 if (!on)
514 refcount--;
515 if (refcount == 0 && cn_tab->cn_dbctl != NULL)
516 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
517 if (on)
518 refcount++;
519}
520
521static void
522cn_drvinit(void *unused)
523{
524
525 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
526 "console");
527}
528
529SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)