1/*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 */
4/*
5 * Copyright (c) 1987, 1988 NeXT, Inc.
6 *
7 * HISTORY 7-Jan-93 Mac Gillon (mgillon) at NeXT Integrated POSIX support
8 *
9 * 12-Aug-87 John Seamons (jks) at NeXT Ported to NeXT.
10 */
11
12/*
13 * Indirect driver for console.
14 */
15#include <kern/locks.h>
16#include <machine/cons.h>
17#include <sys/param.h>
18#include <sys/systm.h>
19#include <sys/conf.h>
20#include <sys/ioctl.h>
21#include <sys/tty.h>
22#include <sys/proc.h>
23#include <sys/uio.h>
24
25static struct tty *_constty; /* current console device */
26static LCK_GRP_DECLARE(_constty_lock_grp, "constty");
27static LCK_MTX_DECLARE(_constty_lock, &_constty_lock_grp);
28
29struct tty *
30copy_constty(void)
31{
32 struct tty *result = NULL;
33 lck_mtx_lock(lck: &_constty_lock);
34 if (_constty != NULL) {
35 ttyhold(tp: _constty);
36 result = _constty;
37 }
38 lck_mtx_unlock(lck: &_constty_lock);
39 return result;
40}
41
42struct tty *
43set_constty(struct tty *new_tty)
44{
45 struct tty *old_tty = NULL;
46 lck_mtx_lock(lck: &_constty_lock);
47 old_tty = _constty;
48 _constty = new_tty;
49 if (_constty) {
50 ttyhold(tp: _constty);
51 }
52 lck_mtx_unlock(lck: &_constty_lock);
53
54 return old_tty;
55}
56
57/*
58 * The km driver supplied the default console device for the systems
59 * (usually a raw frame buffer driver, but potentially a serial driver).
60 */
61extern struct tty *km_tty[1];
62
63/*
64 * cdevsw[] entries for the console device driver
65 */
66int cnopen(__unused dev_t dev, int flag, int devtype, proc_t pp);
67int cnclose(__unused dev_t dev, int flag, int mode, proc_t pp);
68int cnread(__unused dev_t dev, struct uio *uio, int ioflag);
69int cnwrite(__unused dev_t dev, struct uio *uio, int ioflag);
70int cnioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flg, proc_t p);
71int cnselect(__unused dev_t dev, int flag, void * wql, proc_t p);
72
73int
74cnopen(__unused dev_t dev, int flag, int devtype, struct proc *pp)
75{
76 int error;
77 struct tty *constty = copy_constty();
78 if (constty) {
79 dev = constty->t_dev;
80 } else {
81 dev = km_tty[0]->t_dev;
82 }
83 error = (*cdevsw[major(dev)].d_open)(dev, flag, devtype, pp);
84 if (constty != NULL) {
85 ttyfree(constty);
86 }
87 return error;
88}
89
90
91int
92cnclose(__unused dev_t dev, int flag, int mode, struct proc *pp)
93{
94 int error;
95 struct tty *constty = copy_constty();
96 if (constty) {
97 dev = constty->t_dev;
98 } else {
99 dev = km_tty[0]->t_dev;
100 }
101 error = (*cdevsw[major(dev)].d_close)(dev, flag, mode, pp);
102 if (constty != NULL) {
103 ttyfree(constty);
104 }
105 return error;
106}
107
108
109int
110cnread(__unused dev_t dev, struct uio *uio, int ioflag)
111{
112 int error;
113 struct tty *constty = copy_constty();
114 if (constty) {
115 dev = constty->t_dev;
116 } else {
117 dev = km_tty[0]->t_dev;
118 }
119 error = (*cdevsw[major(dev)].d_read)(dev, uio, ioflag);
120 if (constty != NULL) {
121 ttyfree(constty);
122 }
123 return error;
124}
125
126
127int
128cnwrite(__unused dev_t dev, struct uio *uio, int ioflag)
129{
130 int error;
131 struct tty *constty = copy_constty();
132 if (constty) {
133 dev = constty->t_dev;
134 } else {
135 dev = km_tty[0]->t_dev;
136 }
137 error = (*cdevsw[major(dev)].d_write)(dev, uio, ioflag);
138 if (constty != NULL) {
139 ttyfree(constty);
140 }
141 return error;
142}
143
144
145int
146cnioctl(__unused dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
147{
148 int error;
149 struct tty *constty = copy_constty();
150 struct tty *freetp = NULL;
151 if (constty) {
152 dev = constty->t_dev;
153 } else {
154 dev = km_tty[0]->t_dev;
155 }
156
157 /*
158 * XXX This check prevents the cons.c code from being shared between
159 * XXX all architectures; it is probably not needed on ARM, either,
160 * XXX but I have no test platforms or ability to run a kernel.
161 *
162 * Superuser can always use this to wrest control of console
163 * output from the "virtual" console.
164 */
165 if ((unsigned) cmd == TIOCCONS && constty) {
166 error = proc_suser(p);
167 if (error) {
168 goto finish;
169 }
170 freetp = set_constty(NULL);
171 if (freetp) {
172 ttyfree(freetp);
173 freetp = NULL;
174 }
175 } else {
176 error = (*cdevsw[major(dev)].d_ioctl)(dev, cmd, addr, flag, p);
177 }
178finish:
179 if (constty != NULL) {
180 ttyfree(constty);
181 }
182 return error;
183}
184
185
186int
187cnselect(__unused dev_t dev, int flag, void *wql, struct proc *p)
188{
189 int error;
190 struct tty *constty = copy_constty();
191 if (constty) {
192 dev = constty->t_dev;
193 } else {
194 dev = km_tty[0]->t_dev;
195 }
196 error = (*cdevsw[major(dev)].d_select)(dev, flag, wql, p);
197 if (constty != NULL) {
198 ttyfree(constty);
199 }
200 return error;
201}
202