siotty.c revision 1.42 1 1.42 dholland /* $NetBSD: siotty.c,v 1.42 2014/07/25 08:10:33 dholland Exp $ */
2 1.1 nisimura
3 1.1 nisimura /*-
4 1.1 nisimura * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 1.1 nisimura * All rights reserved.
6 1.1 nisimura *
7 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation
8 1.1 nisimura * by Tohru Nishimura.
9 1.1 nisimura *
10 1.1 nisimura * Redistribution and use in source and binary forms, with or without
11 1.1 nisimura * modification, are permitted provided that the following conditions
12 1.1 nisimura * are met:
13 1.1 nisimura * 1. Redistributions of source code must retain the above copyright
14 1.1 nisimura * notice, this list of conditions and the following disclaimer.
15 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 nisimura * notice, this list of conditions and the following disclaimer in the
17 1.1 nisimura * documentation and/or other materials provided with the distribution.
18 1.1 nisimura *
19 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE.
30 1.1 nisimura */
31 1.1 nisimura
32 1.1 nisimura #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
33 1.1 nisimura
34 1.42 dholland __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.42 2014/07/25 08:10:33 dholland Exp $");
35 1.1 nisimura
36 1.1 nisimura #include "opt_ddb.h"
37 1.1 nisimura
38 1.1 nisimura #include <sys/param.h>
39 1.1 nisimura #include <sys/systm.h>
40 1.1 nisimura #include <sys/device.h>
41 1.1 nisimura #include <sys/conf.h>
42 1.1 nisimura #include <sys/ioctl.h>
43 1.1 nisimura #include <sys/proc.h>
44 1.1 nisimura #include <sys/tty.h>
45 1.1 nisimura #include <sys/uio.h>
46 1.1 nisimura #include <sys/callout.h>
47 1.1 nisimura #include <sys/fcntl.h>
48 1.1 nisimura #include <dev/cons.h>
49 1.17 elad #include <sys/kauth.h>
50 1.37 tsutsui #include <sys/kmem.h>
51 1.1 nisimura
52 1.1 nisimura #include <machine/cpu.h>
53 1.1 nisimura
54 1.1 nisimura #include <luna68k/dev/sioreg.h>
55 1.1 nisimura #include <luna68k/dev/siovar.h>
56 1.1 nisimura
57 1.31 tsutsui #include "ioconf.h"
58 1.31 tsutsui
59 1.1 nisimura #define TIOCM_BREAK 01000 /* non standard use */
60 1.1 nisimura
61 1.32 tsutsui static const uint8_t ch0_regs[6] = {
62 1.1 nisimura WR0_RSTINT, /* reset E/S interrupt */
63 1.35 tsutsui WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
64 1.1 nisimura 0, /* */
65 1.1 nisimura WR3_RX8BIT | WR3_RXENBL, /* Rx */
66 1.1 nisimura WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
67 1.1 nisimura WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
68 1.1 nisimura };
69 1.1 nisimura
70 1.14 matt static const struct speedtab siospeedtab[] = {
71 1.1 nisimura { 2400, WR4_BAUD24, },
72 1.1 nisimura { 4800, WR4_BAUD48, },
73 1.1 nisimura { 9600, WR4_BAUD96, },
74 1.1 nisimura { -1, 0, },
75 1.1 nisimura };
76 1.1 nisimura
77 1.1 nisimura struct siotty_softc {
78 1.31 tsutsui device_t sc_dev;
79 1.1 nisimura struct tty *sc_tty;
80 1.1 nisimura struct sioreg *sc_ctl;
81 1.35 tsutsui u_int sc_flags;
82 1.32 tsutsui uint8_t sc_wr[6];
83 1.37 tsutsui void *sc_si; /* software interrupt handler */
84 1.37 tsutsui u_int sc_hwflags;
85 1.37 tsutsui #define SIOTTY_HW_CONSOLE 0x0001
86 1.37 tsutsui
87 1.37 tsutsui uint8_t *sc_rbuf;
88 1.37 tsutsui uint8_t *sc_rbufend;
89 1.37 tsutsui uint8_t * volatile sc_rbget;
90 1.37 tsutsui uint8_t * volatile sc_rbput;
91 1.37 tsutsui volatile u_int sc_rbavail;
92 1.37 tsutsui
93 1.37 tsutsui uint8_t *sc_tba;
94 1.37 tsutsui u_int sc_tbc;
95 1.37 tsutsui
96 1.37 tsutsui bool sc_rx_ready;
97 1.37 tsutsui bool sc_tx_busy;
98 1.37 tsutsui bool sc_tx_done;
99 1.1 nisimura };
100 1.1 nisimura
101 1.37 tsutsui #define SIOTTY_RING_SIZE 2048
102 1.37 tsutsui u_int siotty_rbuf_size = SIOTTY_RING_SIZE;
103 1.37 tsutsui
104 1.37 tsutsui static struct cnm_state siotty_cnm_state;
105 1.37 tsutsui
106 1.1 nisimura #include "siotty.h"
107 1.24 dsl static void siostart(struct tty *);
108 1.24 dsl static int sioparam(struct tty *, struct termios *);
109 1.39 tsutsui static void siottyintr(void *);
110 1.37 tsutsui static void siottysoft(void *);
111 1.37 tsutsui static void siotty_rxsoft(struct siotty_softc *, struct tty *);
112 1.37 tsutsui static void siotty_txsoft(struct siotty_softc *, struct tty *);
113 1.24 dsl static int siomctl(struct siotty_softc *, int, int);
114 1.1 nisimura
115 1.31 tsutsui static int siotty_match(device_t, cfdata_t, void *);
116 1.31 tsutsui static void siotty_attach(device_t, device_t, void *);
117 1.1 nisimura
118 1.31 tsutsui CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc),
119 1.11 thorpej siotty_match, siotty_attach, NULL, NULL);
120 1.1 nisimura
121 1.10 gehenna dev_type_open(sioopen);
122 1.10 gehenna dev_type_close(sioclose);
123 1.10 gehenna dev_type_read(sioread);
124 1.10 gehenna dev_type_write(siowrite);
125 1.10 gehenna dev_type_ioctl(sioioctl);
126 1.10 gehenna dev_type_stop(siostop);
127 1.10 gehenna dev_type_tty(siotty);
128 1.10 gehenna dev_type_poll(siopoll);
129 1.10 gehenna
130 1.10 gehenna const struct cdevsw siotty_cdevsw = {
131 1.40 dholland .d_open = sioopen,
132 1.40 dholland .d_close = sioclose,
133 1.40 dholland .d_read = sioread,
134 1.40 dholland .d_write = siowrite,
135 1.40 dholland .d_ioctl = sioioctl,
136 1.40 dholland .d_stop = siostop,
137 1.40 dholland .d_tty = siotty,
138 1.40 dholland .d_poll = siopoll,
139 1.40 dholland .d_mmap = nommap,
140 1.40 dholland .d_kqfilter = ttykqfilter,
141 1.42 dholland .d_discard = nodiscard,
142 1.40 dholland .d_flag = D_TTY
143 1.10 gehenna };
144 1.10 gehenna
145 1.35 tsutsui static int
146 1.31 tsutsui siotty_match(device_t parent, cfdata_t cf, void *aux)
147 1.1 nisimura {
148 1.1 nisimura struct sio_attach_args *args = aux;
149 1.1 nisimura
150 1.1 nisimura if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
151 1.1 nisimura return 0;
152 1.1 nisimura return 1;
153 1.1 nisimura }
154 1.1 nisimura
155 1.35 tsutsui static void
156 1.34 tsutsui siotty_attach(device_t parent, device_t self, void *aux)
157 1.1 nisimura {
158 1.39 tsutsui struct sio_softc *siosc = device_private(parent);
159 1.31 tsutsui struct siotty_softc *sc = device_private(self);
160 1.1 nisimura struct sio_attach_args *args = aux;
161 1.39 tsutsui int channel;
162 1.37 tsutsui struct tty *tp;
163 1.1 nisimura
164 1.31 tsutsui sc->sc_dev = self;
165 1.39 tsutsui channel = args->channel;
166 1.39 tsutsui sc->sc_ctl = &siosc->sc_ctl[channel];
167 1.28 cegger memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
168 1.39 tsutsui siosc->sc_intrhand[channel].ih_func = siottyintr;
169 1.39 tsutsui siosc->sc_intrhand[channel].ih_arg = sc;
170 1.37 tsutsui if (args->hwflags == 1)
171 1.37 tsutsui sc->sc_hwflags |= SIOTTY_HW_CONSOLE;
172 1.1 nisimura
173 1.37 tsutsui if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0) {
174 1.31 tsutsui aprint_normal(" (console)");
175 1.1 nisimura sc->sc_flags = TIOCFLAG_SOFTCAR;
176 1.32 tsutsui } else {
177 1.1 nisimura setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
178 1.1 nisimura setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
179 1.1 nisimura setsioreg(sc->sc_ctl, WR2B, 0);
180 1.1 nisimura setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
181 1.1 nisimura setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
182 1.1 nisimura setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
183 1.1 nisimura setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
184 1.1 nisimura setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
185 1.1 nisimura }
186 1.1 nisimura setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
187 1.1 nisimura
188 1.31 tsutsui aprint_normal("\n");
189 1.37 tsutsui
190 1.37 tsutsui sc->sc_rbuf = kmem_alloc(siotty_rbuf_size * 2, KM_NOSLEEP);
191 1.37 tsutsui if (sc->sc_rbuf == NULL) {
192 1.37 tsutsui aprint_error_dev(self, "unable to allocate ring buffer\n");
193 1.37 tsutsui return;
194 1.37 tsutsui }
195 1.37 tsutsui sc->sc_rbufend = sc->sc_rbuf + (siotty_rbuf_size * 2);
196 1.37 tsutsui sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
197 1.37 tsutsui sc->sc_rbavail = siotty_rbuf_size;
198 1.37 tsutsui
199 1.37 tsutsui tp = tty_alloc();
200 1.37 tsutsui tp->t_oproc = siostart;
201 1.37 tsutsui tp->t_param = sioparam;
202 1.37 tsutsui tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
203 1.37 tsutsui if ((sc->sc_hwflags & SIOTTY_HW_CONSOLE) != 0)
204 1.37 tsutsui tp->t_dev = cn_tab->cn_dev;
205 1.37 tsutsui sc->sc_tty = tp;
206 1.37 tsutsui
207 1.37 tsutsui tty_attach(tp);
208 1.37 tsutsui
209 1.37 tsutsui sc->sc_si = softint_establish(SOFTINT_SERIAL, siottysoft, sc);
210 1.1 nisimura }
211 1.1 nisimura
212 1.1 nisimura /*-------------------- low level routine --------------------*/
213 1.1 nisimura
214 1.1 nisimura static void
215 1.39 tsutsui siottyintr(void *arg)
216 1.1 nisimura {
217 1.1 nisimura struct siotty_softc *sc;
218 1.1 nisimura struct sioreg *sio;
219 1.37 tsutsui uint8_t *put, *end;
220 1.37 tsutsui uint8_t c;
221 1.37 tsutsui uint16_t rr;
222 1.37 tsutsui int cc;
223 1.1 nisimura
224 1.39 tsutsui sc = arg;
225 1.37 tsutsui end = sc->sc_rbufend;
226 1.37 tsutsui put = sc->sc_rbput;
227 1.37 tsutsui cc = sc->sc_rbavail;
228 1.37 tsutsui
229 1.1 nisimura sio = sc->sc_ctl;
230 1.1 nisimura rr = getsiocsr(sio);
231 1.37 tsutsui if ((rr & RR_BREAK) != 0) {
232 1.37 tsutsui sio->sio_cmd = WR0_RSTINT;
233 1.37 tsutsui cn_check_magic(sc->sc_tty->t_dev, CNC_BREAK, siotty_cnm_state);
234 1.37 tsutsui }
235 1.41 tsutsui if ((rr & RR_RXRDY) != 0) {
236 1.1 nisimura do {
237 1.37 tsutsui if (cc > 0) {
238 1.37 tsutsui c = sio->sio_data;
239 1.37 tsutsui cn_check_magic(sc->sc_tty->t_dev, c,
240 1.37 tsutsui siotty_cnm_state);
241 1.37 tsutsui put[0] = c;
242 1.37 tsutsui put[1] = rr & 0xff;
243 1.37 tsutsui put += 2;
244 1.37 tsutsui if (put >= end)
245 1.37 tsutsui put = sc->sc_rbuf;
246 1.37 tsutsui cc--;
247 1.37 tsutsui }
248 1.37 tsutsui if ((rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) != 0)
249 1.1 nisimura sio->sio_cmd = WR0_ERRRST;
250 1.37 tsutsui
251 1.37 tsutsui sc->sc_rbput = put;
252 1.37 tsutsui sc->sc_rbavail = cc;
253 1.37 tsutsui sc->sc_rx_ready = true;
254 1.41 tsutsui } while (((rr = getsiocsr(sio)) & RR_RXRDY) != 0);
255 1.1 nisimura }
256 1.41 tsutsui if ((rr & RR_TXRDY) != 0) {
257 1.1 nisimura sio->sio_cmd = WR0_RSTPEND;
258 1.37 tsutsui if (sc->sc_tbc > 0) {
259 1.37 tsutsui sio->sio_data = *sc->sc_tba;
260 1.37 tsutsui sc->sc_tba++;
261 1.37 tsutsui sc->sc_tbc--;
262 1.37 tsutsui } else {
263 1.37 tsutsui if (sc->sc_tx_busy) {
264 1.37 tsutsui sc->sc_tx_busy = false;
265 1.37 tsutsui sc->sc_tx_done = true;
266 1.37 tsutsui }
267 1.1 nisimura }
268 1.1 nisimura }
269 1.37 tsutsui softint_schedule(sc->sc_si);
270 1.37 tsutsui }
271 1.37 tsutsui
272 1.37 tsutsui static void
273 1.37 tsutsui siottysoft(void *arg)
274 1.37 tsutsui {
275 1.37 tsutsui struct siotty_softc *sc;
276 1.37 tsutsui struct tty *tp;
277 1.37 tsutsui
278 1.37 tsutsui sc = arg;
279 1.37 tsutsui tp = sc->sc_tty;
280 1.37 tsutsui
281 1.37 tsutsui if (sc->sc_rx_ready) {
282 1.37 tsutsui sc->sc_rx_ready = false;
283 1.37 tsutsui siotty_rxsoft(sc, tp);
284 1.37 tsutsui }
285 1.37 tsutsui if (sc->sc_tx_done) {
286 1.37 tsutsui sc->sc_tx_done = false;
287 1.37 tsutsui siotty_txsoft(sc, tp);
288 1.37 tsutsui }
289 1.37 tsutsui }
290 1.37 tsutsui
291 1.37 tsutsui static void
292 1.37 tsutsui siotty_rxsoft(struct siotty_softc *sc, struct tty *tp)
293 1.37 tsutsui {
294 1.37 tsutsui uint8_t *get, *end;
295 1.37 tsutsui u_int cc, scc;
296 1.37 tsutsui unsigned int code;
297 1.37 tsutsui uint8_t stat;
298 1.37 tsutsui int s;
299 1.37 tsutsui
300 1.37 tsutsui end = sc->sc_rbufend;
301 1.37 tsutsui get = sc->sc_rbget;
302 1.37 tsutsui scc = cc = siotty_rbuf_size - sc->sc_rbavail;
303 1.37 tsutsui
304 1.37 tsutsui if (cc == siotty_rbuf_size) {
305 1.37 tsutsui printf("%s: rx buffer overflow\n", device_xname(sc->sc_dev));
306 1.37 tsutsui }
307 1.37 tsutsui
308 1.37 tsutsui while (cc > 0) {
309 1.37 tsutsui code = get[0];
310 1.37 tsutsui stat = get[1];
311 1.37 tsutsui if ((stat & RR_FRAMING) != 0)
312 1.37 tsutsui code |= TTY_FE;
313 1.37 tsutsui else if ((stat & RR_PARITY) != 0)
314 1.37 tsutsui code |= TTY_PE;
315 1.37 tsutsui
316 1.37 tsutsui (*tp->t_linesw->l_rint)(code, tp);
317 1.37 tsutsui get += 2;
318 1.37 tsutsui if (get >= end)
319 1.37 tsutsui get = sc->sc_rbuf;
320 1.37 tsutsui cc--;
321 1.37 tsutsui }
322 1.37 tsutsui
323 1.37 tsutsui if (cc != scc) {
324 1.37 tsutsui s = splserial();
325 1.37 tsutsui sc->sc_rbget = get;
326 1.37 tsutsui sc->sc_rbavail += scc - cc;
327 1.37 tsutsui splx(s);
328 1.37 tsutsui }
329 1.37 tsutsui }
330 1.37 tsutsui
331 1.37 tsutsui static void
332 1.37 tsutsui siotty_txsoft(struct siotty_softc *sc, struct tty *tp)
333 1.37 tsutsui {
334 1.37 tsutsui
335 1.37 tsutsui tp->t_state &= ~TS_BUSY;
336 1.37 tsutsui if ((tp->t_state & TS_FLUSH) != 0)
337 1.37 tsutsui tp->t_state &= ~TS_FLUSH;
338 1.37 tsutsui else
339 1.37 tsutsui ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
340 1.37 tsutsui (*tp->t_linesw->l_start)(tp);
341 1.1 nisimura }
342 1.1 nisimura
343 1.1 nisimura static void
344 1.23 cegger siostart(struct tty *tp)
345 1.1 nisimura {
346 1.32 tsutsui struct siotty_softc *sc;
347 1.37 tsutsui int s;
348 1.37 tsutsui uint8_t *tba;
349 1.37 tsutsui int tbc;
350 1.35 tsutsui
351 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
352 1.33 tsutsui s = splserial();
353 1.41 tsutsui if ((tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP)) != 0)
354 1.1 nisimura goto out;
355 1.21 ad if (!ttypull(tp))
356 1.1 nisimura goto out;
357 1.1 nisimura tp->t_state |= TS_BUSY;
358 1.37 tsutsui
359 1.37 tsutsui tba = tp->t_outq.c_cf;
360 1.37 tsutsui tbc = ndqb(&tp->t_outq, 0);
361 1.37 tsutsui
362 1.37 tsutsui sc->sc_tba = tba;
363 1.37 tsutsui sc->sc_tbc = tbc;
364 1.37 tsutsui sc->sc_tx_busy = true;
365 1.37 tsutsui
366 1.37 tsutsui sc->sc_ctl->sio_data = *sc->sc_tba;
367 1.37 tsutsui sc->sc_tba++;
368 1.37 tsutsui sc->sc_tbc--;
369 1.1 nisimura out:
370 1.1 nisimura splx(s);
371 1.1 nisimura }
372 1.1 nisimura
373 1.1 nisimura void
374 1.25 dsl siostop(struct tty *tp, int flag)
375 1.1 nisimura {
376 1.1 nisimura int s;
377 1.1 nisimura
378 1.35 tsutsui s = splserial();
379 1.35 tsutsui if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
380 1.35 tsutsui /*
381 1.35 tsutsui * Device is transmitting; must stop it.
382 1.35 tsutsui */
383 1.1 nisimura tp->t_state |= TS_FLUSH;
384 1.35 tsutsui }
385 1.35 tsutsui splx(s);
386 1.1 nisimura }
387 1.1 nisimura
388 1.1 nisimura static int
389 1.23 cegger sioparam(struct tty *tp, struct termios *t)
390 1.1 nisimura {
391 1.32 tsutsui struct siotty_softc *sc;
392 1.1 nisimura int wr4, s;
393 1.1 nisimura
394 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
395 1.1 nisimura if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
396 1.1 nisimura return EINVAL;
397 1.1 nisimura wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
398 1.1 nisimura if (wr4 < 0)
399 1.1 nisimura return EINVAL;
400 1.1 nisimura
401 1.41 tsutsui if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0) {
402 1.1 nisimura t->c_cflag |= CLOCAL;
403 1.1 nisimura t->c_cflag &= ~HUPCL;
404 1.1 nisimura }
405 1.41 tsutsui if ((sc->sc_flags & TIOCFLAG_CLOCAL) != 0)
406 1.1 nisimura t->c_cflag |= CLOCAL;
407 1.1 nisimura
408 1.1 nisimura /*
409 1.1 nisimura * If there were no changes, don't do anything. This avoids dropping
410 1.1 nisimura * input and improves performance when all we did was frob things like
411 1.1 nisimura * VMIN and VTIME.
412 1.1 nisimura */
413 1.1 nisimura if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
414 1.1 nisimura return 0;
415 1.1 nisimura
416 1.1 nisimura tp->t_ispeed = t->c_ispeed;
417 1.1 nisimura tp->t_ospeed = t->c_ospeed;
418 1.1 nisimura tp->t_cflag = t->c_cflag;
419 1.1 nisimura
420 1.1 nisimura sc->sc_wr[WR3] &= 0x3f;
421 1.1 nisimura sc->sc_wr[WR5] &= 0x9f;
422 1.1 nisimura switch (tp->t_cflag & CSIZE) {
423 1.1 nisimura case CS7:
424 1.1 nisimura sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
425 1.1 nisimura break;
426 1.1 nisimura case CS8:
427 1.1 nisimura sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
428 1.1 nisimura break;
429 1.1 nisimura }
430 1.41 tsutsui if ((tp->t_cflag & PARENB) != 0) {
431 1.1 nisimura wr4 |= WR4_PARENAB;
432 1.1 nisimura if ((tp->t_cflag & PARODD) == 0)
433 1.1 nisimura wr4 |= WR4_EPARITY;
434 1.1 nisimura }
435 1.36 tsutsui wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
436 1.1 nisimura sc->sc_wr[WR4] = wr4;
437 1.1 nisimura
438 1.33 tsutsui s = splserial();
439 1.1 nisimura setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
440 1.1 nisimura setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
441 1.1 nisimura setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
442 1.1 nisimura splx(s);
443 1.1 nisimura
444 1.1 nisimura return 0;
445 1.1 nisimura }
446 1.1 nisimura
447 1.1 nisimura static int
448 1.26 dsl siomctl(struct siotty_softc *sc, int control, int op)
449 1.1 nisimura {
450 1.37 tsutsui int val, s;
451 1.37 tsutsui uint8_t wr5;
452 1.37 tsutsui uint16_t rr;
453 1.1 nisimura
454 1.1 nisimura val = 0;
455 1.41 tsutsui if ((control & TIOCM_BREAK) != 0)
456 1.1 nisimura val |= WR5_BREAK;
457 1.41 tsutsui if ((control & TIOCM_DTR) != 0)
458 1.1 nisimura val |= WR5_DTR;
459 1.41 tsutsui if ((control & TIOCM_RTS) != 0)
460 1.1 nisimura val |= WR5_RTS;
461 1.33 tsutsui s = splserial();
462 1.1 nisimura wr5 = sc->sc_wr[WR5];
463 1.1 nisimura switch (op) {
464 1.1 nisimura case DMSET:
465 1.1 nisimura wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
466 1.1 nisimura /* FALLTHRU */
467 1.1 nisimura case DMBIS:
468 1.1 nisimura wr5 |= val;
469 1.1 nisimura break;
470 1.1 nisimura case DMBIC:
471 1.1 nisimura wr5 &= ~val;
472 1.1 nisimura break;
473 1.1 nisimura case DMGET:
474 1.1 nisimura val = 0;
475 1.1 nisimura rr = getsiocsr(sc->sc_ctl);
476 1.41 tsutsui if ((wr5 & WR5_DTR) != 0)
477 1.1 nisimura val |= TIOCM_DTR;
478 1.41 tsutsui if ((wr5 & WR5_RTS) != 0)
479 1.1 nisimura val |= TIOCM_RTS;
480 1.41 tsutsui if ((rr & RR_CTS) != 0)
481 1.1 nisimura val |= TIOCM_CTS;
482 1.41 tsutsui if ((rr & RR_DCD) != 0)
483 1.1 nisimura val |= TIOCM_CD;
484 1.1 nisimura goto done;
485 1.1 nisimura }
486 1.1 nisimura sc->sc_wr[WR5] = wr5;
487 1.1 nisimura setsioreg(sc->sc_ctl, WR5, wr5);
488 1.1 nisimura val = 0;
489 1.35 tsutsui done:
490 1.1 nisimura splx(s);
491 1.1 nisimura return val;
492 1.1 nisimura }
493 1.1 nisimura
494 1.1 nisimura /*-------------------- cdevsw[] interface --------------------*/
495 1.1 nisimura
496 1.1 nisimura int
497 1.23 cegger sioopen(dev_t dev, int flag, int mode, struct lwp *l)
498 1.1 nisimura {
499 1.1 nisimura struct siotty_softc *sc;
500 1.1 nisimura struct tty *tp;
501 1.1 nisimura int error;
502 1.37 tsutsui int s;
503 1.1 nisimura
504 1.23 cegger sc = device_lookup_private(&siotty_cd, minor(dev));
505 1.23 cegger if (sc == NULL)
506 1.1 nisimura return ENXIO;
507 1.1 nisimura
508 1.37 tsutsui tp = sc->sc_tty;
509 1.19 elad
510 1.19 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
511 1.32 tsutsui return EBUSY;
512 1.19 elad
513 1.1 nisimura if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
514 1.1 nisimura struct termios t;
515 1.1 nisimura
516 1.37 tsutsui tp->t_dev = dev;
517 1.1 nisimura t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
518 1.1 nisimura t.c_cflag = TTYDEF_CFLAG;
519 1.1 nisimura tp->t_ospeed = 0; /* force register update */
520 1.1 nisimura (void)sioparam(tp, &t);
521 1.1 nisimura tp->t_iflag = TTYDEF_IFLAG;
522 1.1 nisimura tp->t_oflag = TTYDEF_OFLAG;
523 1.1 nisimura tp->t_lflag = TTYDEF_LFLAG;
524 1.1 nisimura ttychars(tp);
525 1.1 nisimura ttsetwater(tp);
526 1.1 nisimura /* raise RTS and DTR here; but, DTR lead is not wired */
527 1.1 nisimura /* then check DCD condition; but, DCD lead is not wired */
528 1.1 nisimura #if 0
529 1.41 tsutsui if ((sc->sc_flags & TIOCFLAG_SOFTCAR) != 0
530 1.41 tsutsui || (tp->t_cflag & MDMBUF) != 0
531 1.41 tsutsui || (getsiocsr(sc->sc_ctl) & RR_DCD) != 0)
532 1.1 nisimura tp->t_state |= TS_CARR_ON;
533 1.1 nisimura else
534 1.1 nisimura tp->t_state &= ~TS_CARR_ON;
535 1.37 tsutsui #else
536 1.37 tsutsui tp->t_state |= TS_CARR_ON; /* assume detected all the time */
537 1.1 nisimura #endif
538 1.37 tsutsui
539 1.37 tsutsui s = splserial();
540 1.37 tsutsui sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
541 1.37 tsutsui sc->sc_rbavail = siotty_rbuf_size;
542 1.37 tsutsui splx(s);
543 1.1 nisimura }
544 1.1 nisimura
545 1.1 nisimura error = ttyopen(tp, 0, (flag & O_NONBLOCK));
546 1.1 nisimura if (error > 0)
547 1.1 nisimura return error;
548 1.5 eeh return (*tp->t_linesw->l_open)(dev, tp);
549 1.1 nisimura }
550 1.35 tsutsui
551 1.1 nisimura int
552 1.23 cegger sioclose(dev_t dev, int flag, int mode, struct lwp *l)
553 1.1 nisimura {
554 1.23 cegger struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
555 1.1 nisimura struct tty *tp = sc->sc_tty;
556 1.1 nisimura int s;
557 1.1 nisimura
558 1.5 eeh (*tp->t_linesw->l_close)(tp, flag);
559 1.1 nisimura
560 1.33 tsutsui s = splserial();
561 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIC);
562 1.1 nisimura #if 0 /* because unable to feed DTR signal */
563 1.41 tsutsui if ((tp->t_cflag & HUPCL) != 0
564 1.1 nisimura || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
565 1.1 nisimura siomctl(sc, TIOCM_DTR, DMBIC);
566 1.1 nisimura /* Yield CPU time to others for 1 second, then ... */
567 1.1 nisimura siomctl(sc, TIOCM_DTR, DMBIS);
568 1.1 nisimura }
569 1.1 nisimura #endif
570 1.1 nisimura splx(s);
571 1.1 nisimura return ttyclose(tp);
572 1.1 nisimura }
573 1.35 tsutsui
574 1.1 nisimura int
575 1.23 cegger sioread(dev_t dev, struct uio *uio, int flag)
576 1.1 nisimura {
577 1.32 tsutsui struct siotty_softc *sc;
578 1.32 tsutsui struct tty *tp;
579 1.35 tsutsui
580 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
581 1.32 tsutsui tp = sc->sc_tty;
582 1.5 eeh return (*tp->t_linesw->l_read)(tp, uio, flag);
583 1.1 nisimura }
584 1.35 tsutsui
585 1.1 nisimura int
586 1.23 cegger siowrite(dev_t dev, struct uio *uio, int flag)
587 1.1 nisimura {
588 1.32 tsutsui struct siotty_softc *sc;
589 1.32 tsutsui struct tty *tp;
590 1.35 tsutsui
591 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
592 1.32 tsutsui tp = sc->sc_tty;
593 1.5 eeh return (*tp->t_linesw->l_write)(tp, uio, flag);
594 1.8 scw }
595 1.8 scw
596 1.8 scw int
597 1.23 cegger siopoll(dev_t dev, int events, struct lwp *l)
598 1.8 scw {
599 1.32 tsutsui struct siotty_softc *sc;
600 1.32 tsutsui struct tty *tp;
601 1.35 tsutsui
602 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
603 1.32 tsutsui tp = sc->sc_tty;
604 1.16 christos return ((*tp->t_linesw->l_poll)(tp, events, l));
605 1.1 nisimura }
606 1.1 nisimura
607 1.1 nisimura int
608 1.23 cegger sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
609 1.1 nisimura {
610 1.32 tsutsui struct siotty_softc *sc;
611 1.32 tsutsui struct tty *tp;
612 1.1 nisimura int error;
613 1.1 nisimura
614 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
615 1.32 tsutsui tp = sc->sc_tty;
616 1.16 christos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
617 1.9 atatat if (error != EPASSTHROUGH)
618 1.1 nisimura return error;
619 1.9 atatat
620 1.16 christos error = ttioctl(tp, cmd, data, flag, l);
621 1.9 atatat if (error != EPASSTHROUGH)
622 1.1 nisimura return error;
623 1.1 nisimura
624 1.1 nisimura /* the last resort for TIOC ioctl tranversing */
625 1.1 nisimura switch (cmd) {
626 1.1 nisimura case TIOCSBRK: /* Set the hardware into BREAK condition */
627 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIS);
628 1.1 nisimura break;
629 1.1 nisimura case TIOCCBRK: /* Clear the hardware BREAK condition */
630 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIC);
631 1.1 nisimura break;
632 1.1 nisimura case TIOCSDTR: /* Assert DTR signal */
633 1.1 nisimura siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
634 1.1 nisimura break;
635 1.1 nisimura case TIOCCDTR: /* Clear DTR signal */
636 1.1 nisimura siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
637 1.1 nisimura break;
638 1.1 nisimura case TIOCMSET: /* Set modem state replacing current one */
639 1.1 nisimura siomctl(sc, *(int *)data, DMSET);
640 1.1 nisimura break;
641 1.1 nisimura case TIOCMGET: /* Return current modem state */
642 1.1 nisimura *(int *)data = siomctl(sc, 0, DMGET);
643 1.1 nisimura break;
644 1.1 nisimura case TIOCMBIS: /* Set individual bits of modem state */
645 1.1 nisimura siomctl(sc, *(int *)data, DMBIS);
646 1.1 nisimura break;
647 1.1 nisimura case TIOCMBIC: /* Clear individual bits of modem state */
648 1.1 nisimura siomctl(sc, *(int *)data, DMBIC);
649 1.1 nisimura break;
650 1.1 nisimura case TIOCSFLAGS: /* Instruct how serial port behaves */
651 1.1 nisimura sc->sc_flags = *(int *)data;
652 1.1 nisimura break;
653 1.1 nisimura case TIOCGFLAGS: /* Return current serial port state */
654 1.1 nisimura *(int *)data = sc->sc_flags;
655 1.1 nisimura break;
656 1.1 nisimura default:
657 1.9 atatat return EPASSTHROUGH;
658 1.1 nisimura }
659 1.1 nisimura return 0;
660 1.1 nisimura }
661 1.1 nisimura
662 1.1 nisimura /* ARSGUSED */
663 1.1 nisimura struct tty *
664 1.23 cegger siotty(dev_t dev)
665 1.1 nisimura {
666 1.32 tsutsui struct siotty_softc *sc;
667 1.35 tsutsui
668 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
669 1.1 nisimura return sc->sc_tty;
670 1.1 nisimura }
671 1.1 nisimura
672 1.1 nisimura /*-------------------- miscelleneous routine --------------------*/
673 1.1 nisimura
674 1.1 nisimura /* EXPORT */ void
675 1.23 cegger setsioreg(struct sioreg *sio, int regno, int val)
676 1.1 nisimura {
677 1.32 tsutsui
678 1.1 nisimura if (regno != 0)
679 1.1 nisimura sio->sio_cmd = regno; /* DELAY(); */
680 1.1 nisimura sio->sio_cmd = val; /* DELAY(); */
681 1.1 nisimura }
682 1.1 nisimura
683 1.37 tsutsui /* EXPORT */ uint16_t
684 1.23 cegger getsiocsr(struct sioreg *sio)
685 1.1 nisimura {
686 1.1 nisimura int val;
687 1.1 nisimura
688 1.1 nisimura val = sio->sio_stat << 8; /* DELAY(); */
689 1.1 nisimura sio->sio_cmd = 1; /* DELAY(); */
690 1.1 nisimura val |= sio->sio_stat; /* DELAY(); */
691 1.1 nisimura return val;
692 1.1 nisimura }
693 1.1 nisimura
694 1.1 nisimura /*--------------------- console interface ----------------------*/
695 1.1 nisimura
696 1.24 dsl void syscnattach(int);
697 1.24 dsl int syscngetc(dev_t);
698 1.24 dsl void syscnputc(dev_t, int);
699 1.1 nisimura
700 1.1 nisimura struct consdev syscons = {
701 1.1 nisimura NULL,
702 1.1 nisimura NULL,
703 1.1 nisimura syscngetc,
704 1.1 nisimura syscnputc,
705 1.1 nisimura nullcnpollc,
706 1.13 he NULL,
707 1.13 he NULL,
708 1.4 thorpej NULL,
709 1.1 nisimura NODEV,
710 1.1 nisimura CN_REMOTE,
711 1.1 nisimura };
712 1.1 nisimura
713 1.1 nisimura /* EXPORT */ void
714 1.25 dsl syscnattach(int channel)
715 1.1 nisimura {
716 1.1 nisimura /*
717 1.1 nisimura * Channel A is immediately initialized with 9600N1 right after cold
718 1.1 nisimura * boot/reset/poweron. ROM monitor emits one line message on CH.A.
719 1.1 nisimura */
720 1.1 nisimura struct sioreg *sio;
721 1.1 nisimura sio = (struct sioreg *)0x51000000 + channel;
722 1.1 nisimura
723 1.10 gehenna syscons.cn_dev = makedev(cdevsw_lookup_major(&siotty_cdevsw),
724 1.10 gehenna channel);
725 1.1 nisimura cn_tab = &syscons;
726 1.37 tsutsui cn_init_magic(&siotty_cnm_state);
727 1.37 tsutsui cn_set_magic("\047\001");
728 1.1 nisimura
729 1.1 nisimura setsioreg(sio, WR0, WR0_CHANRST);
730 1.1 nisimura setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
731 1.1 nisimura setsioreg(sio, WR2B, 0);
732 1.1 nisimura setsioreg(sio, WR0, ch0_regs[WR0]);
733 1.1 nisimura setsioreg(sio, WR4, ch0_regs[WR4]);
734 1.1 nisimura setsioreg(sio, WR3, ch0_regs[WR3]);
735 1.1 nisimura setsioreg(sio, WR5, ch0_regs[WR5]);
736 1.1 nisimura setsioreg(sio, WR0, ch0_regs[WR0]);
737 1.1 nisimura }
738 1.1 nisimura
739 1.1 nisimura /* EXPORT */ int
740 1.25 dsl syscngetc(dev_t dev)
741 1.1 nisimura {
742 1.1 nisimura struct sioreg *sio;
743 1.1 nisimura int s, c;
744 1.1 nisimura
745 1.1 nisimura sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
746 1.1 nisimura s = splhigh();
747 1.1 nisimura while ((getsiocsr(sio) & RR_RXRDY) == 0)
748 1.32 tsutsui continue;
749 1.1 nisimura c = sio->sio_data;
750 1.1 nisimura splx(s);
751 1.1 nisimura
752 1.1 nisimura return c;
753 1.1 nisimura }
754 1.1 nisimura
755 1.1 nisimura /* EXPORT */ void
756 1.25 dsl syscnputc(dev_t dev, int c)
757 1.1 nisimura {
758 1.1 nisimura struct sioreg *sio;
759 1.1 nisimura int s;
760 1.1 nisimura
761 1.1 nisimura sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
762 1.1 nisimura s = splhigh();
763 1.1 nisimura while ((getsiocsr(sio) & RR_TXRDY) == 0)
764 1.32 tsutsui continue;
765 1.1 nisimura sio->sio_cmd = WR0_RSTPEND;
766 1.1 nisimura sio->sio_data = c;
767 1.1 nisimura splx(s);
768 1.1 nisimura }
769