Annotation of sys/arch/luna88k/dev/siotty.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: siotty.c,v 1.5 2007/02/14 01:12:16 jsg Exp $ */
2: /* $NetBSD: siotty.c,v 1.9 2002/03/17 19:40:43 atatat Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Tohru Nishimura.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/device.h>
43: #include <sys/conf.h>
44: #include <sys/ioctl.h>
45: #include <sys/proc.h>
46: #include <sys/user.h>
47: #include <sys/tty.h>
48: #include <sys/uio.h>
49: #include <sys/fcntl.h>
50: #include <dev/cons.h>
51:
52: #include <machine/cpu.h>
53:
54: #include <luna88k/dev/sioreg.h>
55: #include <luna88k/dev/siovar.h>
56:
57: #define TIOCM_BREAK 01000 /* non standard use */
58:
59: static const u_int8_t ch0_regs[6] = {
60: WR0_RSTINT, /* reset E/S interrupt */
61: WR1_RXALLS | WR1_TXENBL, /* Rx per char, Tx */
62: 0, /* */
63: WR3_RX8BIT | WR3_RXENBL, /* Rx */
64: WR4_BAUD96 | WR4_STOP1, /* Tx/Rx */
65: WR5_TX8BIT | WR5_TXENBL | WR5_DTR | WR5_RTS, /* Tx */
66: };
67:
68: static const struct speedtab siospeedtab[] = {
69: { 2400, WR4_BAUD24, },
70: { 4800, WR4_BAUD48, },
71: { 9600, WR4_BAUD96, },
72: { -1, 0, },
73: };
74:
75: struct siotty_softc {
76: struct device sc_dev;
77: struct tty *sc_tty;
78: struct sioreg *sc_ctl;
79: u_int sc_flags;
80: u_int8_t sc_wr[6];
81: };
82:
83: cdev_decl(sio);
84: void siostart(struct tty *);
85: int sioparam(struct tty *, struct termios *);
86: void siottyintr(int);
87: int siomctl(struct siotty_softc *, int, int);
88:
89: int siotty_match(struct device *, void *, void *);
90: void siotty_attach(struct device *, struct device *, void *);
91:
92: const struct cfattach siotty_ca = {
93: sizeof(struct siotty_softc), siotty_match, siotty_attach
94: };
95:
96: struct cfdriver siotty_cd = {
97: NULL, "siotty", DV_TTY
98: };
99:
100: int
101: siotty_match(parent, cf, aux)
102: struct device *parent;
103: void *cf, *aux;
104: {
105: struct sio_attach_args *args = aux;
106:
107: if (args->channel != 0) /* XXX allow tty on Ch.B XXX */
108: return 0;
109: return 1;
110: }
111:
112: void
113: siotty_attach(parent, self, aux)
114: struct device *parent, *self;
115: void *aux;
116: {
117: struct sio_softc *scp = (void *)parent;
118: struct siotty_softc *sc = (void *)self;
119: struct sio_attach_args *args = aux;
120:
121: sc->sc_ctl = (struct sioreg *)scp->scp_ctl + args->channel;
122: bcopy(ch0_regs, sc->sc_wr, sizeof(ch0_regs));
123: scp->scp_intr[args->channel] = siottyintr;
124:
125: if (args->hwflags == 1) {
126: printf(" (console)");
127: sc->sc_flags = TIOCFLAG_SOFTCAR;
128: }
129: else {
130: setsioreg(sc->sc_ctl, WR0, WR0_CHANRST);
131: setsioreg(sc->sc_ctl, WR2A, WR2_VEC86 | WR2_INTR_1);
132: setsioreg(sc->sc_ctl, WR2B, 0);
133: setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
134: setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
135: setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
136: setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
137: setsioreg(sc->sc_ctl, WR0, sc->sc_wr[WR0]);
138: }
139: setsioreg(sc->sc_ctl, WR1, sc->sc_wr[WR1]); /* now interrupt driven */
140:
141: printf("\n");
142: }
143:
144: /*-------------------- low level routine --------------------*/
145:
146: void
147: siottyintr(chan)
148: int chan;
149: {
150: struct siotty_softc *sc;
151: struct sioreg *sio;
152: struct tty *tp;
153: unsigned int code;
154: int rr;
155:
156: if (chan >= siotty_cd.cd_ndevs)
157: return;
158: sc = siotty_cd.cd_devs[chan];
159: tp = sc->sc_tty;
160: sio = sc->sc_ctl;
161: rr = getsiocsr(sio);
162: if (rr & RR_RXRDY) {
163: do {
164: code = sio->sio_data;
165: if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
166: sio->sio_cmd = WR0_ERRRST;
167: if (sio->sio_stat & RR_FRAMING)
168: code |= TTY_FE;
169: else if (sio->sio_stat & RR_PARITY)
170: code |= TTY_PE;
171: }
172: if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
173: continue;
174: #if 0 && defined(DDB) /* ?!?! fails to resume ?!?! */
175: if ((rr & RR_BREAK) && tp->t_dev == cn_tab->cn_dev) {
176: if (db_console)
177: Debugger();
178: return;
179: }
180: #endif
181: /*
182: (*tp->t_linesw->l_rint)(code, tp);
183: */
184: (*linesw[tp->t_line].l_rint)(code, tp);
185: } while ((rr = getsiocsr(sio)) & RR_RXRDY);
186: }
187: if (rr & RR_TXRDY) {
188: sio->sio_cmd = WR0_RSTPEND;
189: if (tp != NULL) {
190: tp->t_state &= ~(TS_BUSY|TS_FLUSH);
191: /*
192: (*tp->t_linesw->l_start)(tp);
193: */
194: (*linesw[tp->t_line].l_start)(tp);
195: }
196: }
197: }
198:
199: void
200: siostart(tp)
201: struct tty *tp;
202: {
203: struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
204: int s, c;
205:
206: s = spltty();
207: if (tp->t_state & (TS_BUSY|TS_TIMEOUT|TS_TTSTOP))
208: goto out;
209: if (tp->t_outq.c_cc <= tp->t_lowat) {
210: if (tp->t_state & TS_ASLEEP) {
211: tp->t_state &= ~TS_ASLEEP;
212: wakeup((caddr_t)&tp->t_outq);
213: }
214: selwakeup(&tp->t_wsel);
215: }
216: if (tp->t_outq.c_cc == 0)
217: goto out;
218:
219: tp->t_state |= TS_BUSY;
220: while (getsiocsr(sc->sc_ctl) & RR_TXRDY) {
221: if ((c = getc(&tp->t_outq)) == -1)
222: break;
223: sc->sc_ctl->sio_data = c;
224: }
225: out:
226: splx(s);
227: }
228:
229: int
230: siostop(tp, flag)
231: struct tty *tp;
232: int flag;
233: {
234: int s;
235:
236: s = spltty();
237: if (TS_BUSY == (tp->t_state & (TS_BUSY|TS_TTSTOP))) {
238: /*
239: * Device is transmitting; must stop it.
240: */
241: tp->t_state |= TS_FLUSH;
242: }
243: splx(s);
244: return (0);
245: }
246:
247: int
248: sioparam(tp, t)
249: struct tty *tp;
250: struct termios *t;
251: {
252: struct siotty_softc *sc = siotty_cd.cd_devs[minor(tp->t_dev)];
253: int wr4, s;
254:
255: if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
256: return EINVAL;
257: wr4 = ttspeedtab(t->c_ospeed, siospeedtab);
258: if (wr4 < 0)
259: return EINVAL;
260:
261: if (sc->sc_flags & TIOCFLAG_SOFTCAR) {
262: t->c_cflag |= CLOCAL;
263: t->c_cflag &= ~HUPCL;
264: }
265: if (sc->sc_flags & TIOCFLAG_CLOCAL)
266: t->c_cflag |= CLOCAL;
267:
268: /*
269: * If there were no changes, don't do anything. This avoids dropping
270: * input and improves performance when all we did was frob things like
271: * VMIN and VTIME.
272: */
273: if (tp->t_ospeed == t->c_ospeed && tp->t_cflag == t->c_cflag)
274: return 0;
275:
276: tp->t_ispeed = t->c_ispeed;
277: tp->t_ospeed = t->c_ospeed;
278: tp->t_cflag = t->c_cflag;
279:
280: sc->sc_wr[WR3] &= 0x3f;
281: sc->sc_wr[WR5] &= 0x9f;
282: switch (tp->t_cflag & CSIZE) {
283: case CS7:
284: sc->sc_wr[WR3] |= WR3_RX7BIT; sc->sc_wr[WR5] |= WR5_TX7BIT;
285: break;
286: case CS8:
287: sc->sc_wr[WR3] |= WR3_RX8BIT; sc->sc_wr[WR5] |= WR5_TX8BIT;
288: break;
289: }
290: if (tp->t_cflag & PARENB) {
291: wr4 |= WR4_PARENAB;
292: if ((tp->t_cflag & PARODD) == 0)
293: wr4 |= WR4_EPARITY;
294: }
295: wr4 |= (tp->t_cflag & CSTOPB) ? WR4_STOP2 : WR4_STOP1;
296: sc->sc_wr[WR4] = wr4;
297:
298: s = spltty();
299: setsioreg(sc->sc_ctl, WR4, sc->sc_wr[WR4]);
300: setsioreg(sc->sc_ctl, WR3, sc->sc_wr[WR3]);
301: setsioreg(sc->sc_ctl, WR5, sc->sc_wr[WR5]);
302: splx(s);
303:
304: return 0;
305: }
306:
307: int
308: siomctl(sc, control, op)
309: struct siotty_softc *sc;
310: int control, op;
311: {
312: int val, s, wr5, rr;
313:
314: val = 0;
315: if (control & TIOCM_BREAK)
316: val |= WR5_BREAK;
317: if (control & TIOCM_DTR)
318: val |= WR5_DTR;
319: if (control & TIOCM_RTS)
320: val |= WR5_RTS;
321: s = spltty();
322: wr5 = sc->sc_wr[WR5];
323: switch (op) {
324: case DMSET:
325: wr5 &= ~(WR5_BREAK|WR5_DTR|WR5_RTS);
326: /* FALLTHROUGH */
327: case DMBIS:
328: wr5 |= val;
329: break;
330: case DMBIC:
331: wr5 &= ~val;
332: break;
333: case DMGET:
334: val = 0;
335: rr = getsiocsr(sc->sc_ctl);
336: if (wr5 & WR5_DTR)
337: val |= TIOCM_DTR;
338: if (wr5 & WR5_RTS)
339: val |= TIOCM_RTS;
340: if (rr & RR_CTS)
341: val |= TIOCM_CTS;
342: if (rr & RR_DCD)
343: val |= TIOCM_CD;
344: goto done;
345: }
346: sc->sc_wr[WR5] = wr5;
347: setsioreg(sc->sc_ctl, WR5, wr5);
348: val = 0;
349: done:
350: splx(s);
351: return val;
352: }
353:
354: /*-------------------- cdevsw[] interface --------------------*/
355:
356: int
357: sioopen(dev, flag, mode, p)
358: dev_t dev;
359: int flag, mode;
360: struct proc *p;
361: {
362: struct siotty_softc *sc;
363: struct tty *tp;
364: int error;
365:
366: if ((sc = siotty_cd.cd_devs[minor(dev)]) == NULL)
367: return ENXIO;
368: if ((tp = sc->sc_tty) == NULL) {
369: tp = sc->sc_tty = ttymalloc();
370: }
371: else if ((tp->t_state & TS_ISOPEN) && (tp->t_state & TS_XCLUDE)
372: && p->p_ucred->cr_uid != 0)
373: return EBUSY;
374:
375: tp->t_oproc = siostart;
376: tp->t_param = sioparam;
377: tp->t_hwiflow = NULL /* XXX siohwiflow XXX */;
378: tp->t_dev = dev;
379: if ((tp->t_state & TS_ISOPEN) == 0) {
380: struct termios t;
381:
382: t.c_ispeed = t.c_ospeed = TTYDEF_SPEED;
383: t.c_cflag = TTYDEF_CFLAG;
384: tp->t_ospeed = 0; /* force register update */
385: (void)sioparam(tp, &t);
386: tp->t_iflag = TTYDEF_IFLAG;
387: tp->t_oflag = TTYDEF_OFLAG;
388: tp->t_lflag = TTYDEF_LFLAG;
389: ttychars(tp);
390: ttsetwater(tp);
391: /* raise RTS and DTR here; but, DTR lead is not wired */
392: /* then check DCD condition; but, DCD lead is not wired */
393: tp->t_state |= TS_CARR_ON; /* assume detected all the time */
394: #if 0
395: if ((sc->sc_flags & TIOCFLAG_SOFTCAR)
396: || (tp->t_cflag & MDMBUF)
397: || (getsiocsr(sc->sc_ctl) & RR_DCD))
398: tp->t_state |= TS_CARR_ON;
399: else
400: tp->t_state &= ~TS_CARR_ON;
401: #endif
402: }
403:
404: error = ttyopen(dev, tp);
405: if (error > 0)
406: return error;
407: /*
408: return (*tp->t_linesw->l_open)(dev, tp);
409: */
410: return (*linesw[tp->t_line].l_open)(dev, tp);
411: }
412:
413: int
414: sioclose(dev, flag, mode, p)
415: dev_t dev;
416: int flag, mode;
417: struct proc *p;
418: {
419: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
420: struct tty *tp = sc->sc_tty;
421: int s;
422:
423: /*
424: (*tp->t_linesw->l_close)(tp, flag);
425: */
426: (*linesw[tp->t_line].l_close)(tp, flag);
427:
428: s = spltty();
429: siomctl(sc, TIOCM_BREAK, DMBIC);
430: #if 0 /* because unable to feed DTR signal */
431: if ((tp->t_cflag & HUPCL)
432: || tp->t_wopen || (tp->t_state & TS_ISOPEN) == 0) {
433: siomctl(sc, TIOCM_DTR, DMBIC);
434: /* Yield CPU time to others for 1 second, then ... */
435: siomctl(sc, TIOCM_DTR, DMBIS);
436: }
437: #endif
438: splx(s);
439: return ttyclose(tp);
440: }
441:
442: int
443: sioread(dev, uio, flag)
444: dev_t dev;
445: struct uio *uio;
446: int flag;
447: {
448: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
449: struct tty *tp = sc->sc_tty;
450:
451: /*
452: return (*tp->t_linesw->l_read)(tp, uio, flag);
453: */
454: return (*linesw[tp->t_line].l_read)(tp, uio, flag);
455: }
456:
457: int
458: siowrite(dev, uio, flag)
459: dev_t dev;
460: struct uio *uio;
461: int flag;
462: {
463: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
464: struct tty *tp = sc->sc_tty;
465:
466: /*
467: return (*tp->t_linesw->l_write)(tp, uio, flag);
468: */
469: return (*linesw[tp->t_line].l_write)(tp, uio, flag);
470: }
471:
472: #if 0
473: int
474: sioselect(dev, events, p)
475: dev_t dev;
476: int events;
477: struct proc *p;
478: {
479: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
480: struct tty *tp = sc->sc_tty;
481:
482: /*
483: return ((*tp->t_linesw->l_poll)(tp, events, p));
484: */
485: return ((*linesw[tp->t_line].l_select)(tp, events, p));
486:
487: }
488: #endif
489:
490: int
491: sioioctl(dev, cmd, data, flag, p)
492: dev_t dev;
493: u_long cmd;
494: caddr_t data;
495: int flag;
496: struct proc *p;
497: {
498: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
499: struct tty *tp = sc->sc_tty;
500: int error;
501:
502: /*
503: error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
504: */
505: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
506: if (error >= 0)
507: return error;
508:
509: error = ttioctl(tp, cmd, data, flag, p);
510: if (error >= 0)
511: return error;
512:
513: /* the last resort for TIOC ioctl tranversing */
514: switch (cmd) {
515: case TIOCSBRK: /* Set the hardware into BREAK condition */
516: siomctl(sc, TIOCM_BREAK, DMBIS);
517: break;
518: case TIOCCBRK: /* Clear the hardware BREAK condition */
519: siomctl(sc, TIOCM_BREAK, DMBIC);
520: break;
521: case TIOCSDTR: /* Assert DTR signal */
522: siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIS);
523: break;
524: case TIOCCDTR: /* Clear DTR signal */
525: siomctl(sc, TIOCM_DTR|TIOCM_RTS, DMBIC);
526: break;
527: case TIOCMSET: /* Set modem state replacing current one */
528: siomctl(sc, *(int *)data, DMSET);
529: break;
530: case TIOCMGET: /* Return current modem state */
531: *(int *)data = siomctl(sc, 0, DMGET);
532: break;
533: case TIOCMBIS: /* Set individual bits of modem state */
534: siomctl(sc, *(int *)data, DMBIS);
535: break;
536: case TIOCMBIC: /* Clear individual bits of modem state */
537: siomctl(sc, *(int *)data, DMBIC);
538: break;
539: case TIOCSFLAGS: /* Instruct how serial port behaves */
540: error = suser(p, 0);
541: if (error != 0)
542: return EPERM;
543: sc->sc_flags = *(int *)data;
544: break;
545: case TIOCGFLAGS: /* Return current serial port state */
546: *(int *)data = sc->sc_flags;
547: break;
548: default:
549: /*
550: return EPASSTHROUGH;
551: */
552: return ENOTTY;
553: }
554: return 0;
555: }
556:
557: /* ARSGUSED */
558: struct tty *
559: siotty(dev)
560: dev_t dev;
561: {
562: struct siotty_softc *sc = siotty_cd.cd_devs[minor(dev)];
563:
564: return sc->sc_tty;
565: }
566:
567: /*-------------------- miscellaneous routines --------------------*/
568:
569: /* EXPORT */ void
570: setsioreg(sio, regno, val)
571: struct sioreg *sio;
572: int regno, val;
573: {
574: if (regno != 0)
575: sio->sio_cmd = regno; /* DELAY(); */
576: sio->sio_cmd = val; /* DELAY(); */
577: }
578:
579: /* EXPORT */ int
580: getsiocsr(sio)
581: struct sioreg *sio;
582: {
583: int val;
584:
585: val = sio->sio_stat << 8; /* DELAY(); */
586: sio->sio_cmd = 1; /* DELAY(); */
587: val |= sio->sio_stat; /* DELAY(); */
588: return val;
589: }
590:
591: /*--------------------- console interface ----------------------*/
592:
593: void syscnattach(int);
594: int syscngetc(dev_t);
595: void syscnputc(dev_t, int);
596:
597: struct consdev syscons = {
598: NULL,
599: NULL,
600: syscngetc,
601: syscnputc,
602: nullcnpollc,
603: NULL,
604: NODEV,
605: CN_REMOTE,
606: };
607:
608: /* EXPORT */ void
609: syscnattach(channel)
610: int channel;
611: {
612: /*
613: * Channel A is immediately initialized with 9600N1 right after cold
614: * boot/reset/poweron. ROM monitor emits one line message on CH.A.
615: */
616: struct sioreg *sio;
617: sio = (struct sioreg *)0x51000000 + channel;
618:
619: /* syscons.cn_dev = makedev(7, channel); */
620: syscons.cn_dev = makedev(12, channel);
621: cn_tab = &syscons;
622:
623: #if 0
624: setsioreg(sio, WR0, WR0_CHANRST);
625: setsioreg(sio, WR2A, WR2_VEC86 | WR2_INTR_1);
626: setsioreg(sio, WR2B, 0);
627: setsioreg(sio, WR0, ch0_regs[WR0]);
628: setsioreg(sio, WR4, ch0_regs[WR4]);
629: setsioreg(sio, WR3, ch0_regs[WR3]);
630: setsioreg(sio, WR5, ch0_regs[WR5]);
631: setsioreg(sio, WR0, ch0_regs[WR0]);
632: #endif
633: }
634:
635: /* EXPORT */ int
636: syscngetc(dev)
637: dev_t dev;
638: {
639: struct sioreg *sio;
640: int s, c;
641:
642: sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
643: s = splhigh();
644: while ((getsiocsr(sio) & RR_RXRDY) == 0)
645: ;
646: c = sio->sio_data;
647: splx(s);
648:
649: return c;
650: }
651:
652: /* EXPORT */ void
653: syscnputc(dev, c)
654: dev_t dev;
655: int c;
656: {
657: struct sioreg *sio;
658: int s;
659:
660: sio = (struct sioreg *)0x51000000 + ((int)dev & 0x1);
661: s = splhigh();
662: while ((getsiocsr(sio) & RR_TXRDY) == 0)
663: ;
664: sio->sio_cmd = WR0_RSTPEND;
665: sio->sio_data = c;
666: splx(s);
667: }
CVSweb