siotty.c revision 1.36 1 1.36 tsutsui /* $NetBSD: siotty.c,v 1.36 2013/09/23 17:27:09 tsutsui 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.36 tsutsui __KERNEL_RCSID(0, "$NetBSD: siotty.c,v 1.36 2013/09/23 17:27:09 tsutsui 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.1 nisimura
51 1.1 nisimura #include <machine/cpu.h>
52 1.1 nisimura
53 1.1 nisimura #include <luna68k/dev/sioreg.h>
54 1.1 nisimura #include <luna68k/dev/siovar.h>
55 1.1 nisimura
56 1.31 tsutsui #include "ioconf.h"
57 1.31 tsutsui
58 1.1 nisimura #define TIOCM_BREAK 01000 /* non standard use */
59 1.1 nisimura
60 1.32 tsutsui static const uint8_t ch0_regs[6] = {
61 1.1 nisimura WR0_RSTINT, /* reset E/S interrupt */
62 1.35 tsutsui WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
63 1.1 nisimura 0, /* */
64 1.1 nisimura WR3_RX8BIT | WR3_RXENBL, /* Rx */
65 1.1 nisimura WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
66 1.1 nisimura WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
67 1.1 nisimura };
68 1.1 nisimura
69 1.14 matt static const struct speedtab siospeedtab[] = {
70 1.1 nisimura { 2400, WR4_BAUD24, },
71 1.1 nisimura { 4800, WR4_BAUD48, },
72 1.1 nisimura { 9600, WR4_BAUD96, },
73 1.1 nisimura { -1, 0, },
74 1.1 nisimura };
75 1.1 nisimura
76 1.1 nisimura struct siotty_softc {
77 1.31 tsutsui device_t sc_dev;
78 1.1 nisimura struct tty *sc_tty;
79 1.1 nisimura struct sioreg *sc_ctl;
80 1.35 tsutsui u_int sc_flags;
81 1.32 tsutsui uint8_t sc_wr[6];
82 1.1 nisimura };
83 1.1 nisimura
84 1.1 nisimura #include "siotty.h"
85 1.24 dsl static void siostart(struct tty *);
86 1.24 dsl static int sioparam(struct tty *, struct termios *);
87 1.24 dsl static void siottyintr(int);
88 1.24 dsl static int siomctl(struct siotty_softc *, int, int);
89 1.1 nisimura
90 1.31 tsutsui static int siotty_match(device_t, cfdata_t, void *);
91 1.31 tsutsui static void siotty_attach(device_t, device_t, void *);
92 1.1 nisimura
93 1.31 tsutsui CFATTACH_DECL_NEW(siotty, sizeof(struct siotty_softc),
94 1.11 thorpej siotty_match, siotty_attach, NULL, NULL);
95 1.1 nisimura
96 1.10 gehenna dev_type_open(sioopen);
97 1.10 gehenna dev_type_close(sioclose);
98 1.10 gehenna dev_type_read(sioread);
99 1.10 gehenna dev_type_write(siowrite);
100 1.10 gehenna dev_type_ioctl(sioioctl);
101 1.10 gehenna dev_type_stop(siostop);
102 1.10 gehenna dev_type_tty(siotty);
103 1.10 gehenna dev_type_poll(siopoll);
104 1.10 gehenna
105 1.10 gehenna const struct cdevsw siotty_cdevsw = {
106 1.10 gehenna sioopen, sioclose, sioread, siowrite, sioioctl,
107 1.12 jdolecek siostop, siotty, siopoll, nommap, ttykqfilter, D_TTY
108 1.10 gehenna };
109 1.10 gehenna
110 1.35 tsutsui static int
111 1.31 tsutsui siotty_match(device_t parent, cfdata_t cf, void *aux)
112 1.1 nisimura {
113 1.1 nisimura struct sio_attach_args *args = aux;
114 1.1 nisimura
115 1.1 nisimura if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
116 1.1 nisimura return 0;
117 1.1 nisimura return 1;
118 1.1 nisimura }
119 1.1 nisimura
120 1.35 tsutsui static void
121 1.34 tsutsui siotty_attach(device_t parent, device_t self, void *aux)
122 1.1 nisimura {
123 1.31 tsutsui struct sio_softc *scp = device_private(parent);
124 1.31 tsutsui struct siotty_softc *sc = device_private(self);
125 1.1 nisimura struct sio_attach_args *args = aux;
126 1.1 nisimura
127 1.31 tsutsui sc->sc_dev = self;
128 1.1 nisimura sc->sc_ctl = (struct sioreg *)scp->scp_ctl + args->channel;
129 1.28 cegger memcpy(sc->sc_wr, ch0_regs, sizeof(ch0_regs));
130 1.1 nisimura scp->scp_intr[args->channel] = siottyintr;
131 1.1 nisimura
132 1.1 nisimura if (args->hwflags == 1) {
133 1.31 tsutsui aprint_normal(" (console)");
134 1.1 nisimura sc->sc_flags = TIOCFLAG_SOFTCAR;
135 1.32 tsutsui } else {
136 1.1 nisimura setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
137 1.1 nisimura setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
138 1.1 nisimura setsioreg(sc->sc_ctl, WR2B, 0);
139 1.1 nisimura setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
140 1.1 nisimura setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
141 1.1 nisimura setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
142 1.1 nisimura setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
143 1.1 nisimura setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
144 1.1 nisimura }
145 1.1 nisimura setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
146 1.1 nisimura
147 1.31 tsutsui aprint_normal("\n");
148 1.1 nisimura }
149 1.1 nisimura
150 1.1 nisimura /*-------------------- low level routine --------------------*/
151 1.1 nisimura
152 1.1 nisimura static void
153 1.23 cegger siottyintr(int chan)
154 1.1 nisimura {
155 1.1 nisimura struct siotty_softc *sc;
156 1.1 nisimura struct sioreg *sio;
157 1.1 nisimura struct tty *tp;
158 1.1 nisimura unsigned int code;
159 1.1 nisimura int rr;
160 1.1 nisimura
161 1.23 cegger sc = device_lookup_private(&siotty_cd, chan);
162 1.23 cegger if (sc == NULL)
163 1.1 nisimura return;
164 1.23 cegger
165 1.1 nisimura tp = sc->sc_tty;
166 1.1 nisimura sio = sc->sc_ctl;
167 1.1 nisimura rr = getsiocsr(sio);
168 1.1 nisimura if (rr & RR_RXRDY) {
169 1.1 nisimura do {
170 1.1 nisimura code = sio->sio_data;
171 1.1 nisimura if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
172 1.1 nisimura sio->sio_cmd = WR0_ERRRST;
173 1.1 nisimura if (sio->sio_stat & RR_FRAMING)
174 1.1 nisimura code |= TTY_FE;
175 1.1 nisimura else if (sio->sio_stat & RR_PARITY)
176 1.1 nisimura code |= TTY_PE;
177 1.1 nisimura }
178 1.1 nisimura if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
179 1.1 nisimura continue;
180 1.3 nisimura #if 0 && defined(DDB) /* ?!?! fails to resume ?!?! */
181 1.3 nisimura if ((rr & RR_BREAK) && tp->t_dev == cn_tab->cn_dev) {
182 1.2 nisimura cpu_Debugger();
183 1.3 nisimura return;
184 1.3 nisimura }
185 1.2 nisimura #endif
186 1.5 eeh (*tp->t_linesw->l_rint)(code, tp);
187 1.1 nisimura } while ((rr = getsiocsr(sio)) & RR_RXRDY);
188 1.1 nisimura }
189 1.1 nisimura if (rr & RR_TXRDY) {
190 1.1 nisimura sio->sio_cmd = WR0_RSTPEND;
191 1.1 nisimura if (tp != NULL) {
192 1.1 nisimura tp->t_state &= ~(TS_BUSY|TS_FLUSH);
193 1.7 enami (*tp->t_linesw->l_start)(tp);
194 1.1 nisimura }
195 1.1 nisimura }
196 1.1 nisimura }
197 1.1 nisimura
198 1.1 nisimura static void
199 1.23 cegger siostart(struct tty *tp)
200 1.1 nisimura {
201 1.32 tsutsui struct siotty_softc *sc;
202 1.1 nisimura int s, c;
203 1.35 tsutsui
204 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
205 1.33 tsutsui s = splserial();
206 1.1 nisimura if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
207 1.1 nisimura goto out;
208 1.21 ad if (!ttypull(tp))
209 1.1 nisimura goto out;
210 1.1 nisimura tp->t_state |= TS_BUSY;
211 1.1 nisimura while (getsiocsr(sc->sc_ctl) & RR_TXRDY) {
212 1.1 nisimura if ((c = getc(&tp->t_outq)) == -1)
213 1.1 nisimura break;
214 1.1 nisimura sc->sc_ctl->sio_data = c;
215 1.1 nisimura }
216 1.1 nisimura out:
217 1.1 nisimura splx(s);
218 1.1 nisimura }
219 1.1 nisimura
220 1.1 nisimura void
221 1.25 dsl siostop(struct tty *tp, int flag)
222 1.1 nisimura {
223 1.1 nisimura int s;
224 1.1 nisimura
225 1.35 tsutsui s = splserial();
226 1.35 tsutsui if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
227 1.35 tsutsui /*
228 1.35 tsutsui * Device is transmitting; must stop it.
229 1.35 tsutsui */
230 1.1 nisimura tp->t_state |= TS_FLUSH;
231 1.35 tsutsui }
232 1.35 tsutsui splx(s);
233 1.1 nisimura }
234 1.1 nisimura
235 1.1 nisimura static int
236 1.23 cegger sioparam(struct tty *tp, struct termios *t)
237 1.1 nisimura {
238 1.32 tsutsui struct siotty_softc *sc;
239 1.1 nisimura int wr4, s;
240 1.1 nisimura
241 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(tp->t_dev));
242 1.1 nisimura if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
243 1.1 nisimura return EINVAL;
244 1.1 nisimura wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
245 1.1 nisimura if (wr4 < 0)
246 1.1 nisimura return EINVAL;
247 1.1 nisimura
248 1.1 nisimura if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
249 1.1 nisimura t->c_cflag |= CLOCAL;
250 1.1 nisimura t->c_cflag &= ~HUPCL;
251 1.1 nisimura }
252 1.1 nisimura if (sc->sc_flags & TIOCFLAG_CLOCAL)
253 1.1 nisimura t->c_cflag |= CLOCAL;
254 1.1 nisimura
255 1.1 nisimura /*
256 1.1 nisimura * If there were no changes, don't do anything. This avoids dropping
257 1.1 nisimura * input and improves performance when all we did was frob things like
258 1.1 nisimura * VMIN and VTIME.
259 1.1 nisimura */
260 1.1 nisimura if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
261 1.1 nisimura return 0;
262 1.1 nisimura
263 1.1 nisimura tp->t_ispeed = t->c_ispeed;
264 1.1 nisimura tp->t_ospeed = t->c_ospeed;
265 1.1 nisimura tp->t_cflag = t->c_cflag;
266 1.1 nisimura
267 1.1 nisimura sc->sc_wr[WR3] &= 0x3f;
268 1.1 nisimura sc->sc_wr[WR5] &= 0x9f;
269 1.1 nisimura switch (tp->t_cflag & CSIZE) {
270 1.1 nisimura case CS7:
271 1.1 nisimura sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
272 1.1 nisimura break;
273 1.1 nisimura case CS8:
274 1.1 nisimura sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
275 1.1 nisimura break;
276 1.1 nisimura }
277 1.1 nisimura if (tp->t_cflag & PARENB) {
278 1.1 nisimura wr4 |= WR4_PARENAB;
279 1.1 nisimura if ((tp->t_cflag & PARODD) == 0)
280 1.1 nisimura wr4 |= WR4_EPARITY;
281 1.1 nisimura }
282 1.36 tsutsui wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
283 1.1 nisimura sc->sc_wr[WR4] = wr4;
284 1.1 nisimura
285 1.33 tsutsui s = splserial();
286 1.1 nisimura setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
287 1.1 nisimura setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
288 1.1 nisimura setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
289 1.1 nisimura splx(s);
290 1.1 nisimura
291 1.1 nisimura return 0;
292 1.1 nisimura }
293 1.1 nisimura
294 1.1 nisimura static int
295 1.26 dsl siomctl(struct siotty_softc *sc, int control, int op)
296 1.1 nisimura {
297 1.1 nisimura int val, s, wr5, rr;
298 1.1 nisimura
299 1.1 nisimura val = 0;
300 1.1 nisimura if (control & TIOCM_BREAK)
301 1.1 nisimura val |= WR5_BREAK;
302 1.1 nisimura if (control & TIOCM_DTR)
303 1.1 nisimura val |= WR5_DTR;
304 1.1 nisimura if (control & TIOCM_RTS)
305 1.1 nisimura val |= WR5_RTS;
306 1.33 tsutsui s = splserial();
307 1.1 nisimura wr5 = sc->sc_wr[WR5];
308 1.1 nisimura switch (op) {
309 1.1 nisimura case DMSET:
310 1.1 nisimura wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
311 1.1 nisimura /* FALLTHRU */
312 1.1 nisimura case DMBIS:
313 1.1 nisimura wr5 |= val;
314 1.1 nisimura break;
315 1.1 nisimura case DMBIC:
316 1.1 nisimura wr5 &= ~val;
317 1.1 nisimura break;
318 1.1 nisimura case DMGET:
319 1.1 nisimura val = 0;
320 1.1 nisimura rr = getsiocsr(sc->sc_ctl);
321 1.1 nisimura if (wr5 & WR5_DTR)
322 1.1 nisimura val |= TIOCM_DTR;
323 1.1 nisimura if (wr5 & WR5_RTS)
324 1.1 nisimura val |= TIOCM_RTS;
325 1.1 nisimura if (rr & RR_CTS)
326 1.1 nisimura val |= TIOCM_CTS;
327 1.1 nisimura if (rr & RR_DCD)
328 1.1 nisimura val |= TIOCM_CD;
329 1.1 nisimura goto done;
330 1.1 nisimura }
331 1.1 nisimura sc->sc_wr[WR5] = wr5;
332 1.1 nisimura setsioreg(sc->sc_ctl, WR5, wr5);
333 1.1 nisimura val = 0;
334 1.35 tsutsui done:
335 1.1 nisimura splx(s);
336 1.1 nisimura return val;
337 1.1 nisimura }
338 1.1 nisimura
339 1.1 nisimura /*-------------------- cdevsw[] interface --------------------*/
340 1.1 nisimura
341 1.1 nisimura int
342 1.23 cegger sioopen(dev_t dev, int flag, int mode, struct lwp *l)
343 1.1 nisimura {
344 1.1 nisimura struct siotty_softc *sc;
345 1.1 nisimura struct tty *tp;
346 1.1 nisimura int error;
347 1.1 nisimura
348 1.23 cegger sc = device_lookup_private(&siotty_cd, minor(dev));
349 1.23 cegger if (sc == NULL)
350 1.1 nisimura return ENXIO;
351 1.1 nisimura if ((tp = sc->sc_tty) == NULL) {
352 1.30 rmind tp = sc->sc_tty = tty_alloc();
353 1.1 nisimura tty_attach(tp);
354 1.30 rmind }
355 1.1 nisimura
356 1.1 nisimura tp->t_oproc = siostart;
357 1.1 nisimura tp->t_param = sioparam;
358 1.1 nisimura tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
359 1.1 nisimura tp->t_dev = dev;
360 1.19 elad
361 1.19 elad if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
362 1.32 tsutsui return EBUSY;
363 1.19 elad
364 1.1 nisimura if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
365 1.1 nisimura struct termios t;
366 1.1 nisimura
367 1.1 nisimura t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
368 1.1 nisimura t.c_cflag = TTYDEF_CFLAG;
369 1.1 nisimura tp->t_ospeed = 0; /* force register update */
370 1.1 nisimura (void)sioparam(tp, &t);
371 1.1 nisimura tp->t_iflag = TTYDEF_IFLAG;
372 1.1 nisimura tp->t_oflag = TTYDEF_OFLAG;
373 1.1 nisimura tp->t_lflag = TTYDEF_LFLAG;
374 1.1 nisimura ttychars(tp);
375 1.1 nisimura ttsetwater(tp);
376 1.1 nisimura /* raise RTS and DTR here; but, DTR lead is not wired */
377 1.1 nisimura /* then check DCD condition; but, DCD lead is not wired */
378 1.1 nisimura tp->t_state |= TS_CARR_ON; /* assume detected all the time */
379 1.1 nisimura #if 0
380 1.1 nisimura if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
381 1.1 nisimura || (tp->t_cflag & MDMBUF)
382 1.1 nisimura || (getsiocsr(sc->sc_ctl) & RR_DCD))
383 1.1 nisimura tp->t_state |= TS_CARR_ON;
384 1.1 nisimura else
385 1.1 nisimura tp->t_state &= ~TS_CARR_ON;
386 1.1 nisimura #endif
387 1.1 nisimura }
388 1.1 nisimura
389 1.1 nisimura error = ttyopen(tp, 0, (flag & O_NONBLOCK));
390 1.1 nisimura if (error > 0)
391 1.1 nisimura return error;
392 1.5 eeh return (*tp->t_linesw->l_open)(dev, tp);
393 1.1 nisimura }
394 1.35 tsutsui
395 1.1 nisimura int
396 1.23 cegger sioclose(dev_t dev, int flag, int mode, struct lwp *l)
397 1.1 nisimura {
398 1.23 cegger struct siotty_softc *sc = device_lookup_private(&siotty_cd,minor(dev));
399 1.1 nisimura struct tty *tp = sc->sc_tty;
400 1.1 nisimura int s;
401 1.1 nisimura
402 1.5 eeh (*tp->t_linesw->l_close)(tp, flag);
403 1.1 nisimura
404 1.33 tsutsui s = splserial();
405 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIC);
406 1.1 nisimura #if 0 /* because unable to feed DTR signal */
407 1.1 nisimura if ((tp->t_cflag & HUPCL)
408 1.1 nisimura || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
409 1.1 nisimura siomctl(sc, TIOCM_DTR, DMBIC);
410 1.1 nisimura /* Yield CPU time to others for 1 second, then ... */
411 1.1 nisimura siomctl(sc, TIOCM_DTR, DMBIS);
412 1.1 nisimura }
413 1.1 nisimura #endif
414 1.1 nisimura splx(s);
415 1.1 nisimura return ttyclose(tp);
416 1.1 nisimura }
417 1.35 tsutsui
418 1.1 nisimura int
419 1.23 cegger sioread(dev_t dev, struct uio *uio, int flag)
420 1.1 nisimura {
421 1.32 tsutsui struct siotty_softc *sc;
422 1.32 tsutsui struct tty *tp;
423 1.35 tsutsui
424 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
425 1.32 tsutsui tp = sc->sc_tty;
426 1.5 eeh return (*tp->t_linesw->l_read)(tp, uio, flag);
427 1.1 nisimura }
428 1.35 tsutsui
429 1.1 nisimura int
430 1.23 cegger siowrite(dev_t dev, struct uio *uio, int flag)
431 1.1 nisimura {
432 1.32 tsutsui struct siotty_softc *sc;
433 1.32 tsutsui struct tty *tp;
434 1.35 tsutsui
435 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
436 1.32 tsutsui tp = sc->sc_tty;
437 1.5 eeh return (*tp->t_linesw->l_write)(tp, uio, flag);
438 1.8 scw }
439 1.8 scw
440 1.8 scw int
441 1.23 cegger siopoll(dev_t dev, int events, struct lwp *l)
442 1.8 scw {
443 1.32 tsutsui struct siotty_softc *sc;
444 1.32 tsutsui struct tty *tp;
445 1.35 tsutsui
446 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
447 1.32 tsutsui tp = sc->sc_tty;
448 1.16 christos return ((*tp->t_linesw->l_poll)(tp, events, l));
449 1.1 nisimura }
450 1.1 nisimura
451 1.1 nisimura int
452 1.23 cegger sioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
453 1.1 nisimura {
454 1.32 tsutsui struct siotty_softc *sc;
455 1.32 tsutsui struct tty *tp;
456 1.1 nisimura int error;
457 1.1 nisimura
458 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
459 1.32 tsutsui tp = sc->sc_tty;
460 1.16 christos error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
461 1.9 atatat if (error != EPASSTHROUGH)
462 1.1 nisimura return error;
463 1.9 atatat
464 1.16 christos error = ttioctl(tp, cmd, data, flag, l);
465 1.9 atatat if (error != EPASSTHROUGH)
466 1.1 nisimura return error;
467 1.1 nisimura
468 1.1 nisimura /* the last resort for TIOC ioctl tranversing */
469 1.1 nisimura switch (cmd) {
470 1.1 nisimura case TIOCSBRK: /* Set the hardware into BREAK condition */
471 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIS);
472 1.1 nisimura break;
473 1.1 nisimura case TIOCCBRK: /* Clear the hardware BREAK condition */
474 1.1 nisimura siomctl(sc, TIOCM_BREAK, DMBIC);
475 1.1 nisimura break;
476 1.1 nisimura case TIOCSDTR: /* Assert DTR signal */
477 1.1 nisimura siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
478 1.1 nisimura break;
479 1.1 nisimura case TIOCCDTR: /* Clear DTR signal */
480 1.1 nisimura siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
481 1.1 nisimura break;
482 1.1 nisimura case TIOCMSET: /* Set modem state replacing current one */
483 1.1 nisimura siomctl(sc, *(int *)data, DMSET);
484 1.1 nisimura break;
485 1.1 nisimura case TIOCMGET: /* Return current modem state */
486 1.1 nisimura *(int *)data = siomctl(sc, 0, DMGET);
487 1.1 nisimura break;
488 1.1 nisimura case TIOCMBIS: /* Set individual bits of modem state */
489 1.1 nisimura siomctl(sc, *(int *)data, DMBIS);
490 1.1 nisimura break;
491 1.1 nisimura case TIOCMBIC: /* Clear individual bits of modem state */
492 1.1 nisimura siomctl(sc, *(int *)data, DMBIC);
493 1.1 nisimura break;
494 1.1 nisimura case TIOCSFLAGS: /* Instruct how serial port behaves */
495 1.1 nisimura sc->sc_flags = *(int *)data;
496 1.1 nisimura break;
497 1.1 nisimura case TIOCGFLAGS: /* Return current serial port state */
498 1.1 nisimura *(int *)data = sc->sc_flags;
499 1.1 nisimura break;
500 1.1 nisimura default:
501 1.9 atatat return EPASSTHROUGH;
502 1.1 nisimura }
503 1.1 nisimura return 0;
504 1.1 nisimura }
505 1.1 nisimura
506 1.1 nisimura /* ARSGUSED */
507 1.1 nisimura struct tty *
508 1.23 cegger siotty(dev_t dev)
509 1.1 nisimura {
510 1.32 tsutsui struct siotty_softc *sc;
511 1.35 tsutsui
512 1.32 tsutsui sc = device_lookup_private(&siotty_cd, minor(dev));
513 1.1 nisimura return sc->sc_tty;
514 1.1 nisimura }
515 1.1 nisimura
516 1.1 nisimura /*-------------------- miscelleneous routine --------------------*/
517 1.1 nisimura
518 1.1 nisimura /* EXPORT */ void
519 1.23 cegger setsioreg(struct sioreg *sio, int regno, int val)
520 1.1 nisimura {
521 1.32 tsutsui
522 1.1 nisimura if (regno != 0)
523 1.1 nisimura sio->sio_cmd = regno; /* DELAY(); */
524 1.1 nisimura sio->sio_cmd = val; /* DELAY(); */
525 1.1 nisimura }
526 1.1 nisimura
527 1.1 nisimura /* EXPORT */ int
528 1.23 cegger getsiocsr(struct sioreg *sio)
529 1.1 nisimura {
530 1.1 nisimura int val;
531 1.1 nisimura
532 1.1 nisimura val = sio->sio_stat << 8; /* DELAY(); */
533 1.1 nisimura sio->sio_cmd = 1; /* DELAY(); */
534 1.1 nisimura val |= sio->sio_stat; /* DELAY(); */
535 1.1 nisimura return val;
536 1.1 nisimura }
537 1.1 nisimura
538 1.1 nisimura /*--------------------- console interface ----------------------*/
539 1.1 nisimura
540 1.24 dsl void syscnattach(int);
541 1.24 dsl int syscngetc(dev_t);
542 1.24 dsl void syscnputc(dev_t, int);
543 1.1 nisimura
544 1.1 nisimura struct consdev syscons = {
545 1.1 nisimura NULL,
546 1.1 nisimura NULL,
547 1.1 nisimura syscngetc,
548 1.1 nisimura syscnputc,
549 1.1 nisimura nullcnpollc,
550 1.13 he NULL,
551 1.13 he NULL,
552 1.4 thorpej NULL,
553 1.1 nisimura NODEV,
554 1.1 nisimura CN_REMOTE,
555 1.1 nisimura };
556 1.1 nisimura
557 1.1 nisimura /* EXPORT */ void
558 1.25 dsl syscnattach(int channel)
559 1.1 nisimura {
560 1.1 nisimura /*
561 1.1 nisimura * Channel A is immediately initialized with 9600N1 right after cold
562 1.1 nisimura * boot/reset/poweron. ROM monitor emits one line message on CH.A.
563 1.1 nisimura */
564 1.1 nisimura struct sioreg *sio;
565 1.1 nisimura sio = (struct sioreg *)0x51000000 + channel;
566 1.1 nisimura
567 1.10 gehenna syscons.cn_dev = makedev(cdevsw_lookup_major(&siotty_cdevsw),
568 1.10 gehenna channel);
569 1.1 nisimura cn_tab = &syscons;
570 1.1 nisimura
571 1.1 nisimura setsioreg(sio, WR0, WR0_CHANRST);
572 1.1 nisimura setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
573 1.1 nisimura setsioreg(sio, WR2B, 0);
574 1.1 nisimura setsioreg(sio, WR0, ch0_regs[WR0]);
575 1.1 nisimura setsioreg(sio, WR4, ch0_regs[WR4]);
576 1.1 nisimura setsioreg(sio, WR3, ch0_regs[WR3]);
577 1.1 nisimura setsioreg(sio, WR5, ch0_regs[WR5]);
578 1.1 nisimura setsioreg(sio, WR0, ch0_regs[WR0]);
579 1.1 nisimura }
580 1.1 nisimura
581 1.1 nisimura /* EXPORT */ int
582 1.25 dsl syscngetc(dev_t dev)
583 1.1 nisimura {
584 1.1 nisimura struct sioreg *sio;
585 1.1 nisimura int s, c;
586 1.1 nisimura
587 1.1 nisimura sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
588 1.1 nisimura s = splhigh();
589 1.1 nisimura while ((getsiocsr(sio) & RR_RXRDY) == 0)
590 1.32 tsutsui continue;
591 1.1 nisimura c = sio->sio_data;
592 1.1 nisimura splx(s);
593 1.1 nisimura
594 1.1 nisimura return c;
595 1.1 nisimura }
596 1.1 nisimura
597 1.1 nisimura /* EXPORT */ void
598 1.25 dsl syscnputc(dev_t dev, int c)
599 1.1 nisimura {
600 1.1 nisimura struct sioreg *sio;
601 1.1 nisimura int s;
602 1.1 nisimura
603 1.1 nisimura sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
604 1.1 nisimura s = splhigh();
605 1.1 nisimura while ((getsiocsr(sio) & RR_TXRDY) == 0)
606 1.32 tsutsui continue;
607 1.1 nisimura sio->sio_cmd = WR0_RSTPEND;
608 1.1 nisimura sio->sio_data = c;
609 1.1 nisimura splx(s);
610 1.1 nisimura }
611