1 /* $NetBSD: promcons.c,v 1.41 2020/09/03 02:09:09 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
5 * All rights reserved.
6 *
7 * Author: Chris G. Demetriou
8 *
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
28 */
29
30 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
31
32 __KERNEL_RCSID(0, "$NetBSD: promcons.c,v 1.41 2020/09/03 02:09:09 thorpej Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/ioctl.h>
37 #include <sys/select.h>
38 #include <sys/tty.h>
39 #include <sys/proc.h>
40 #include <sys/file.h>
41 #include <sys/uio.h>
42 #include <sys/kernel.h>
43 #include <sys/syslog.h>
44 #include <sys/types.h>
45 #include <sys/device.h>
46 #include <sys/conf.h>
47 #include <sys/kauth.h>
48
49 #include <uvm/uvm_extern.h>
50
51 #include <machine/cpuconf.h>
52 #include <machine/prom.h>
53
54 #ifndef CONSPEED
55 #define CONSPEED 9600
56 #endif
57
58 #ifdef _PROM_MAY_USE_PROM_CONSOLE
59
60 dev_type_open(promopen);
61 dev_type_close(promclose);
62 dev_type_read(promread);
63 dev_type_write(promwrite);
64 dev_type_ioctl(promioctl);
65 dev_type_stop(promstop);
66 dev_type_tty(promtty);
67 dev_type_poll(prompoll);
68
69 const struct cdevsw prom_cdevsw = {
70 .d_open = promopen,
71 .d_close = promclose,
72 .d_read = promread,
73 .d_write = promwrite,
74 .d_ioctl = promioctl,
75 .d_stop = promstop,
76 .d_tty = promtty,
77 .d_poll = prompoll,
78 .d_mmap = nommap,
79 .d_kqfilter = ttykqfilter,
80 .d_discard = nodiscard,
81 .d_flag = D_TTY
82 };
83
84 #define PROM_POLL_HZ 50
85
86 static struct tty *prom_tty[1];
87 static int polltime;
88
89 void promstart(struct tty *);
90 void promtimeout(void *);
91 int promparam(struct tty *, struct termios *);
92
93 struct callout prom_ch;
94
95 int
promopen(dev_t dev,int flag,int mode,struct lwp * l)96 promopen(dev_t dev, int flag, int mode, struct lwp *l)
97 {
98 int unit = minor(dev);
99 struct tty *tp;
100 int s;
101 int error = 0, setuptimeout = 0;
102 static bool callo;
103
104 if (!callo) {
105 callout_init(&prom_ch, 0);
106 callo = true;
107 }
108
109 if (!prom_uses_prom_console() || unit >= 1)
110 return ENXIO;
111
112 s = spltty();
113
114 if (!prom_tty[unit]) {
115 tp = prom_tty[unit] = tty_alloc();
116 tty_attach(tp);
117 } else
118 tp = prom_tty[unit];
119
120 tp->t_oproc = promstart;
121 tp->t_param = promparam;
122 tp->t_dev = dev;
123
124 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
125 splx(s);
126 return (EBUSY);
127 }
128
129 if ((tp->t_state & TS_ISOPEN) == 0) {
130 tp->t_state |= TS_CARR_ON;
131 ttychars(tp);
132 tp->t_iflag = TTYDEF_IFLAG;
133 tp->t_oflag = TTYDEF_OFLAG;
134 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
135 tp->t_lflag = TTYDEF_LFLAG;
136 tp->t_ispeed = tp->t_ospeed = CONSPEED;
137 ttsetwater(tp);
138
139 setuptimeout = 1;
140 }
141
142 splx(s);
143
144 error = (*tp->t_linesw->l_open)(dev, tp);
145 if (error == 0 && setuptimeout) {
146 polltime = hz / PROM_POLL_HZ;
147 if (polltime < 1)
148 polltime = 1;
149 callout_reset(&prom_ch, polltime, promtimeout, tp);
150 }
151 return error;
152 }
153
154 int
promclose(dev_t dev,int flag,int mode,struct lwp * l)155 promclose(dev_t dev, int flag, int mode, struct lwp *l)
156 {
157 int unit = minor(dev);
158 struct tty *tp = prom_tty[unit];
159
160 callout_stop(&prom_ch);
161 (*tp->t_linesw->l_close)(tp, flag);
162 ttyclose(tp);
163 return 0;
164 }
165
166 int
promread(dev_t dev,struct uio * uio,int flag)167 promread(dev_t dev, struct uio *uio, int flag)
168 {
169 struct tty *tp = prom_tty[minor(dev)];
170
171 return ((*tp->t_linesw->l_read)(tp, uio, flag));
172 }
173
174 int
promwrite(dev_t dev,struct uio * uio,int flag)175 promwrite(dev_t dev, struct uio *uio, int flag)
176 {
177 struct tty *tp = prom_tty[minor(dev)];
178
179 return ((*tp->t_linesw->l_write)(tp, uio, flag));
180 }
181
182 int
prompoll(dev_t dev,int events,struct lwp * l)183 prompoll(dev_t dev, int events, struct lwp *l)
184 {
185 struct tty *tp = prom_tty[minor(dev)];
186
187 return ((*tp->t_linesw->l_poll)(tp, events, l));
188 }
189
190 int
promioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)191 promioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
192 {
193 int unit = minor(dev);
194 struct tty *tp = prom_tty[unit];
195 int error;
196
197 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
198 if (error != EPASSTHROUGH)
199 return error;
200 return ttioctl(tp, cmd, data, flag, l);
201 }
202
203 int
promparam(struct tty * tp,struct termios * t)204 promparam(struct tty *tp, struct termios *t)
205 {
206
207 return 0;
208 }
209
210 void
promstart(struct tty * tp)211 promstart(struct tty *tp)
212 {
213 int s;
214
215 s = spltty();
216 if (tp->t_state & (TS_TTSTOP | TS_BUSY))
217 goto out;
218 ttypull(tp);
219 tp->t_state |= TS_BUSY;
220 while (tp->t_outq.c_cc != 0)
221 promcnputc(tp->t_dev, getc(&tp->t_outq));
222 tp->t_state &= ~TS_BUSY;
223 out:
224 splx(s);
225 }
226
227 /*
228 * Stop output on a line.
229 */
230 void
promstop(struct tty * tp,int flag)231 promstop(struct tty *tp, int flag)
232 {
233 int s;
234
235 s = spltty();
236 if (tp->t_state & TS_BUSY)
237 if ((tp->t_state & TS_TTSTOP) == 0)
238 tp->t_state |= TS_FLUSH;
239 splx(s);
240 }
241
242 void
promtimeout(void * v)243 promtimeout(void *v)
244 {
245 struct tty *tp = v;
246 u_char c;
247
248 while (promcnlookc(tp->t_dev, &c)) {
249 if (tp->t_state & TS_ISOPEN)
250 (*tp->t_linesw->l_rint)(c, tp);
251 }
252 callout_reset(&prom_ch, polltime, promtimeout, tp);
253 }
254
255 struct tty *
promtty(dev_t dev)256 promtty(dev_t dev)
257 {
258
259 if (minor(dev) != 0)
260 panic("promtty: bogus");
261
262 return prom_tty[0];
263 }
264
265 #else /* _PROM_MAY_USE_PROM_CONSOLE */
266
267 /*
268 * If not defined _PROM_MAY_USE_PROM_CONSOLE,
269 * this fake prom_cdevsw is attached to the kernel.
270 * NEVER REMOVE!
271 */
272 const struct cdevsw prom_cdevsw = {
273 .d_open = noopen,
274 .d_close = noclose,
275 .d_read = noread,
276 .d_write = nowrite,
277 .d_ioctl = noioctl,
278 .d_stop = nostop,
279 .d_tty = notty,
280 .d_poll = nopoll,
281 .d_mmap = nommap,
282 .d_kqfilter = nokqfilter,
283 .d_discard = nodiscard,
284 .d_flag = 0
285 };
286
287 #endif /* _PROM_MAY_USE_PROM_CONSOLE */
288