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