Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / amiga / dev / ser.c
blob0ec53e3d12337730ef3d55b9e5f2801a07cd59f0
1 /* $NetBSD: ser.c,v 1.77 2007/11/19 18:51:37 ad Exp $ */
3 /*
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * @(#)ser.c 7.12 (Berkeley) 6/27/91
34 * XXX This file needs major cleanup it will never service more than one
35 * XXX unit.
38 #include "opt_amigacons.h"
39 #include "opt_ddb.h"
40 #include "opt_kgdb.h"
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: ser.c,v 1.77 2007/11/19 18:51:37 ad Exp $");
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/ioctl.h>
48 #include <sys/device.h>
49 #include <sys/tty.h>
50 #include <sys/proc.h>
51 #include <sys/file.h>
52 #include <sys/malloc.h>
53 #include <sys/uio.h>
54 #include <sys/kernel.h>
55 #include <sys/syslog.h>
56 #include <sys/queue.h>
57 #include <sys/conf.h>
58 #include <sys/kauth.h>
59 #include <machine/cpu.h>
60 #include <amiga/amiga/device.h>
61 #include <amiga/dev/serreg.h>
62 #include <amiga/amiga/custom.h>
63 #include <amiga/amiga/cia.h>
64 #include <amiga/amiga/cc.h>
66 #include <dev/cons.h>
68 #include "ser.h"
69 #if NSER > 0
71 void serattach(struct device *, struct device *, void *);
72 int sermatch(struct device *, struct cfdata *, void *);
74 struct ser_softc {
75 struct device dev;
76 struct tty *ser_tty;
79 CFATTACH_DECL(ser, sizeof(struct ser_softc),
80 sermatch, serattach, NULL, NULL);
82 extern struct cfdriver ser_cd;
84 dev_type_open(seropen);
85 dev_type_close(serclose);
86 dev_type_read(serread);
87 dev_type_write(serwrite);
88 dev_type_ioctl(serioctl);
89 dev_type_stop(serstop);
90 dev_type_tty(sertty);
91 dev_type_poll(serpoll);
93 const struct cdevsw ser_cdevsw = {
94 seropen, serclose, serread, serwrite, serioctl,
95 serstop, sertty, serpoll, nommap, ttykqfilter, D_TTY
98 #ifndef SEROBUF_SIZE
99 #define SEROBUF_SIZE 32
100 #endif
101 #ifndef SERIBUF_SIZE
102 #define SERIBUF_SIZE 512
103 #endif
105 #define splser() spl5()
107 void serstart(struct tty *);
108 void ser_shutdown(struct ser_softc *);
109 int serparam(struct tty *, struct termios *);
110 void serintr(void);
111 int serhwiflow(struct tty *, int);
112 int sermctl(dev_t dev, int, int);
113 void ser_fastint(void);
114 void sereint(int);
115 static void ser_putchar(struct tty *, u_short);
116 void ser_outintr(void);
117 void sercnprobe(struct consdev *);
118 void sercninit(struct consdev *);
119 void serinit(int);
120 int sercngetc(dev_t dev);
121 void sercnputc(dev_t, int);
122 void sercnpollc(dev_t, int);
124 int nser = NSER;
125 #ifdef SERCONSOLE
126 int serconsole = 0;
127 #else
128 int serconsole = -1;
129 #endif
130 int serconsinit;
131 int serdefaultrate = TTYDEF_SPEED;
132 int serswflags;
134 struct vbl_node ser_vbl_node;
135 struct tty ser_cons;
136 struct tty *ser_tty;
138 static u_short serbuf[SERIBUF_SIZE];
139 static u_short *sbrpt = serbuf;
140 static u_short *sbwpt = serbuf;
141 static u_short sbcnt;
142 static u_short sbovfl;
143 static u_char serdcd;
146 * Since this UART is not particularly bright (to put it nicely), we'll
147 * have to do parity stuff on our own. This table contains the 8th bit
148 * in 7bit character mode, for even parity. If you want odd parity,
149 * flip the bit. (for generation of the table, see genpar.c)
152 u_char even_parity[] = {
153 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
154 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
155 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
156 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
157 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
158 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
159 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
160 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
164 * Since we don't get interrupts for changes on the modem control line,
165 * we'll have to fake them by comparing current settings to the settings
166 * we remembered on last invocation.
169 u_char last_ciab_pra;
171 extern struct tty *constty;
173 extern int ser_open_speed; /* current speed of open serial device */
175 #ifdef KGDB
176 #include <machine/remote-sl.h>
178 extern dev_t kgdb_dev;
179 extern int kgdb_rate;
180 extern int kgdb_debug_init;
181 #endif
183 #ifdef DEBUG
184 long fifoin[17];
185 long fifoout[17];
186 long serintrcount[16];
187 long sermintcount[16];
188 #endif
190 void sermint(register int unit);
193 sermatch(struct device *pdp, struct cfdata *cfp, void *auxp)
195 static int ser_matched = 0;
196 static int ser_matched_real = 0;
198 /* Allow only once instance. */
199 if (matchname("ser", (char *)auxp) == 0)
200 return(0);
202 if (amiga_realconfig) {
203 if (ser_matched_real)
204 return(0);
205 ser_matched_real = 1;
206 } else {
207 if (serconsole != 0)
208 return(0);
210 if (ser_matched != 0)
211 return(0);
213 ser_matched = 1;
215 return(1);
219 void
220 serattach(struct device *pdp, struct device *dp, void *auxp)
222 struct ser_softc *sc;
223 struct tty *tp;
224 u_short ir;
226 sc = device_private(dp);
228 ir = custom.intenar;
229 if (serconsole == 0)
230 DELAY(100000);
232 ser_vbl_node.function = (void (*) (void *)) sermint;
233 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0);
234 #ifdef KGDB
235 if (kgdb_dev == makedev(cdevsw_lookup_major(&ser_cdevsw), 0)) {
236 if (serconsole == 0)
237 kgdb_dev = NODEV; /* can't debug over console port */
238 else {
239 (void) serinit(kgdb_rate);
240 serconsinit = 1; /* don't re-init in serputc */
241 if (kgdb_debug_init == 0)
242 printf(" kgdb enabled\n");
243 else {
245 * Print prefix of device name,
246 * let kgdb_connect print the rest.
248 printf("ser0: ");
249 kgdb_connect(1);
253 #endif
255 * Need to reset baud rate, etc. of next print so reset serconsinit.
257 if (0 == serconsole)
258 serconsinit = 0;
260 tp = ttymalloc();
261 tp->t_oproc = (void (*) (struct tty *)) serstart;
262 tp->t_param = serparam;
263 tp->t_hwiflow = serhwiflow;
264 tty_attach(tp);
265 sc->ser_tty = ser_tty = tp;
267 if (dp)
268 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE,
269 SEROBUF_SIZE);
273 /* ARGSUSED */
275 seropen(dev_t dev, int flag, int mode, struct lwp *l)
277 struct ser_softc *sc;
278 struct tty *tp;
279 int unit, error, s, s2;
281 error = 0;
282 unit = SERUNIT(dev);
284 sc = device_lookup_private(&ser_cd, unit);
285 if (sc == NULL)
286 return (ENXIO);
288 /* XXX com.c: insert KGDB check here */
290 /* XXX ser.c had: s = spltty(); */
292 tp = sc->ser_tty;
294 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
295 return (EBUSY);
297 s = spltty();
300 * If this is a first open...
303 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
304 struct termios t;
306 tp->t_dev = dev;
308 s2 = splser();
310 * XXX here: hw enable,
312 last_ciab_pra = ciab.pra;
314 splx(s2);
315 t.c_ispeed = 0;
317 /* XXX serconsolerate? */
318 t.c_ospeed = TTYDEF_SPEED;
319 t.c_cflag = TTYDEF_CFLAG;
321 if (serswflags & TIOCFLAG_CLOCAL)
322 t.c_cflag |= CLOCAL;
323 if (serswflags & TIOCFLAG_CRTSCTS)
324 t.c_cflag |= CRTSCTS;
325 if (serswflags & TIOCFLAG_MDMBUF)
326 t.c_cflag |= MDMBUF;
328 /* Make sure serparam() will do something. */
329 tp->t_ospeed = 0;
330 serparam(tp, &t);
331 tp->t_iflag = TTYDEF_IFLAG;
332 tp->t_oflag = TTYDEF_OFLAG;
333 tp->t_lflag = TTYDEF_LFLAG;
334 ttychars(tp);
335 ttsetwater(tp);
337 s2 = splser();
338 (void)sermctl(dev, TIOCM_DTR, DMSET);
339 /* clear input ring */
340 sbrpt = sbwpt = serbuf;
341 sbcnt = 0;
342 splx(s2);
345 splx(s);
347 error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK);
348 if (error)
349 goto bad;
351 error = tp->t_linesw->l_open(dev, tp);
352 if (error)
353 goto bad;
355 return (0);
357 bad:
358 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
359 ser_shutdown(sc);
362 return (error);
365 /*ARGSUSED*/
367 serclose(dev_t dev, int flag, int mode, struct lwp *l)
369 struct ser_softc *sc;
370 struct tty *tp;
372 sc = device_lookup_private(&ser_cd, SERUNIT(dev));
373 tp = ser_tty;
375 /* XXX This is for cons.c, according to com.c */
376 if (!(tp->t_state & TS_ISOPEN))
377 return (0);
379 tp->t_linesw->l_close(tp, flag);
380 ttyclose(tp);
382 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) {
383 ser_shutdown(sc);
385 return (0);
388 void
389 ser_shutdown(struct ser_softc *sc)
391 struct tty *tp = sc->ser_tty;
392 int s;
394 s = splser();
396 custom.adkcon = ADKCONF_UARTBRK; /* clear break */
397 #if 0 /* XXX fix: #ifdef KGDB */
399 * do not disable interrupts if debugging
401 if (dev != kgdb_dev)
402 #endif
403 custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */
404 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */
407 * If HUPCL is not set, leave DTR unchanged.
409 if (tp->t_cflag & HUPCL) {
410 (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC);
412 * Idea from dev/ic/com.c:
413 * sleep a bit so that other side will notice, even if we
414 * reopen immediately.
416 (void) tsleep(tp, TTIPRI, ttclos, hz);
419 #if not_yet
420 if (tp != &ser_cons) {
421 remove_vbl_function(&ser_vbl_node);
422 ttyfree(tp);
423 ser_tty = (struct tty *) NULL;
425 #endif
426 ser_open_speed = tp->t_ispeed;
427 return;
431 serread(dev_t dev, struct uio *uio, int flag)
433 /* ARGSUSED */
435 return ser_tty->t_linesw->l_read(ser_tty, uio, flag);
439 serwrite(dev_t dev, struct uio *uio, int flag)
441 /* ARGSUSED */
443 return ser_tty->t_linesw->l_write(ser_tty, uio, flag);
447 serpoll(dev_t dev, int events, struct lwp *l)
449 /* ARGSUSED */
451 return ser_tty->t_linesw->l_poll(ser_tty, events, l);
454 struct tty *
455 sertty(dev_t dev)
457 /* ARGSUSED */
459 return (ser_tty);
463 * We don't do any processing of data here, so we store the raw code
464 * obtained from the uart register. In theory, 110kBaud gives you
465 * 11kcps, so 16k buffer should be more than enough, interrupt
466 * latency of 1s should never happen, or something is seriously
467 * wrong..
468 * buffers moved to above seropen() -is
472 * This is a replacement for the lack of a hardware fifo. 32k should be
473 * enough (there's only one unit anyway, so this is not going to
474 * accumulate).
476 void
477 ser_fastint(void)
480 * We're at RBE-level, which is higher than VBL-level which is used
481 * to periodically transmit contents of this buffer up one layer,
482 * so no spl-raising is necessary.
484 u_short code;
487 * This register contains both data and status bits!
489 code = custom.serdatr;
492 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but
493 * we save one (slow) custom chip access.
495 if ((code & SERDATRF_RBF) == 0)
496 return;
499 * clear interrupt
501 custom.intreq = INTF_RBF;
504 * check for buffer overflow.
506 if (sbcnt == SERIBUF_SIZE) {
507 ++sbovfl;
508 return;
511 * store in buffer
513 *sbwpt++ = code;
514 if (sbwpt == serbuf + SERIBUF_SIZE)
515 sbwpt = serbuf;
516 ++sbcnt;
517 if (sbcnt > SERIBUF_SIZE - 20)
518 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */
522 void
523 serintr(void)
525 int s1, s2, ovfl;
526 struct tty *tp = ser_tty;
529 * Make sure we're not interrupted by another
530 * vbl, but allow level5 ints
532 s1 = spltty();
535 * pass along any acumulated information
537 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) {
539 * no collision with ser_fastint()
541 sereint(*sbrpt++);
543 ovfl = 0;
544 /* lock against ser_fastint() */
545 s2 = splser();
546 sbcnt--;
547 if (sbrpt == serbuf + SERIBUF_SIZE)
548 sbrpt = serbuf;
549 if (sbovfl != 0) {
550 ovfl = sbovfl;
551 sbovfl = 0;
553 splx(s2);
554 if (ovfl != 0)
555 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n",
556 ovfl);
558 s2 = splser();
559 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0)
560 SETRTS(ciab.pra); /* start accepting data again */
561 splx(s2);
562 splx(s1);
565 void
566 sereint(int stat)
568 static int break_in_progress = 0;
569 struct tty *tp;
570 u_char ch;
571 int c;
573 tp = ser_tty;
574 ch = stat & 0xff;
575 c = ch;
577 if ((tp->t_state & TS_ISOPEN) == 0) {
578 #ifdef KGDB
579 int maj;
581 /* we don't care about parity errors */
582 maj = cdevsw_lookup_major(&ser_cdevsw);
583 if (kgdb_dev == makedev(maj, 0) && c == FRAME_END)
584 kgdb_connect(0); /* trap into kgdb */
585 #endif
586 return;
590 * Check for break and (if enabled) parity error.
592 if ((stat & 0x1ff) == 0) {
593 if (break_in_progress)
594 return;
596 c = TTY_FE;
597 break_in_progress = 1;
598 #ifdef DDB
599 if (serconsole == 0) {
600 extern int db_active;
602 if (!db_active) {
603 console_debugger();
604 return;
607 #endif
608 } else {
609 break_in_progress = 0;
610 if ((tp->t_cflag & PARENB) &&
611 (((ch >> 7) + even_parity[ch & 0x7f]
612 + !!(tp->t_cflag & PARODD)) & 1))
613 c |= TTY_PE;
616 if (stat & SERDATRF_OVRUN)
617 log(LOG_WARNING, "ser0: silo overflow\n");
619 tp->t_linesw->l_rint(c, tp);
623 * This interrupt is periodically invoked in the vertical blank
624 * interrupt. It's used to keep track of the modem control lines
625 * and (new with the fast_int code) to move accumulated data
626 * up into the tty layer.
628 void
629 sermint(int unit)
631 struct tty *tp;
632 u_char stat, last, istat;
634 tp = ser_tty;
635 if (!tp)
636 return;
639 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
640 sbrpt = sbwpt = serbuf;
641 return;
645 * empty buffer
647 serintr();
649 stat = ciab.pra;
650 last = last_ciab_pra;
651 last_ciab_pra = stat;
654 * check whether any interesting signal changed state
656 istat = stat ^ last;
658 if (istat & serdcd) {
659 tp->t_linesw->l_modem(tp, ISDCD(stat));
662 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) &&
663 (tp->t_cflag & CRTSCTS)) {
664 #if 0
665 /* the line is up and we want to do rts/cts flow control */
666 if (ISCTS(stat)) {
667 tp->t_state &= ~TS_TTSTOP;
668 ttstart(tp);
669 /* cause tbe-int if we were stuck there */
670 custom.intreq = INTF_SETCLR | INTF_TBE;
671 } else
672 tp->t_state |= TS_TTSTOP;
673 #else
674 /* do this on hardware level, not with tty driver */
675 if (ISCTS(stat)) {
676 tp->t_state &= ~TS_TTSTOP;
677 /* cause TBE interrupt */
678 custom.intreq = INTF_SETCLR | INTF_TBE;
680 #endif
685 serioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
687 register struct tty *tp;
688 register int error;
690 tp = ser_tty;
691 if (!tp)
692 return ENXIO;
694 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l);
695 if (error != EPASSTHROUGH)
696 return(error);
698 error = ttioctl(tp, cmd, data, flag, l);
699 if (error != EPASSTHROUGH)
700 return(error);
702 switch (cmd) {
703 case TIOCSBRK:
704 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK;
705 break;
707 case TIOCCBRK:
708 custom.adkcon = ADKCONF_UARTBRK;
709 break;
711 case TIOCSDTR:
712 (void) sermctl(dev, TIOCM_DTR, DMBIS);
713 break;
715 case TIOCCDTR:
716 (void) sermctl(dev, TIOCM_DTR, DMBIC);
717 break;
719 case TIOCMSET:
720 (void) sermctl(dev, *(int *) data, DMSET);
721 break;
723 case TIOCMBIS:
724 (void) sermctl(dev, *(int *) data, DMBIS);
725 break;
727 case TIOCMBIC:
728 (void) sermctl(dev, *(int *) data, DMBIC);
729 break;
731 case TIOCMGET:
732 *(int *)data = sermctl(dev, 0, DMGET);
733 break;
734 case TIOCGFLAGS:
735 *(int *)data = serswflags;
736 break;
737 case TIOCSFLAGS:
738 error = kauth_authorize_device_tty(l->l_cred,
739 KAUTH_DEVICE_TTY_PRIVSET, tp);
740 if (error != 0)
741 return(EPERM);
743 serswflags = *(int *)data;
744 serswflags &= /* only allow valid flags */
745 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
746 break;
747 default:
748 return(EPASSTHROUGH);
751 return(0);
755 serparam(struct tty *tp, struct termios *t)
757 int cflag, ospeed = 0;
759 if (t->c_ospeed > 0) {
760 if (t->c_ospeed < 110)
761 return(EINVAL);
762 ospeed = SERBRD(t->c_ospeed);
765 if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
766 return(EINVAL);
768 if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) {
769 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL;
772 /* if no changes, dont do anything. com.c explains why. */
773 if (tp->t_ospeed == t->c_ospeed &&
774 tp->t_cflag == t->c_cflag)
775 return (0);
777 cflag = t->c_cflag;
779 if (cflag & (CLOCAL | MDMBUF))
780 serdcd = 0;
781 else
782 serdcd = CIAB_PRA_CD;
784 /* TODO: support multiple flow control protocols like com.c */
787 * copy to tty
789 tp->t_ispeed = t->c_ispeed;
790 tp->t_ospeed = t->c_ospeed;
791 tp->t_cflag = cflag;
792 ser_open_speed = tp->t_ispeed;
795 * enable interrupts
797 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE;
798 last_ciab_pra = ciab.pra;
800 if (t->c_ospeed == 0)
801 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */
802 else {
804 * (re)enable DTR
805 * and set baud rate. (8 bit mode)
807 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET);
808 custom.serper = (0 << 15) | ospeed;
810 (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra));
812 return(0);
815 int serhwiflow(struct tty *tp, int flag)
817 #if 0
818 printf ("serhwiflow %d\n", flag);
819 #endif
820 if (flag)
821 CLRRTS(ciab.pra);
822 else
823 SETRTS(ciab.pra);
824 return 1;
827 static void
828 ser_putchar(struct tty *tp, u_short c)
830 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB))
831 c &= 0x7f;
834 * handle parity if necessary
836 if (tp->t_cflag & PARENB) {
837 if (even_parity[c])
838 c |= 0x80;
839 if (tp->t_cflag & PARODD)
840 c ^= 0x80;
843 * add stop bit(s)
845 if (tp->t_cflag & CSTOPB)
846 c |= 0x300;
847 else
848 c |= 0x100;
850 custom.serdat = c;
854 static u_char ser_outbuf[SEROBUF_SIZE];
855 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf;
857 void
858 ser_outintr(void)
860 struct tty *tp;
861 int s;
863 tp = ser_tty;
864 s = spltty();
866 if (tp == 0)
867 goto out;
869 if ((custom.intreqr & INTF_TBE) == 0)
870 goto out;
873 * clear interrupt
875 custom.intreq = INTF_TBE;
877 if (sob_ptr == sob_end) {
878 tp->t_state &= ~(TS_BUSY | TS_FLUSH);
879 if (tp->t_linesw)
880 tp->t_linesw->l_start(tp);
881 else
882 serstart(tp);
883 goto out;
887 * Do hardware flow control here. if the CTS line goes down, don't
888 * transmit anything. That way, we'll be restarted by the periodic
889 * interrupt when CTS comes back up.
891 if (ISCTS(ciab.pra))
892 ser_putchar(tp, *sob_ptr++);
893 else
894 CLRCTS(last_ciab_pra); /* Remember that CTS is off */
895 out:
896 splx(s);
899 void
900 serstart(struct tty *tp)
902 int cc, s, hiwat;
903 #ifdef DIAGNOSTIC
904 int unit;
905 #endif
907 hiwat = 0;
909 if ((tp->t_state & TS_ISOPEN) == 0)
910 return;
912 #ifdef DIAGNOSTIC
913 unit = SERUNIT(tp->t_dev);
914 if (unit)
915 panic("serstart: unit is %d", unit);
916 #endif
918 s = spltty();
919 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
920 goto out;
922 cc = tp->t_outq.c_cc;
923 if (!ttypull(tp) || (tp->t_state & TS_BUSY))
924 goto out;
927 * We only do bulk transfers if using CTSRTS flow control, not for
928 * (probably sloooow) ixon/ixoff devices.
930 if ((tp->t_cflag & CRTSCTS) == 0)
931 cc = 1;
934 * Limit the amount of output we do in one burst
935 * to prevent hogging the CPU.
937 if (cc > SEROBUF_SIZE) {
938 hiwat++;
939 cc = SEROBUF_SIZE;
941 cc = q_to_b(&tp->t_outq, ser_outbuf, cc);
942 if (cc > 0) {
943 tp->t_state |= TS_BUSY;
945 sob_ptr = ser_outbuf;
946 sob_end = ser_outbuf + cc;
949 * Get first character out, then have TBE-interrupts blow out
950 * further characters, until buffer is empty, and TS_BUSY gets
951 * cleared.
953 ser_putchar(tp, *sob_ptr++);
955 out:
956 splx(s);
960 * Stop output on a line.
962 /*ARGSUSED*/
963 void
964 serstop(struct tty *tp, int flag)
966 int s;
968 s = spltty();
969 if (tp->t_state & TS_BUSY) {
970 if ((tp->t_state & TS_TTSTOP) == 0)
971 tp->t_state |= TS_FLUSH;
973 splx(s);
977 sermctl(dev_t dev, int bits, int how)
979 int s;
980 u_char ub = 0;
983 * convert TIOCM* mask into CIA mask
984 * which is active low
986 if (how != DMGET) {
987 ub = 0;
988 if (bits & TIOCM_DTR)
989 ub |= CIAB_PRA_DTR;
990 if (bits & TIOCM_RTS)
991 ub |= CIAB_PRA_RTS;
992 if (bits & TIOCM_CTS)
993 ub |= CIAB_PRA_CTS;
994 if (bits & TIOCM_CD)
995 ub |= CIAB_PRA_CD;
996 if (bits & TIOCM_RI)
997 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */
998 if (bits & TIOCM_DSR)
999 ub |= CIAB_PRA_DSR;
1001 s = spltty();
1002 switch (how) {
1003 case DMSET:
1004 /* invert and set */
1005 ciab.pra = ~ub;
1006 break;
1008 case DMBIC:
1009 ciab.pra |= ub;
1010 ub = ~ciab.pra;
1011 break;
1013 case DMBIS:
1014 ciab.pra &= ~ub;
1015 ub = ~ciab.pra;
1016 break;
1018 case DMGET:
1019 ub = ~ciab.pra;
1020 break;
1022 (void)splx(s);
1024 bits = 0;
1025 if (ub & CIAB_PRA_DTR)
1026 bits |= TIOCM_DTR;
1027 if (ub & CIAB_PRA_RTS)
1028 bits |= TIOCM_RTS;
1029 if (ub & CIAB_PRA_CTS)
1030 bits |= TIOCM_CTS;
1031 if (ub & CIAB_PRA_CD)
1032 bits |= TIOCM_CD;
1033 if (ub & CIAB_PRA_SEL)
1034 bits |= TIOCM_RI;
1035 if (ub & CIAB_PRA_DSR)
1036 bits |= TIOCM_DSR;
1038 return(bits);
1042 * Following are all routines needed for SER to act as console
1044 void
1045 sercnprobe(struct consdev *cp)
1047 int maj, unit;
1048 #ifdef KGDB
1049 extern const struct cdevsw ctty_cdevsw;
1050 #endif
1052 /* locate the major number */
1053 maj = cdevsw_lookup_major(&ser_cdevsw);
1056 unit = CONUNIT; /* XXX: ick */
1059 * initialize required fields
1061 cp->cn_dev = makedev(maj, unit);
1062 if (serconsole == unit)
1063 cp->cn_pri = CN_REMOTE;
1064 else
1065 cp->cn_pri = CN_NORMAL;
1066 #ifdef KGDB
1067 /* XXX */
1068 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw)
1069 kgdb_dev = makedev(maj, minor(kgdb_dev));
1070 #endif
1073 void
1074 sercninit(struct consdev *cp)
1076 int unit;
1078 unit = SERUNIT(cp->cn_dev);
1080 serinit(serdefaultrate);
1081 serconsole = unit;
1082 serconsinit = 1;
1085 void
1086 serinit(int rate)
1088 int s;
1090 s = splser();
1092 * might want to fiddle with the CIA later ???
1094 custom.serper = (rate>=110 ? SERBRD(rate) : 0);
1095 splx(s);
1099 sercngetc(dev_t dev)
1101 u_short stat;
1102 int c, s;
1104 s = splser();
1106 * poll
1108 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0)
1111 c = stat & 0xff;
1113 * clear interrupt
1115 custom.intreq = INTF_RBF;
1116 splx(s);
1118 return(c);
1122 * Console kernel output character routine.
1124 void
1125 sercnputc(dev_t dev, int c)
1127 register int timo;
1128 int s;
1130 s = splhigh();
1132 if (serconsinit == 0) {
1133 (void)serinit(serdefaultrate);
1134 serconsinit = 1;
1138 * wait for any pending transmission to finish
1140 timo = 50000;
1141 while (!(custom.serdatr & SERDATRF_TBE) && --timo);
1144 * transmit char.
1146 custom.serdat = (c & 0xff) | 0x100;
1149 * wait for this transmission to complete
1151 timo = 1500000;
1152 while (!(custom.serdatr & SERDATRF_TBE) && --timo)
1156 * Wait for the device (my vt100..) to process the data, since we
1157 * don't do flow-control with cnputc
1159 for (timo = 0; timo < 30000; timo++)
1163 * We set TBE so that ser_outintr() is called right after to check
1164 * whether there still are chars to process.
1165 * We used to clear this, but it hung the tty output if the kernel
1166 * output a char while userland did on the same serial port.
1168 custom.intreq = INTF_SETCLR | INTF_TBE;
1169 splx(s);
1172 void
1173 sercnpollc(dev_t dev, int on)
1176 #endif