proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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 $
dadab5e9 40 * $DragonFly: src/sys/kern/tty_cons.c,v 1.4 2003/06/25 03:55:57 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>
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
60static d_open_t cnopen;
61static d_close_t cnclose;
62static d_read_t cnread;
63static d_write_t cnwrite;
64static d_ioctl_t cnioctl;
65static d_poll_t cnpoll;
66static d_kqfilter_t cnkqfilter;
67
68#define CDEV_MAJOR 0
69static 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
87static dev_t cn_dev_t; /* seems to be never really used */
88static udev_t cn_udev_t;
89SYSCTL_OPAQUE(_machdep, CPU_CONSDEV, consdev, CTLFLAG_RD,
90 &cn_udev_t, sizeof cn_udev_t, "T,dev_t", "");
91
92static int cn_mute;
93
94int cons_unavail = 0; /* XXX:
95 * physical console not available for
96 * input (i.e., it is in graphics mode)
97 */
98
99static u_char cn_is_open; /* nonzero if logical console is open */
100static int openmode, openflag; /* how /dev/console was openned */
101static dev_t cn_devfsdev; /* represents the device private info */
102static u_char cn_phys_is_open; /* nonzero if physical device is open */
103static d_close_t *cn_phys_close; /* physical device close function */
104static d_open_t *cn_phys_open; /* physical device open function */
105 struct consdev *cn_tab; /* physical console device info */
106static u_char console_pausing; /* pause after each line during probe */
107static char *console_pausestr=
108"<pause; press any key to proceed to next line or '.' to end pause mode>";
109
110CONS_DRIVER(cons, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
111
112void
113cninit()
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
168void
169cninit_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
191static void
192cnuninit(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 */
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
261static int
41c20dac 262cnopen(dev, flag, mode, td)
984263bc
MD
263 dev_t dev;
264 int flag, mode;
41c20dac 265 struct thread *td;
984263bc
MD
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)
41c20dac 280 retval = (*cn_phys_open)(physdev, flag, mode, td);
984263bc
MD
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
298static int
41c20dac 299cnclose(dev, flag, mode, td)
984263bc
MD
300 dev_t dev;
301 int flag, mode;
41c20dac 302 struct thread *td;
984263bc
MD
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)
41c20dac 337 return ((*cn_phys_close)(dev, flag, mode, td));
984263bc
MD
338 return (0);
339}
340
341static int
342cnread(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
354static int
355cnwrite(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
373static int
41c20dac 374cnioctl(dev, cmd, data, flag, td)
984263bc
MD
375 dev_t dev;
376 u_long cmd;
377 caddr_t data;
378 int flag;
41c20dac 379 struct thread *td;
984263bc
MD
380{
381 int error;
382
383 if (cn_tab == NULL || cn_phys_open == NULL)
384 return (0);
41c20dac 385 KKASSERT(td->td_proc != NULL);
984263bc
MD
386 /*
387 * Superuser can always use this to wrest control of console
388 * output from the "virtual" console.
389 */
390 if (cmd == TIOCCONS && constty) {
dadab5e9 391 error = suser(td);
984263bc
MD
392 if (error)
393 return (error);
394 constty = NULL;
395 return (0);
396 }
397 dev = cn_tab->cn_dev;
41c20dac 398 return ((*devsw(dev)->d_ioctl)(dev, cmd, data, flag, td));
984263bc
MD
399}
400
401static int
41c20dac 402cnpoll(dev, events, td)
984263bc
MD
403 dev_t dev;
404 int events;
41c20dac 405 struct thread *td;
984263bc
MD
406{
407 if ((cn_tab == NULL) || cn_mute)
408 return (1);
409
410 dev = cn_tab->cn_dev;
411
41c20dac 412 return ((*devsw(dev)->d_poll)(dev, events, td));
984263bc
MD
413}
414
415static int
416cnkqfilter(dev, kn)
417 dev_t dev;
418 struct knote *kn;
419{
420 if ((cn_tab == NULL) || cn_mute)
421 return (1);
422
423 dev = cn_tab->cn_dev;
424 if (devsw(dev)->d_flags & D_KQFILTER)
425 return ((*devsw(dev)->d_kqfilter)(dev, kn));
426 return (1);
427}
428
429int
430cngetc()
431{
432 int c;
433 if ((cn_tab == NULL) || cn_mute)
434 return (-1);
435 c = (*cn_tab->cn_getc)(cn_tab->cn_dev);
436 if (c == '\r') c = '\n'; /* console input is always ICRNL */
437 return (c);
438}
439
440int
441cncheckc()
442{
443 if ((cn_tab == NULL) || cn_mute)
444 return (-1);
445 return ((*cn_tab->cn_checkc)(cn_tab->cn_dev));
446}
447
448void
449cnputc(c)
450 register int c;
451{
452 char *cp;
453
454 if ((cn_tab == NULL) || cn_mute)
455 return;
456 if (c) {
457 if (c == '\n')
458 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
459 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
460#ifdef DDB
461 if (console_pausing && !db_active && (c == '\n')) {
462#else
463 if (console_pausing && (c == '\n')) {
464#endif
465 for(cp=console_pausestr; *cp != '\0'; cp++)
466 (*cn_tab->cn_putc)(cn_tab->cn_dev, *cp);
467 if (cngetc() == '.')
468 console_pausing = 0;
469 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
470 for(cp=console_pausestr; *cp != '\0'; cp++)
471 (*cn_tab->cn_putc)(cn_tab->cn_dev, ' ');
472 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
473 }
474 }
475}
476
477void
478cndbctl(on)
479 int on;
480{
481 static int refcount;
482
483 if (cn_tab == NULL)
484 return;
485 if (!on)
486 refcount--;
487 if (refcount == 0 && cn_tab->cn_dbctl != NULL)
488 (*cn_tab->cn_dbctl)(cn_tab->cn_dev, on);
489 if (on)
490 refcount++;
491}
492
493static void
494cn_drvinit(void *unused)
495{
496
497 cn_devfsdev = make_dev(&cn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
498 "console");
499}
500
501SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)