1 /* $NetBSD: ser.c,v 1.77 2007/11/19 18:51:37 ad Exp $ */
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
31 * @(#)ser.c 7.12 (Berkeley) 6/27/91
34 * XXX This file needs major cleanup it will never service more than one
38 #include "opt_amigacons.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>
52 #include <sys/malloc.h>
54 #include <sys/kernel.h>
55 #include <sys/syslog.h>
56 #include <sys/queue.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>
71 void serattach(struct device
*, struct device
*, void *);
72 int sermatch(struct device
*, struct cfdata
*, void *);
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
);
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
99 #define SEROBUF_SIZE 32
102 #define SERIBUF_SIZE 512
105 #define splser() spl5()
107 void serstart(struct tty
*);
108 void ser_shutdown(struct ser_softc
*);
109 int serparam(struct tty
*, struct termios
*);
111 int serhwiflow(struct tty
*, int);
112 int sermctl(dev_t dev
, int, int);
113 void ser_fastint(void);
115 static void ser_putchar(struct tty
*, u_short
);
116 void ser_outintr(void);
117 void sercnprobe(struct consdev
*);
118 void sercninit(struct consdev
*);
120 int sercngetc(dev_t dev
);
121 void sercnputc(dev_t
, int);
122 void sercnpollc(dev_t
, int);
131 int serdefaultrate
= TTYDEF_SPEED
;
134 struct vbl_node ser_vbl_node
;
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 */
176 #include <machine/remote-sl.h>
178 extern dev_t kgdb_dev
;
179 extern int kgdb_rate
;
180 extern int kgdb_debug_init
;
186 long serintrcount
[16];
187 long sermintcount
[16];
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)
202 if (amiga_realconfig
) {
203 if (ser_matched_real
)
205 ser_matched_real
= 1;
210 if (ser_matched
!= 0)
220 serattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
222 struct ser_softc
*sc
;
226 sc
= device_private(dp
);
232 ser_vbl_node
.function
= (void (*) (void *)) sermint
;
233 add_vbl_function(&ser_vbl_node
, SER_VBL_PRIORITY
, (void *) 0);
235 if (kgdb_dev
== makedev(cdevsw_lookup_major(&ser_cdevsw
), 0)) {
237 kgdb_dev
= NODEV
; /* can't debug over console port */
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");
245 * Print prefix of device name,
246 * let kgdb_connect print the rest.
255 * Need to reset baud rate, etc. of next print so reset serconsinit.
261 tp
->t_oproc
= (void (*) (struct tty
*)) serstart
;
262 tp
->t_param
= serparam
;
263 tp
->t_hwiflow
= serhwiflow
;
265 sc
->ser_tty
= ser_tty
= tp
;
268 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE
,
275 seropen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
277 struct ser_softc
*sc
;
279 int unit
, error
, s
, s2
;
284 sc
= device_lookup_private(&ser_cd
, unit
);
288 /* XXX com.c: insert KGDB check here */
290 /* XXX ser.c had: s = spltty(); */
294 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
300 * If this is a first open...
303 if ((tp
->t_state
& TS_ISOPEN
) == 0 && tp
->t_wopen
== 0) {
310 * XXX here: hw enable,
312 last_ciab_pra
= ciab
.pra
;
317 /* XXX serconsolerate? */
318 t
.c_ospeed
= TTYDEF_SPEED
;
319 t
.c_cflag
= TTYDEF_CFLAG
;
321 if (serswflags
& TIOCFLAG_CLOCAL
)
323 if (serswflags
& TIOCFLAG_CRTSCTS
)
324 t
.c_cflag
|= CRTSCTS
;
325 if (serswflags
& TIOCFLAG_MDMBUF
)
328 /* Make sure serparam() will do something. */
331 tp
->t_iflag
= TTYDEF_IFLAG
;
332 tp
->t_oflag
= TTYDEF_OFLAG
;
333 tp
->t_lflag
= TTYDEF_LFLAG
;
338 (void)sermctl(dev
, TIOCM_DTR
, DMSET
);
339 /* clear input ring */
340 sbrpt
= sbwpt
= serbuf
;
347 error
= ttyopen(tp
, DIALOUT(dev
), flag
& O_NONBLOCK
);
351 error
= tp
->t_linesw
->l_open(dev
, tp
);
358 if (!(tp
->t_state
& TS_ISOPEN
) && tp
->t_wopen
== 0) {
367 serclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
369 struct ser_softc
*sc
;
372 sc
= device_lookup_private(&ser_cd
, SERUNIT(dev
));
375 /* XXX This is for cons.c, according to com.c */
376 if (!(tp
->t_state
& TS_ISOPEN
))
379 tp
->t_linesw
->l_close(tp
, flag
);
382 if (!(tp
->t_state
& TS_ISOPEN
) && tp
->t_wopen
== 0) {
389 ser_shutdown(struct ser_softc
*sc
)
391 struct tty
*tp
= sc
->ser_tty
;
396 custom
.adkcon
= ADKCONF_UARTBRK
; /* clear break */
397 #if 0 /* XXX fix: #ifdef KGDB */
399 * do not disable interrupts if debugging
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
);
420 if (tp
!= &ser_cons
) {
421 remove_vbl_function(&ser_vbl_node
);
423 ser_tty
= (struct tty
*) NULL
;
426 ser_open_speed
= tp
->t_ispeed
;
431 serread(dev_t dev
, struct uio
*uio
, int flag
)
435 return ser_tty
->t_linesw
->l_read(ser_tty
, uio
, flag
);
439 serwrite(dev_t dev
, struct uio
*uio
, int flag
)
443 return ser_tty
->t_linesw
->l_write(ser_tty
, uio
, flag
);
447 serpoll(dev_t dev
, int events
, struct lwp
*l
)
451 return ser_tty
->t_linesw
->l_poll(ser_tty
, events
, l
);
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
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
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.
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)
501 custom
.intreq
= INTF_RBF
;
504 * check for buffer overflow.
506 if (sbcnt
== SERIBUF_SIZE
) {
514 if (sbwpt
== serbuf
+ SERIBUF_SIZE
)
517 if (sbcnt
> SERIBUF_SIZE
- 20)
518 CLRRTS(ciab
.pra
); /* drop RTS if buffer almost full */
526 struct tty
*tp
= ser_tty
;
529 * Make sure we're not interrupted by another
530 * vbl, but allow level5 ints
535 * pass along any acumulated information
537 while (sbcnt
> 0 && (tp
->t_state
& TS_TBLOCK
) == 0) {
539 * no collision with ser_fastint()
544 /* lock against ser_fastint() */
547 if (sbrpt
== serbuf
+ SERIBUF_SIZE
)
555 log(LOG_WARNING
, "ser0: %d ring buffer overflows.\n",
559 if (sbcnt
== 0 && (tp
->t_state
& TS_TBLOCK
) == 0)
560 SETRTS(ciab
.pra
); /* start accepting data again */
568 static int break_in_progress
= 0;
577 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
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 */
590 * Check for break and (if enabled) parity error.
592 if ((stat
& 0x1ff) == 0) {
593 if (break_in_progress
)
597 break_in_progress
= 1;
599 if (serconsole
== 0) {
600 extern int db_active
;
609 break_in_progress
= 0;
610 if ((tp
->t_cflag
& PARENB
) &&
611 (((ch
>> 7) + even_parity
[ch
& 0x7f]
612 + !!(tp
->t_cflag
& PARODD
)) & 1))
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.
632 u_char stat
, last
, istat
;
639 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) {
640 sbrpt = sbwpt = serbuf;
650 last
= last_ciab_pra
;
651 last_ciab_pra
= stat
;
654 * check whether any interesting signal changed state
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
)) {
665 /* the line is up and we want to do rts/cts flow control */
667 tp
->t_state
&= ~TS_TTSTOP
;
669 /* cause tbe-int if we were stuck there */
670 custom
.intreq
= INTF_SETCLR
| INTF_TBE
;
672 tp
->t_state
|= TS_TTSTOP
;
674 /* do this on hardware level, not with tty driver */
676 tp
->t_state
&= ~TS_TTSTOP
;
677 /* cause TBE interrupt */
678 custom
.intreq
= INTF_SETCLR
| INTF_TBE
;
685 serioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
687 register struct tty
*tp
;
694 error
= tp
->t_linesw
->l_ioctl(tp
, cmd
, data
, flag
, l
);
695 if (error
!= EPASSTHROUGH
)
698 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
699 if (error
!= EPASSTHROUGH
)
704 custom
.adkcon
= ADKCONF_SETCLR
| ADKCONF_UARTBRK
;
708 custom
.adkcon
= ADKCONF_UARTBRK
;
712 (void) sermctl(dev
, TIOCM_DTR
, DMBIS
);
716 (void) sermctl(dev
, TIOCM_DTR
, DMBIC
);
720 (void) sermctl(dev
, *(int *) data
, DMSET
);
724 (void) sermctl(dev
, *(int *) data
, DMBIS
);
728 (void) sermctl(dev
, *(int *) data
, DMBIC
);
732 *(int *)data
= sermctl(dev
, 0, DMGET
);
735 *(int *)data
= serswflags
;
738 error
= kauth_authorize_device_tty(l
->l_cred
,
739 KAUTH_DEVICE_TTY_PRIVSET
, tp
);
743 serswflags
= *(int *)data
;
744 serswflags
&= /* only allow valid flags */
745 (TIOCFLAG_SOFTCAR
| TIOCFLAG_CLOCAL
| TIOCFLAG_CRTSCTS
);
748 return(EPASSTHROUGH
);
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)
762 ospeed
= SERBRD(t
->c_ospeed
);
765 if (t
->c_ispeed
&& t
->c_ispeed
!= t
->c_ospeed
)
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
)
779 if (cflag
& (CLOCAL
| MDMBUF
))
782 serdcd
= CIAB_PRA_CD
;
784 /* TODO: support multiple flow control protocols like com.c */
789 tp
->t_ispeed
= t
->c_ispeed
;
790 tp
->t_ospeed
= t
->c_ospeed
;
792 ser_open_speed
= tp
->t_ispeed
;
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 */
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
));
815 int serhwiflow(struct tty
*tp
, int flag
)
818 printf ("serhwiflow %d\n", flag
);
828 ser_putchar(struct tty
*tp
, u_short c
)
830 if ((tp
->t_cflag
& CSIZE
) == CS7
|| (tp
->t_cflag
& PARENB
))
834 * handle parity if necessary
836 if (tp
->t_cflag
& PARENB
) {
839 if (tp
->t_cflag
& PARODD
)
845 if (tp
->t_cflag
& CSTOPB
)
854 static u_char ser_outbuf
[SEROBUF_SIZE
];
855 static u_char
*sob_ptr
= ser_outbuf
, *sob_end
= ser_outbuf
;
869 if ((custom
.intreqr
& INTF_TBE
) == 0)
875 custom
.intreq
= INTF_TBE
;
877 if (sob_ptr
== sob_end
) {
878 tp
->t_state
&= ~(TS_BUSY
| TS_FLUSH
);
880 tp
->t_linesw
->l_start(tp
);
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.
892 ser_putchar(tp
, *sob_ptr
++);
894 CLRCTS(last_ciab_pra
); /* Remember that CTS is off */
900 serstart(struct tty
*tp
)
909 if ((tp
->t_state
& TS_ISOPEN
) == 0)
913 unit
= SERUNIT(tp
->t_dev
);
915 panic("serstart: unit is %d", unit
);
919 if (tp
->t_state
& (TS_TIMEOUT
| TS_TTSTOP
))
922 cc
= tp
->t_outq
.c_cc
;
923 if (!ttypull(tp
) || (tp
->t_state
& TS_BUSY
))
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)
934 * Limit the amount of output we do in one burst
935 * to prevent hogging the CPU.
937 if (cc
> SEROBUF_SIZE
) {
941 cc
= q_to_b(&tp
->t_outq
, ser_outbuf
, cc
);
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
953 ser_putchar(tp
, *sob_ptr
++);
960 * Stop output on a line.
964 serstop(struct tty
*tp
, int flag
)
969 if (tp
->t_state
& TS_BUSY
) {
970 if ((tp
->t_state
& TS_TTSTOP
) == 0)
971 tp
->t_state
|= TS_FLUSH
;
977 sermctl(dev_t dev
, int bits
, int how
)
983 * convert TIOCM* mask into CIA mask
984 * which is active low
988 if (bits
& TIOCM_DTR
)
990 if (bits
& TIOCM_RTS
)
992 if (bits
& TIOCM_CTS
)
997 ub
|= CIAB_PRA_SEL
; /* collision with /dev/par ! */
998 if (bits
& TIOCM_DSR
)
1004 /* invert and set */
1025 if (ub
& CIAB_PRA_DTR
)
1027 if (ub
& CIAB_PRA_RTS
)
1029 if (ub
& CIAB_PRA_CTS
)
1031 if (ub
& CIAB_PRA_CD
)
1033 if (ub
& CIAB_PRA_SEL
)
1035 if (ub
& CIAB_PRA_DSR
)
1042 * Following are all routines needed for SER to act as console
1045 sercnprobe(struct consdev
*cp
)
1049 extern const struct cdevsw ctty_cdevsw
;
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
;
1065 cp
->cn_pri
= CN_NORMAL
;
1068 if (cdevsw_lookup(kgdb_dev
) == &ctty_cdevsw
)
1069 kgdb_dev
= makedev(maj
, minor(kgdb_dev
));
1074 sercninit(struct consdev
*cp
)
1078 unit
= SERUNIT(cp
->cn_dev
);
1080 serinit(serdefaultrate
);
1092 * might want to fiddle with the CIA later ???
1094 custom
.serper
= (rate
>=110 ? SERBRD(rate
) : 0);
1099 sercngetc(dev_t dev
)
1108 while (((stat
= custom
.serdatr
& 0xffff) & SERDATRF_RBF
) == 0)
1115 custom
.intreq
= INTF_RBF
;
1122 * Console kernel output character routine.
1125 sercnputc(dev_t dev
, int c
)
1132 if (serconsinit
== 0) {
1133 (void)serinit(serdefaultrate
);
1138 * wait for any pending transmission to finish
1141 while (!(custom
.serdatr
& SERDATRF_TBE
) && --timo
);
1146 custom
.serdat
= (c
& 0xff) | 0x100;
1149 * wait for this transmission to complete
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
;
1173 sercnpollc(dev_t dev
, int on
)