Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / kern / tty_cons.c
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 $
40  * $DragonFly: src/sys/kern/tty_cons.c,v 1.2 2003/06/17 04:28:41 dillon Exp $
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>
55
56 #include <ddb/ddb.h>
57
58 #include <machine/cpu.h>
59
60 static  d_open_t        cnopen;
61 static  d_close_t       cnclose;
62 static  d_read_t        cnread;
63 static  d_write_t       cnwrite;
64 static  d_ioctl_t       cnioctl;
65 static  d_poll_t        cnpoll;
66 static  d_kqfilter_t    cnkqfilter;
67
68 #define CDEV_MAJOR      0
69 static struct cdevsw cn_cdevsw = {
70         /* open */      cnopen,
71         /* close */     cnclose,
72         /* read */      cnread,
73         /* write */     cnwrite,
74         /* ioctl */     cnioctl,
75         /* poll */      cnpoll,
76         /* mmap */      nommap,
77         /* strategy */  nostrategy,
78         /* name */      "console",
79         /* maj */       CDEV_MAJOR,
80         /* dump */      nodump,
81         /* psize */     nopsize,
82         /* flags */     D_TTY | D_KQFILTER,
83         /* bmaj */      -1,
84         /* kqfilter */  cnkqfilter,
85 };
86
87 static dev_t    cn_dev_t;       /* seems to be never really used */
88 static udev_t   cn_udev_t;
89 SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
90         &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
91
92 static int cn_mute;
93
94 int     cons_unavail = 0;       /* XXX:
95                                  * physical console not available for
96                                  * input (i.e., it is in graphics mode)
97                                  */
98
99 static u_char cn_is_open;               /* nonzero if logical console is open */
100 static int openmode, openflag;          /* how /dev/console was openned */
101 static dev_t cn_devfsdev;               /* represents the device private info */
102 static u_char cn_phys_is_open;          /* nonzero if physical device is open */
103 static d_close_t *cn_phys_close;        /* physical device close function */
104 static d_open_t *cn_phys_open;          /* physical device open function */
105        struct consdev *cn_tab;          /* physical console device info */
106 static u_char console_pausing;          /* pause after each line during probe */
107 static char *console_pausestr=
108 "<pause; press any key to proceed to next line or '.' to end pause mode>";
109
110 CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
111
112 void
113 cninit()
114 {
115         struct consdev *best_cp, *cp, **list;
116
117         /*
118          * Find the first console with the highest priority.
119          */
120         best_cp = NULL;
121         list = (struct consdev **)cons_set.ls_items;
122         while ((cp = *list++) != NULL) {
123                 if (cp->cn_probe == NULL)
124                         continue;
125                 (*cp->cn_probe)(cp);
126                 if (cp->cn_pri > CN_DEAD &&
127                     (best_cp == NULL || cp->cn_pri > best_cp->cn_pri))
128                         best_cp = cp;
129         }
130
131         /*
132          * Check if we should mute the console (for security reasons perhaps)
133          * It can be changes dynamically using sysctl kern.consmute
134          * once we are up and going.
135          * 
136          */
137         cn_mute = ((boothowto & (RB_MUTE
138                         |RB_SINGLE
139                         |RB_VERBOSE
140                         |RB_ASKNAME
141                         |RB_CONFIG)) == RB_MUTE);
142         
143         /*
144          * If no console, give up.
145          */
146         if (best_cp == NULL) {
147                 if (cn_tab != NULL && cn_tab->cn_term != NULL)
148                         (*cn_tab->cn_term)(cn_tab);
149                 cn_tab = best_cp;
150                 return;
151         }
152
153         /*
154          * Initialize console, then attach to it.  This ordering allows
155          * debugging using the previous console, if any.
156          */
157         (*best_cp->cn_init)(best_cp);
158         if (cn_tab != NULL && cn_tab != best_cp) {
159                 /* Turn off the previous console.  */
160                 if (cn_tab->cn_term != NULL)
161                         (*cn_tab->cn_term)(cn_tab);
162         }
163         if (boothowto & RB_PAUSE)
164                 console_pausing = 1;
165         cn_tab = best_cp;
166 }
167
168 void
169 cninit_finish()
170 {
171         struct cdevsw *cdp;
172
173         if ((cn_tab == NULL) || cn_mute)
174                 return;
175
176         /*
177          * Hook the open and close functions.
178          */
179         cdp = devsw(cn_tab->cn_dev);
180         if (cdp != NULL) {
181                 cn_phys_close = cdp->d_close;
182                 cdp->d_close = cnclose;
183                 cn_phys_open = cdp->d_open;
184                 cdp->d_open = cnopen;
185         }
186         cn_dev_t = cn_tab->cn_dev;
187         cn_udev_t = dev2udev(cn_dev_t);
188         console_pausing = 0;
189 }
190
191 static void
192 cnuninit(void)
193 {
194         struct cdevsw *cdp;
195
196         if (cn_tab == NULL)
197                 return;
198
199         /*
200          * Unhook the open and close functions.
201          */
202         cdp = devsw(cn_tab->cn_dev);
203         if (cdp != NULL) {
204                 cdp->d_close = cn_phys_close;
205                 cdp->d_open = cn_phys_open;
206         }
207         cn_phys_close = NULL;
208         cn_phys_open = NULL;
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  */
217 static int
218 sysctl_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,
235                                         openmode, curproc);
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,
245                                         openmode, curproc);
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
258 SYSCTL_PROC(_kern, OID_AUTO, consmute, CTLTYPE_INT|CTLFLAG_RW,
259         0, sizeof cn_mute, sysctl_kern_consmute, "I", "");
260
261 static int
262 cnopen(dev, flag, mode, p)
263         dev_t dev;
264         int flag, mode;
265         struct proc *p;
266 {
267         dev_t cndev, physdev;
268         int retval = 0;
269
270         if (cn_tab == NULL || cn_phys_open == NULL)
271                 return (0);
272         cndev = cn_tab->cn_dev;
273         physdev = (major(dev) == major(cndev) ? dev : cndev);
274         /*
275          * If mute is active, then non console opens don't get here
276          * so we don't need to check for that. They 
277          * bypass this and go straight to the device.
278          */
279         if(!cn_mute)
280                 retval = (*cn_phys_open)(physdev, flag, mode, p);
281         if (retval == 0) {
282                 /* 
283                  * check if we openned it via /dev/console or 
284                  * via the physical entry (e.g. /dev/sio0).
285                  */
286                 if (dev == cndev)
287                         cn_phys_is_open = 1;
288                 else if (physdev == cndev) {
289                         openmode = mode;
290                         openflag = flag;
291                         cn_is_open = 1;
292                 }
293                 dev->si_tty = physdev->si_tty;
294         }
295         return (retval);
296 }
297
298 static int
299 cnclose(dev, flag, mode, p)
300         dev_t dev;
301         int flag, mode;
302         struct proc *p;
303 {
304         dev_t cndev;
305         struct tty *cn_tp;
306
307         if (cn_tab == NULL || cn_phys_open == NULL)
308                 return (0);
309         cndev = cn_tab->cn_dev;
310         cn_tp = cndev->si_tty;
311         /*
312          * act appropriatly depending on whether it's /dev/console
313          * or the pysical device (e.g. /dev/sio) that's being closed.
314          * in either case, don't actually close the device unless
315          * both are closed.
316          */
317         if (dev == cndev) {
318                 /* the physical device is about to be closed */
319                 cn_phys_is_open = 0;
320                 if (cn_is_open) {
321                         if (cn_tp) {
322                                 /* perform a ttyhalfclose() */
323                                 /* reset session and proc group */
324                                 cn_tp->t_pgrp = NULL;
325                                 cn_tp->t_session = NULL;
326                         }
327                         return (0);
328                 }
329         } else if (major(dev) != major(cndev)) {
330                 /* the logical console is about to be closed */
331                 cn_is_open = 0;
332                 if (cn_phys_is_open)
333                         return (0);
334                 dev = cndev;
335         }
336         if(cn_phys_close)
337                 return ((*cn_phys_close)(dev, flag, mode, p));
338         return (0);
339 }
340
341 static int
342 cnread(dev, uio, flag)
343         dev_t dev;
344         struct uio *uio;
345         int flag;
346 {
347
348         if (cn_tab == NULL || cn_phys_open == NULL)
349                 return (0);
350         dev = cn_tab->cn_dev;
351         return ((*devsw(dev)->d_read)(dev, uio, flag));
352 }
353
354 static int
355 cnwrite(dev, uio, flag)
356         dev_t dev;
357         struct uio *uio;
358         int flag;
359 {
360
361         if (cn_tab == NULL || cn_phys_open == NULL) {
362                 uio->uio_resid = 0; /* dump the data */
363                 return (0);
364         }
365         if (constty)
366                 dev = constty->t_dev;
367         else
368                 dev = cn_tab->cn_dev;
369         log_console(uio);
370         return ((*devsw(dev)->d_write)(dev, uio, flag));
371 }
372
373 static int
374 cnioctl(dev, cmd, data, flag, p)
375         dev_t dev;
376         u_long cmd;
377         caddr_t data;
378         int flag;
379         struct proc *p;
380 {
381         int error;
382
383         if (cn_tab == NULL || cn_phys_open == NULL)
384                 return (0);
385         /*
386          * Superuser can always use this to wrest control of console
387          * output from the "virtual" console.
388          */
389         if (cmd == TIOCCONS && constty) {
390                 error = suser(p);
391                 if (error)
392                         return (error);
393                 constty = NULL;
394                 return (0);
395         }
396         dev = cn_tab->cn_dev;
397         return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, p));
398 }
399
400 static int
401 cnpoll(dev, events, p)
402         dev_t dev;
403         int events;
404         struct proc *p;
405 {
406         if ((cn_tab == NULL) || cn_mute)
407                 return (1);
408
409         dev = cn_tab->cn_dev;
410
411         return ((*devsw(dev)->d_poll)(dev, events, p));
412 }
413
414 static int
415 cnkqfilter(dev, kn)
416         dev_t dev;
417         struct knote *kn;
418 {
419         if ((cn_tab == NULL) || cn_mute)
420                 return (1);
421
422         dev = cn_tab->cn_dev;
423         if (devsw(dev)->d_flags & D_KQFILTER)
424                 return ((*devsw(dev)->d_kqfilter)(dev, kn));
425         return (1);
426 }
427
428 int
429 cngetc()
430 {
431         int c;
432         if ((cn_tab == NULL) || cn_mute)
433                 return (-1);
434         c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
435         if (c == '\r') c = '\n'; /* console input is always ICRNL */
436         return (c);
437 }
438
439 int
440 cncheckc()
441 {
442         if ((cn_tab == NULL) || cn_mute)
443                 return (-1);
444         return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
445 }
446
447 void
448 cnputc(c)
449         register int c;
450 {
451         char *cp;
452
453         if ((cn_tab == NULL) || cn_mute)
454                 return;
455         if (c) {
456                 if (c == '\n')
457                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
458                 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
459 #ifdef DDB
460                 if (console_pausing && !db_active && (c == '\n')) {
461 #else
462                 if (console_pausing && (c == '\n')) {
463 #endif
464                         for(cp=console_pausestr; *cp != '\0'; cp++)
465                             (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
466                         if (cngetc() == '.')
467                                 console_pausing = 0;
468                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
469                         for(cp=console_pausestr; *cp != '\0'; cp++)
470                             (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
471                         (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
472                 }
473         }
474 }
475
476 void
477 cndbctl(on)
478         int on;
479 {
480         static int refcount;
481
482         if (cn_tab == NULL)
483                 return;
484         if (!on)
485                 refcount--;
486         if (refcount == 0 && cn_tab->cn_dbctl != NULL)
487                 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
488         if (on)
489                 refcount++;
490 }
491
492 static void
493 cn_drvinit(void *unused)
494 {
495
496         cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
497             "console");
498 }
499
500 SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)