Deleted Added
full compact
rc.c (47739) rc.c (50254)
1/*
2 * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia.
3 * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver
30 *
31 */
32
33#include "rc.h"
34
35#if NRC > 0
1/*
2 * Copyright (C) 1995 by Pavel Antonov, Moscow, Russia.
3 * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/*
29 * SDL Communications Riscom/8 (based on Cirrus Logic CL-CD180) driver
30 *
31 */
32
33#include "rc.h"
34
35#if NRC > 0
36#include "opt_devfs.h"
37
38/*#define RCDEBUG*/
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/tty.h>
43#include <sys/proc.h>
44#include <sys/conf.h>
45#include <sys/dkstat.h>
46#include <sys/fcntl.h>
47#include <sys/interrupt.h>
48#include <sys/kernel.h>
36/*#define RCDEBUG*/
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/tty.h>
41#include <sys/proc.h>
42#include <sys/conf.h>
43#include <sys/dkstat.h>
44#include <sys/fcntl.h>
45#include <sys/interrupt.h>
46#include <sys/kernel.h>
49#ifdef DEVFS
50#include <sys/devfsext.h>
51#endif /*DEVFS*/
52
53#include <machine/clock.h>
54#include <machine/ipl.h>
55
56#include <i386/isa/isa_device.h>
57
58#include <i386/isa/ic/cd180.h>
59#include <i386/isa/rcreg.h>
60
61/* Prototypes */
62static int rcprobe __P((struct isa_device *));
63static int rcattach __P((struct isa_device *));
64
65#define rcin(port) RC_IN (nec, port)
66#define rcout(port,v) RC_OUT (nec, port, v)
67
68#define WAITFORCCR(u,c) rc_wait0(nec, (u), (c), __LINE__)
69#define CCRCMD(u,c,cmd) WAITFORCCR((u), (c)); rcout(CD180_CCR, (cmd))
70
71#define RC_IBUFSIZE 256
72#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE)
73#define RC_OBUFSIZE 512
74#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4)
75#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE)
76#define LOTS_OF_EVENTS 64
77
78#define RC_FAKEID 0x10
79
80#define RC_PROBED 1
81#define RC_ATTACHED 2
82
83#define GET_UNIT(dev) (minor(dev) & 0x3F)
84#define CALLOUT(dev) (minor(dev) & 0x80)
85
86/* For isa routines */
87struct isa_driver rcdriver = {
88 rcprobe, rcattach, "rc"
89};
90
91static d_open_t rcopen;
92static d_close_t rcclose;
93static d_read_t rcread;
94static d_write_t rcwrite;
95static d_ioctl_t rcioctl;
96static d_stop_t rcstop;
97static d_devtotty_t rcdevtotty;
98
99#define CDEV_MAJOR 63
100static struct cdevsw rc_cdevsw = {
101 /* open */ rcopen,
102 /* close */ rcclose,
103 /* read */ rcread,
104 /* write */ rcwrite,
105 /* ioctl */ rcioctl,
106 /* stop */ rcstop,
107 /* reset */ noreset,
108 /* devtotty */ rcdevtotty,
109 /* poll */ ttpoll,
110 /* mmap */ nommap,
111 /* strategy */ nostrategy,
112 /* name */ "rc",
113 /* parms */ noparms,
114 /* maj */ CDEV_MAJOR,
115 /* dump */ nodump,
116 /* psize */ nopsize,
117 /* flags */ D_TTY,
118 /* maxio */ 0,
119 /* bmaj */ -1
120};
121
122/* Per-board structure */
123static struct rc_softc {
124 u_int rcb_probed; /* 1 - probed, 2 - attached */
125 u_int rcb_addr; /* Base I/O addr */
126 u_int rcb_unit; /* unit # */
127 u_char rcb_dtr; /* DTR status */
128 struct rc_chans *rcb_baserc; /* base rc ptr */
129} rc_softc[NRC];
130
131/* Per-channel structure */
132static struct rc_chans {
133 struct rc_softc *rc_rcb; /* back ptr */
134 u_short rc_flags; /* Misc. flags */
135 int rc_chan; /* Channel # */
136 u_char rc_ier; /* intr. enable reg */
137 u_char rc_msvr; /* modem sig. status */
138 u_char rc_cor2; /* options reg */
139 u_char rc_pendcmd; /* special cmd pending */
140 u_int rc_dtrwait; /* dtr timeout */
141 u_int rc_dcdwaits; /* how many waits DCD in open */
142 u_char rc_hotchar; /* end packed optimize */
143 struct tty *rc_tp; /* tty struct */
144 u_char *rc_iptr; /* Chars input buffer */
145 u_char *rc_hiwat; /* hi-water mark */
146 u_char *rc_bufend; /* end of buffer */
147 u_char *rc_optr; /* ptr in output buf */
148 u_char *rc_obufend; /* end of output buf */
149 u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */
150 u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */
47#include <machine/clock.h>
48#include <machine/ipl.h>
49
50#include <i386/isa/isa_device.h>
51
52#include <i386/isa/ic/cd180.h>
53#include <i386/isa/rcreg.h>
54
55/* Prototypes */
56static int rcprobe __P((struct isa_device *));
57static int rcattach __P((struct isa_device *));
58
59#define rcin(port) RC_IN (nec, port)
60#define rcout(port,v) RC_OUT (nec, port, v)
61
62#define WAITFORCCR(u,c) rc_wait0(nec, (u), (c), __LINE__)
63#define CCRCMD(u,c,cmd) WAITFORCCR((u), (c)); rcout(CD180_CCR, (cmd))
64
65#define RC_IBUFSIZE 256
66#define RB_I_HIGH_WATER (TTYHOG - 2 * RC_IBUFSIZE)
67#define RC_OBUFSIZE 512
68#define RC_IHIGHWATER (3 * RC_IBUFSIZE / 4)
69#define INPUT_FLAGS_SHIFT (2 * RC_IBUFSIZE)
70#define LOTS_OF_EVENTS 64
71
72#define RC_FAKEID 0x10
73
74#define RC_PROBED 1
75#define RC_ATTACHED 2
76
77#define GET_UNIT(dev) (minor(dev) & 0x3F)
78#define CALLOUT(dev) (minor(dev) & 0x80)
79
80/* For isa routines */
81struct isa_driver rcdriver = {
82 rcprobe, rcattach, "rc"
83};
84
85static d_open_t rcopen;
86static d_close_t rcclose;
87static d_read_t rcread;
88static d_write_t rcwrite;
89static d_ioctl_t rcioctl;
90static d_stop_t rcstop;
91static d_devtotty_t rcdevtotty;
92
93#define CDEV_MAJOR 63
94static struct cdevsw rc_cdevsw = {
95 /* open */ rcopen,
96 /* close */ rcclose,
97 /* read */ rcread,
98 /* write */ rcwrite,
99 /* ioctl */ rcioctl,
100 /* stop */ rcstop,
101 /* reset */ noreset,
102 /* devtotty */ rcdevtotty,
103 /* poll */ ttpoll,
104 /* mmap */ nommap,
105 /* strategy */ nostrategy,
106 /* name */ "rc",
107 /* parms */ noparms,
108 /* maj */ CDEV_MAJOR,
109 /* dump */ nodump,
110 /* psize */ nopsize,
111 /* flags */ D_TTY,
112 /* maxio */ 0,
113 /* bmaj */ -1
114};
115
116/* Per-board structure */
117static struct rc_softc {
118 u_int rcb_probed; /* 1 - probed, 2 - attached */
119 u_int rcb_addr; /* Base I/O addr */
120 u_int rcb_unit; /* unit # */
121 u_char rcb_dtr; /* DTR status */
122 struct rc_chans *rcb_baserc; /* base rc ptr */
123} rc_softc[NRC];
124
125/* Per-channel structure */
126static struct rc_chans {
127 struct rc_softc *rc_rcb; /* back ptr */
128 u_short rc_flags; /* Misc. flags */
129 int rc_chan; /* Channel # */
130 u_char rc_ier; /* intr. enable reg */
131 u_char rc_msvr; /* modem sig. status */
132 u_char rc_cor2; /* options reg */
133 u_char rc_pendcmd; /* special cmd pending */
134 u_int rc_dtrwait; /* dtr timeout */
135 u_int rc_dcdwaits; /* how many waits DCD in open */
136 u_char rc_hotchar; /* end packed optimize */
137 struct tty *rc_tp; /* tty struct */
138 u_char *rc_iptr; /* Chars input buffer */
139 u_char *rc_hiwat; /* hi-water mark */
140 u_char *rc_bufend; /* end of buffer */
141 u_char *rc_optr; /* ptr in output buf */
142 u_char *rc_obufend; /* end of output buf */
143 u_char rc_ibuf[4 * RC_IBUFSIZE]; /* input buffer */
144 u_char rc_obuf[RC_OBUFSIZE]; /* output buffer */
151#ifdef DEVFS
152 void *devfs_token;
153#endif
154} rc_chans[NRC * CD180_NCHAN];
155
156static int rc_scheduled_event = 0;
157
158/* for pstat -t */
159static struct tty rc_tty[NRC * CD180_NCHAN];
160static const int nrc_tty = NRC * CD180_NCHAN;
161
162/* Flags */
163#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */
164#define RC_ACTOUT 0x0002 /* Dial-out port active */
165#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */
166#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */
167#define RC_DORXFER 0x0010 /* RXFER event planned */
168#define RC_DOXXFER 0x0020 /* XXFER event planned */
169#define RC_MODCHG 0x0040 /* Modem status changed */
170#define RC_OSUSP 0x0080 /* Output suspended */
171#define RC_OSBUSY 0x0100 /* start() routine in progress */
172#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */
173#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */
174#define RC_SEND_RDY 0x0800 /* ready to send */
175
176/* Table for translation of RCSR status bits to internal form */
177static int rc_rcsrt[16] = {
178 0, TTY_OE, TTY_FE,
179 TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE,
180 TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI,
181 TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE,
182 TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE,
183 TTY_BI|TTY_PE|TTY_FE|TTY_OE
184};
185
186/* Static prototypes */
187static ointhand2_t rcintr;
188static void rc_hwreset __P((int, int, unsigned int));
189static int rc_test __P((int, int));
190static void rc_discard_output __P((struct rc_chans *));
191static void rc_hardclose __P((struct rc_chans *));
192static int rc_modctl __P((struct rc_chans *, int, int));
193static void rc_start __P((struct tty *));
194static int rc_param __P((struct tty *, struct termios *));
195static swihand_t rcpoll;
196static void rc_reinit __P((struct rc_softc *));
197#ifdef RCDEBUG
198static void printrcflags();
199#endif
200static timeout_t rc_dtrwakeup;
201static timeout_t rc_wakeup;
202static void disc_optim __P((struct tty *tp, struct termios *t, struct rc_chans *));
203static void rc_wait0 __P((int nec, int unit, int chan, int line));
204
205/**********************************************/
206
207/* Quick device probing */
208static int
209rcprobe(dvp)
210 struct isa_device *dvp;
211{
212 int irq = ffs(dvp->id_irq) - 1;
213 register int nec = dvp->id_iobase;
214
215 if (dvp->id_unit > NRC)
216 return 0;
217 if (!RC_VALIDADDR(nec)) {
218 printf("rc%d: illegal base address %x\n", dvp->id_unit, nec);
219 return 0;
220 }
221 if (!RC_VALIDIRQ(irq)) {
222 printf("rc%d: illegal IRQ value %d\n", dvp->id_unit, irq);
223 return 0;
224 }
225 rcout(CD180_PPRL, 0x22); /* Random values to Prescale reg. */
226 rcout(CD180_PPRH, 0x11);
227 if (rcin(CD180_PPRL) != 0x22 || rcin(CD180_PPRH) != 0x11)
228 return 0;
229 /* Now, test the board more thoroughly, with diagnostic */
230 if (rc_test(nec, dvp->id_unit))
231 return 0;
232 rc_softc[dvp->id_unit].rcb_probed = RC_PROBED;
233
234 return 0xF;
235}
236
237static int
238rcattach(dvp)
239 struct isa_device *dvp;
240{
241 register int chan, nec = dvp->id_iobase;
242 struct rc_softc *rcb = &rc_softc[dvp->id_unit];
243 struct rc_chans *rc = &rc_chans[dvp->id_unit * CD180_NCHAN];
244 static int rc_started = 0;
245 struct tty *tp;
246
247 dvp->id_ointr = rcintr;
248
249 /* Thorooughly test the device */
250 if (rcb->rcb_probed != RC_PROBED)
251 return 0;
252 rcb->rcb_addr = nec;
253 rcb->rcb_dtr = 0;
254 rcb->rcb_baserc = rc;
255 rcb->rcb_unit = dvp->id_unit;
256 /*rcb->rcb_chipid = 0x10 + dvp->id_unit;*/
257 printf("rc%d: %d chans, firmware rev. %c\n", rcb->rcb_unit,
258 CD180_NCHAN, (rcin(CD180_GFRCR) & 0xF) + 'A');
259
260 for (chan = 0; chan < CD180_NCHAN; chan++, rc++) {
261 rc->rc_rcb = rcb;
262 rc->rc_chan = chan;
263 rc->rc_iptr = rc->rc_ibuf;
264 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];
265 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER];
266 rc->rc_flags = rc->rc_ier = rc->rc_msvr = 0;
267 rc->rc_cor2 = rc->rc_pendcmd = 0;
268 rc->rc_optr = rc->rc_obufend = rc->rc_obuf;
269 rc->rc_dtrwait = 3 * hz;
270 rc->rc_dcdwaits= 0;
271 rc->rc_hotchar = 0;
272 tp = rc->rc_tp = &rc_tty[chan + (dvp->id_unit * CD180_NCHAN)];
273 ttychars(tp);
274 tp->t_lflag = tp->t_iflag = tp->t_oflag = 0;
275 tp->t_cflag = TTYDEF_CFLAG;
276 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
145} rc_chans[NRC * CD180_NCHAN];
146
147static int rc_scheduled_event = 0;
148
149/* for pstat -t */
150static struct tty rc_tty[NRC * CD180_NCHAN];
151static const int nrc_tty = NRC * CD180_NCHAN;
152
153/* Flags */
154#define RC_DTR_OFF 0x0001 /* DTR wait, for close/open */
155#define RC_ACTOUT 0x0002 /* Dial-out port active */
156#define RC_RTSFLOW 0x0004 /* RTS flow ctl enabled */
157#define RC_CTSFLOW 0x0008 /* CTS flow ctl enabled */
158#define RC_DORXFER 0x0010 /* RXFER event planned */
159#define RC_DOXXFER 0x0020 /* XXFER event planned */
160#define RC_MODCHG 0x0040 /* Modem status changed */
161#define RC_OSUSP 0x0080 /* Output suspended */
162#define RC_OSBUSY 0x0100 /* start() routine in progress */
163#define RC_WAS_BUFOVFL 0x0200 /* low-level buffer ovferflow */
164#define RC_WAS_SILOVFL 0x0400 /* silo buffer overflow */
165#define RC_SEND_RDY 0x0800 /* ready to send */
166
167/* Table for translation of RCSR status bits to internal form */
168static int rc_rcsrt[16] = {
169 0, TTY_OE, TTY_FE,
170 TTY_FE|TTY_OE, TTY_PE, TTY_PE|TTY_OE,
171 TTY_PE|TTY_FE, TTY_PE|TTY_FE|TTY_OE, TTY_BI,
172 TTY_BI|TTY_OE, TTY_BI|TTY_FE, TTY_BI|TTY_FE|TTY_OE,
173 TTY_BI|TTY_PE, TTY_BI|TTY_PE|TTY_OE, TTY_BI|TTY_PE|TTY_FE,
174 TTY_BI|TTY_PE|TTY_FE|TTY_OE
175};
176
177/* Static prototypes */
178static ointhand2_t rcintr;
179static void rc_hwreset __P((int, int, unsigned int));
180static int rc_test __P((int, int));
181static void rc_discard_output __P((struct rc_chans *));
182static void rc_hardclose __P((struct rc_chans *));
183static int rc_modctl __P((struct rc_chans *, int, int));
184static void rc_start __P((struct tty *));
185static int rc_param __P((struct tty *, struct termios *));
186static swihand_t rcpoll;
187static void rc_reinit __P((struct rc_softc *));
188#ifdef RCDEBUG
189static void printrcflags();
190#endif
191static timeout_t rc_dtrwakeup;
192static timeout_t rc_wakeup;
193static void disc_optim __P((struct tty *tp, struct termios *t, struct rc_chans *));
194static void rc_wait0 __P((int nec, int unit, int chan, int line));
195
196/**********************************************/
197
198/* Quick device probing */
199static int
200rcprobe(dvp)
201 struct isa_device *dvp;
202{
203 int irq = ffs(dvp->id_irq) - 1;
204 register int nec = dvp->id_iobase;
205
206 if (dvp->id_unit > NRC)
207 return 0;
208 if (!RC_VALIDADDR(nec)) {
209 printf("rc%d: illegal base address %x\n", dvp->id_unit, nec);
210 return 0;
211 }
212 if (!RC_VALIDIRQ(irq)) {
213 printf("rc%d: illegal IRQ value %d\n", dvp->id_unit, irq);
214 return 0;
215 }
216 rcout(CD180_PPRL, 0x22); /* Random values to Prescale reg. */
217 rcout(CD180_PPRH, 0x11);
218 if (rcin(CD180_PPRL) != 0x22 || rcin(CD180_PPRH) != 0x11)
219 return 0;
220 /* Now, test the board more thoroughly, with diagnostic */
221 if (rc_test(nec, dvp->id_unit))
222 return 0;
223 rc_softc[dvp->id_unit].rcb_probed = RC_PROBED;
224
225 return 0xF;
226}
227
228static int
229rcattach(dvp)
230 struct isa_device *dvp;
231{
232 register int chan, nec = dvp->id_iobase;
233 struct rc_softc *rcb = &rc_softc[dvp->id_unit];
234 struct rc_chans *rc = &rc_chans[dvp->id_unit * CD180_NCHAN];
235 static int rc_started = 0;
236 struct tty *tp;
237
238 dvp->id_ointr = rcintr;
239
240 /* Thorooughly test the device */
241 if (rcb->rcb_probed != RC_PROBED)
242 return 0;
243 rcb->rcb_addr = nec;
244 rcb->rcb_dtr = 0;
245 rcb->rcb_baserc = rc;
246 rcb->rcb_unit = dvp->id_unit;
247 /*rcb->rcb_chipid = 0x10 + dvp->id_unit;*/
248 printf("rc%d: %d chans, firmware rev. %c\n", rcb->rcb_unit,
249 CD180_NCHAN, (rcin(CD180_GFRCR) & 0xF) + 'A');
250
251 for (chan = 0; chan < CD180_NCHAN; chan++, rc++) {
252 rc->rc_rcb = rcb;
253 rc->rc_chan = chan;
254 rc->rc_iptr = rc->rc_ibuf;
255 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];
256 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER];
257 rc->rc_flags = rc->rc_ier = rc->rc_msvr = 0;
258 rc->rc_cor2 = rc->rc_pendcmd = 0;
259 rc->rc_optr = rc->rc_obufend = rc->rc_obuf;
260 rc->rc_dtrwait = 3 * hz;
261 rc->rc_dcdwaits= 0;
262 rc->rc_hotchar = 0;
263 tp = rc->rc_tp = &rc_tty[chan + (dvp->id_unit * CD180_NCHAN)];
264 ttychars(tp);
265 tp->t_lflag = tp->t_iflag = tp->t_oflag = 0;
266 tp->t_cflag = TTYDEF_CFLAG;
267 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
277#ifdef DEVFS
278/* FIX THIS to reflect real devices */
279 rc->devfs_token =
280 devfs_add_devswf(&rc_cdevsw,
281 (dvp->id_unit * CD180_NCHAN) + chan,
282 DV_CHR, 0, 0, 0600, "rc%d.%d",
283 dvp->id_unit, chan);
284#endif
285 }
286 rcb->rcb_probed = RC_ATTACHED;
287 if (!rc_started) {
288 cdevsw_add(&rc_cdevsw);
289 register_swi(SWI_TTY, rcpoll);
290 rc_wakeup((void *)NULL);
291 rc_started = 1;
292 }
293 return 1;
294}
295
296/* RC interrupt handling */
297static void
298rcintr(unit)
299 int unit;
300{
301 register struct rc_softc *rcb = &rc_softc[unit];
302 register struct rc_chans *rc;
303 register int nec, resid;
304 register u_char val, iack, bsr, ucnt, *optr;
305 int good_data, t_state;
306
307 if (rcb->rcb_probed != RC_ATTACHED) {
308 printf("rc%d: bogus interrupt\n", unit);
309 return;
310 }
311 nec = rcb->rcb_addr;
312
313 bsr = ~(rcin(RC_BSR));
314
315 if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) {
316 printf("rc%d: extra interrupt\n", unit);
317 rcout(CD180_EOIR, 0);
318 return;
319 }
320
321 while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) {
322#ifdef RCDEBUG_DETAILED
323 printf("rc%d: intr (%02x) %s%s%s%s\n", unit, bsr,
324 (bsr & RC_BSR_TOUT)?"TOUT ":"",
325 (bsr & RC_BSR_RXINT)?"RXINT ":"",
326 (bsr & RC_BSR_TXINT)?"TXINT ":"",
327 (bsr & RC_BSR_MOINT)?"MOINT":"");
328#endif
329 if (bsr & RC_BSR_TOUT) {
330 printf("rc%d: hardware failure, reset board\n", unit);
331 rcout(RC_CTOUT, 0);
332 rc_reinit(rcb);
333 return;
334 }
335 if (bsr & RC_BSR_RXINT) {
336 iack = rcin(RC_PILR_RX);
337 good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID));
338 if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) {
339 printf("rc%d: fake rxint: %02x\n", unit, iack);
340 goto more_intrs;
341 }
342 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
343 t_state = rc->rc_tp->t_state;
344 /* Do RTS flow control stuff */
345 if ( (rc->rc_flags & RC_RTSFLOW)
346 || !(t_state & TS_ISOPEN)
347 ) {
348 if ( ( !(t_state & TS_ISOPEN)
349 || (t_state & TS_TBLOCK)
350 )
351 && (rc->rc_msvr & MSVR_RTS)
352 )
353 rcout(CD180_MSVR,
354 rc->rc_msvr &= ~MSVR_RTS);
355 else if (!(rc->rc_msvr & MSVR_RTS))
356 rcout(CD180_MSVR,
357 rc->rc_msvr |= MSVR_RTS);
358 }
359 ucnt = rcin(CD180_RDCR) & 0xF;
360 resid = 0;
361
362 if (t_state & TS_ISOPEN) {
363 /* check for input buffer overflow */
364 if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) {
365 resid = ucnt;
366 ucnt = rc->rc_bufend - rc->rc_iptr;
367 resid -= ucnt;
368 if (!(rc->rc_flags & RC_WAS_BUFOVFL)) {
369 rc->rc_flags |= RC_WAS_BUFOVFL;
370 rc_scheduled_event++;
371 }
372 }
373 optr = rc->rc_iptr;
374 /* check foor good data */
375 if (good_data) {
376 while (ucnt-- > 0) {
377 val = rcin(CD180_RDR);
378 optr[0] = val;
379 optr[INPUT_FLAGS_SHIFT] = 0;
380 optr++;
381 rc_scheduled_event++;
382 if (val != 0 && val == rc->rc_hotchar)
383 setsofttty();
384 }
385 } else {
386 /* Store also status data */
387 while (ucnt-- > 0) {
388 iack = rcin(CD180_RCSR);
389 if (iack & RCSR_Timeout)
390 break;
391 if ( (iack & RCSR_OE)
392 && !(rc->rc_flags & RC_WAS_SILOVFL)) {
393 rc->rc_flags |= RC_WAS_SILOVFL;
394 rc_scheduled_event++;
395 }
396 val = rcin(CD180_RDR);
397 /*
398 Don't store PE if IGNPAR and BREAK if IGNBRK,
399 this hack allows "raw" tty optimization
400 works even if IGN* is set.
401 */
402 if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break))
403 || ((!(iack & (RCSR_PE|RCSR_FE))
404 || !(rc->rc_tp->t_iflag & IGNPAR))
405 && (!(iack & RCSR_Break)
406 || !(rc->rc_tp->t_iflag & IGNBRK)))) {
407 if ( (iack & (RCSR_PE|RCSR_FE))
408 && (t_state & TS_CAN_BYPASS_L_RINT)
409 && ((iack & RCSR_FE)
410 || ((iack & RCSR_PE)
411 && (rc->rc_tp->t_iflag & INPCK))))
412 val = 0;
413 else if (val != 0 && val == rc->rc_hotchar)
414 setsofttty();
415 optr[0] = val;
416 optr[INPUT_FLAGS_SHIFT] = iack;
417 optr++;
418 rc_scheduled_event++;
419 }
420 }
421 }
422 rc->rc_iptr = optr;
423 rc->rc_flags |= RC_DORXFER;
424 } else
425 resid = ucnt;
426 /* Clear FIFO if necessary */
427 while (resid-- > 0) {
428 if (!good_data)
429 iack = rcin(CD180_RCSR);
430 else
431 iack = 0;
432 if (iack & RCSR_Timeout)
433 break;
434 (void) rcin(CD180_RDR);
435 }
436 goto more_intrs;
437 }
438 if (bsr & RC_BSR_MOINT) {
439 iack = rcin(RC_PILR_MODEM);
440 if (iack != (GIVR_IT_MSCI | RC_FAKEID)) {
441 printf("rc%d: fake moint: %02x\n", unit, iack);
442 goto more_intrs;
443 }
444 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
445 iack = rcin(CD180_MCR);
446 rc->rc_msvr = rcin(CD180_MSVR);
447 rcout(CD180_MCR, 0);
448#ifdef RCDEBUG
449 printrcflags(rc, "moint");
450#endif
451 if (rc->rc_flags & RC_CTSFLOW) {
452 if (rc->rc_msvr & MSVR_CTS)
453 rc->rc_flags |= RC_SEND_RDY;
454 else
455 rc->rc_flags &= ~RC_SEND_RDY;
456 } else
457 rc->rc_flags |= RC_SEND_RDY;
458 if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) {
459 rc_scheduled_event += LOTS_OF_EVENTS;
460 rc->rc_flags |= RC_MODCHG;
461 setsofttty();
462 }
463 goto more_intrs;
464 }
465 if (bsr & RC_BSR_TXINT) {
466 iack = rcin(RC_PILR_TX);
467 if (iack != (GIVR_IT_TDI | RC_FAKEID)) {
468 printf("rc%d: fake txint: %02x\n", unit, iack);
469 goto more_intrs;
470 }
471 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
472 if ( (rc->rc_flags & RC_OSUSP)
473 || !(rc->rc_flags & RC_SEND_RDY)
474 )
475 goto more_intrs;
476 /* Handle breaks and other stuff */
477 if (rc->rc_pendcmd) {
478 rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC);
479 rcout(CD180_TDR, CD180_C_ESC);
480 rcout(CD180_TDR, rc->rc_pendcmd);
481 rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC);
482 rc->rc_pendcmd = 0;
483 goto more_intrs;
484 }
485 optr = rc->rc_optr;
486 resid = rc->rc_obufend - optr;
487 if (resid > CD180_NFIFO)
488 resid = CD180_NFIFO;
489 while (resid-- > 0)
490 rcout(CD180_TDR, *optr++);
491 rc->rc_optr = optr;
492
493 /* output completed? */
494 if (optr >= rc->rc_obufend) {
495 rcout(CD180_IER, rc->rc_ier &= ~IER_TxRdy);
496#ifdef RCDEBUG
497 printf("rc%d/%d: output completed\n", unit, rc->rc_chan);
498#endif
499 if (!(rc->rc_flags & RC_DOXXFER)) {
500 rc_scheduled_event += LOTS_OF_EVENTS;
501 rc->rc_flags |= RC_DOXXFER;
502 setsofttty();
503 }
504 }
505 }
506 more_intrs:
507 rcout(CD180_EOIR, 0); /* end of interrupt */
508 rcout(RC_CTOUT, 0);
509 bsr = ~(rcin(RC_BSR));
510 }
511}
512
513/* Feed characters to output buffer */
514static void rc_start(tp)
515register struct tty *tp;
516{
517 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
518 register int nec = rc->rc_rcb->rcb_addr, s;
519
520 if (rc->rc_flags & RC_OSBUSY)
521 return;
522 s = spltty();
523 rc->rc_flags |= RC_OSBUSY;
524 disable_intr();
525 if (tp->t_state & TS_TTSTOP)
526 rc->rc_flags |= RC_OSUSP;
527 else
528 rc->rc_flags &= ~RC_OSUSP;
529 /* Do RTS flow control stuff */
530 if ( (rc->rc_flags & RC_RTSFLOW)
531 && (tp->t_state & TS_TBLOCK)
532 && (rc->rc_msvr & MSVR_RTS)
533 ) {
534 rcout(CD180_CAR, rc->rc_chan);
535 rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS);
536 } else if (!(rc->rc_msvr & MSVR_RTS)) {
537 rcout(CD180_CAR, rc->rc_chan);
538 rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS);
539 }
540 enable_intr();
541 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
542 goto out;
543#ifdef RCDEBUG
544 printrcflags(rc, "rcstart");
545#endif
546 ttwwakeup(tp);
547#ifdef RCDEBUG
548 printf("rcstart: outq = %d obuf = %d\n",
549 tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr);
550#endif
551 if (tp->t_state & TS_BUSY)
552 goto out; /* output still in progress ... */
553
554 if (tp->t_outq.c_cc > 0) {
555 u_int ocnt;
556
557 tp->t_state |= TS_BUSY;
558 ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf);
559 disable_intr();
560 rc->rc_optr = rc->rc_obuf;
561 rc->rc_obufend = rc->rc_optr + ocnt;
562 enable_intr();
563 if (!(rc->rc_ier & IER_TxRdy)) {
564#ifdef RCDEBUG
565 printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan);
566#endif
567 rcout(CD180_CAR, rc->rc_chan);
568 rcout(CD180_IER, rc->rc_ier |= IER_TxRdy);
569 }
570 }
571out:
572 rc->rc_flags &= ~RC_OSBUSY;
573 (void) splx(s);
574}
575
576/* Handle delayed events. */
577void rcpoll()
578{
579 register struct rc_chans *rc;
580 register struct rc_softc *rcb;
581 register u_char *tptr, *eptr;
582 register struct tty *tp;
583 register int chan, icnt, nec, unit;
584
585 if (rc_scheduled_event == 0)
586 return;
587repeat:
588 for (unit = 0; unit < NRC; unit++) {
589 rcb = &rc_softc[unit];
590 rc = rcb->rcb_baserc;
591 nec = rc->rc_rcb->rcb_addr;
592 for (chan = 0; chan < CD180_NCHAN; rc++, chan++) {
593 tp = rc->rc_tp;
594#ifdef RCDEBUG
595 if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG|
596 RC_WAS_BUFOVFL|RC_WAS_SILOVFL))
597 printrcflags(rc, "rcevent");
598#endif
599 if (rc->rc_flags & RC_WAS_BUFOVFL) {
600 disable_intr();
601 rc->rc_flags &= ~RC_WAS_BUFOVFL;
602 rc_scheduled_event--;
603 enable_intr();
604 printf("rc%d/%d: interrupt-level buffer overflow\n",
605 unit, chan);
606 }
607 if (rc->rc_flags & RC_WAS_SILOVFL) {
608 disable_intr();
609 rc->rc_flags &= ~RC_WAS_SILOVFL;
610 rc_scheduled_event--;
611 enable_intr();
612 printf("rc%d/%d: silo overflow\n",
613 unit, chan);
614 }
615 if (rc->rc_flags & RC_MODCHG) {
616 disable_intr();
617 rc->rc_flags &= ~RC_MODCHG;
618 rc_scheduled_event -= LOTS_OF_EVENTS;
619 enable_intr();
620 (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD));
621 }
622 if (rc->rc_flags & RC_DORXFER) {
623 disable_intr();
624 rc->rc_flags &= ~RC_DORXFER;
625 eptr = rc->rc_iptr;
626 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE])
627 tptr = &rc->rc_ibuf[RC_IBUFSIZE];
628 else
629 tptr = rc->rc_ibuf;
630 icnt = eptr - tptr;
631 if (icnt > 0) {
632 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
633 rc->rc_iptr = rc->rc_ibuf;
634 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];
635 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER];
636 } else {
637 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];
638 rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE];
639 rc->rc_hiwat =
640 &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER];
641 }
642 if ( (rc->rc_flags & RC_RTSFLOW)
643 && (tp->t_state & TS_ISOPEN)
644 && !(tp->t_state & TS_TBLOCK)
645 && !(rc->rc_msvr & MSVR_RTS)
646 ) {
647 rcout(CD180_CAR, chan);
648 rcout(CD180_MSVR,
649 rc->rc_msvr |= MSVR_RTS);
650 }
651 rc_scheduled_event -= icnt;
652 }
653 enable_intr();
654
655 if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))
656 goto done1;
657
658 if ( (tp->t_state & TS_CAN_BYPASS_L_RINT)
659 && !(tp->t_state & TS_LOCAL)) {
660 if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER
661 && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
662 && !(tp->t_state & TS_TBLOCK))
663 ttyblock(tp);
664 tk_nin += icnt;
665 tk_rawcc += icnt;
666 tp->t_rawcc += icnt;
667 if (b_to_q(tptr, icnt, &tp->t_rawq))
668 printf("rc%d/%d: tty-level buffer overflow\n",
669 unit, chan);
670 ttwakeup(tp);
671 if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY)
672 || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) {
673 tp->t_state &= ~TS_TTSTOP;
674 tp->t_lflag &= ~FLUSHO;
675 rc_start(tp);
676 }
677 } else {
678 for (; tptr < eptr; tptr++)
679 (*linesw[tp->t_line].l_rint)
680 (tptr[0] |
681 rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp);
682 }
683done1: ;
684 }
685 if (rc->rc_flags & RC_DOXXFER) {
686 disable_intr();
687 rc_scheduled_event -= LOTS_OF_EVENTS;
688 rc->rc_flags &= ~RC_DOXXFER;
689 rc->rc_tp->t_state &= ~TS_BUSY;
690 enable_intr();
691 (*linesw[tp->t_line].l_start)(tp);
692 }
693 }
694 if (rc_scheduled_event == 0)
695 break;
696 }
697 if (rc_scheduled_event >= LOTS_OF_EVENTS)
698 goto repeat;
699}
700
701static void
702rcstop(tp, rw)
703 register struct tty *tp;
704 int rw;
705{
706 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
707 u_char *tptr, *eptr;
708
709#ifdef RCDEBUG
710 printf("rc%d/%d: rcstop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan,
711 (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":"");
712#endif
713 if (rw & FWRITE)
714 rc_discard_output(rc);
715 disable_intr();
716 if (rw & FREAD) {
717 rc->rc_flags &= ~RC_DORXFER;
718 eptr = rc->rc_iptr;
719 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
720 tptr = &rc->rc_ibuf[RC_IBUFSIZE];
721 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];
722 } else {
723 tptr = rc->rc_ibuf;
724 rc->rc_iptr = rc->rc_ibuf;
725 }
726 rc_scheduled_event -= eptr - tptr;
727 }
728 if (tp->t_state & TS_TTSTOP)
729 rc->rc_flags |= RC_OSUSP;
730 else
731 rc->rc_flags &= ~RC_OSUSP;
732 enable_intr();
733}
734
735static int
736rcopen(dev, flag, mode, p)
737 dev_t dev;
738 int flag, mode;
739 struct proc *p;
740{
741 register struct rc_chans *rc;
742 register struct tty *tp;
743 int unit, nec, s, error = 0;
744
745 unit = GET_UNIT(dev);
746 if (unit >= NRC * CD180_NCHAN)
747 return ENXIO;
748 if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED)
749 return ENXIO;
750 rc = &rc_chans[unit];
751 tp = rc->rc_tp;
752 nec = rc->rc_rcb->rcb_addr;
753#ifdef RCDEBUG
754 printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
755#endif
756 s = spltty();
757
758again:
759 while (rc->rc_flags & RC_DTR_OFF) {
760 error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0);
761 if (error != 0)
762 goto out;
763 }
764 if (tp->t_state & TS_ISOPEN) {
765 if (CALLOUT(dev)) {
766 if (!(rc->rc_flags & RC_ACTOUT)) {
767 error = EBUSY;
768 goto out;
769 }
770 } else {
771 if (rc->rc_flags & RC_ACTOUT) {
772 if (flag & O_NONBLOCK) {
773 error = EBUSY;
774 goto out;
775 }
776 error = tsleep(&rc->rc_rcb,
777 TTIPRI|PCATCH, "rcbi", 0);
778 if (error)
779 goto out;
780 goto again;
781 }
782 }
783 if (tp->t_state & TS_XCLUDE &&
784 suser(p)) {
785 error = EBUSY;
786 goto out;
787 }
788 } else {
789 tp->t_oproc = rc_start;
790 tp->t_param = rc_param;
791 tp->t_dev = dev;
792
793 if (CALLOUT(dev))
794 tp->t_cflag |= CLOCAL;
795 else
796 tp->t_cflag &= ~CLOCAL;
797
798 error = rc_param(tp, &tp->t_termios);
799 if (error)
800 goto out;
801 (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET);
802
803 if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev))
804 (*linesw[tp->t_line].l_modem)(tp, 1);
805 }
806 if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev)
807 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
808 rc->rc_dcdwaits++;
809 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0);
810 rc->rc_dcdwaits--;
811 if (error != 0)
812 goto out;
813 goto again;
814 }
815 error = (*linesw[tp->t_line].l_open)(dev, tp);
816 disc_optim(tp, &tp->t_termios, rc);
817 if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev))
818 rc->rc_flags |= RC_ACTOUT;
819out:
820 (void) splx(s);
821
822 if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN))
823 rc_hardclose(rc);
824
825 return error;
826}
827
828static int
829rcclose(dev, flag, mode, p)
830 dev_t dev;
831 int flag, mode;
832 struct proc *p;
833{
834 register struct rc_chans *rc;
835 register struct tty *tp;
836 int s, unit = GET_UNIT(dev);
837
838 if (unit >= NRC * CD180_NCHAN)
839 return ENXIO;
840 rc = &rc_chans[unit];
841 tp = rc->rc_tp;
842#ifdef RCDEBUG
843 printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
844#endif
845 s = spltty();
846 (*linesw[tp->t_line].l_close)(tp, flag);
847 disc_optim(tp, &tp->t_termios, rc);
848 rcstop(tp, FREAD | FWRITE);
849 rc_hardclose(rc);
850 ttyclose(tp);
851 splx(s);
852 return 0;
853}
854
855static void rc_hardclose(rc)
856register struct rc_chans *rc;
857{
858 register int s, nec = rc->rc_rcb->rcb_addr;
859 register struct tty *tp = rc->rc_tp;
860
861 s = spltty();
862 rcout(CD180_CAR, rc->rc_chan);
863
864 /* Disable rx/tx intrs */
865 rcout(CD180_IER, rc->rc_ier = 0);
866 if ( (tp->t_cflag & HUPCL)
867 || (!(rc->rc_flags & RC_ACTOUT)
868 && !(rc->rc_msvr & MSVR_CD)
869 && !(tp->t_cflag & CLOCAL))
870 || !(tp->t_state & TS_ISOPEN)
871 ) {
872 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
873 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
874 (void) rc_modctl(rc, TIOCM_RTS, DMSET);
875 if (rc->rc_dtrwait) {
876 timeout(rc_dtrwakeup, rc, rc->rc_dtrwait);
877 rc->rc_flags |= RC_DTR_OFF;
878 }
879 }
880 rc->rc_flags &= ~RC_ACTOUT;
881 wakeup((caddr_t) &rc->rc_rcb); /* wake bi */
882 wakeup(TSA_CARR_ON(tp));
883 (void) splx(s);
884}
885
886/* Read from line */
887static int
888rcread(dev, uio, flag)
889 dev_t dev;
890 struct uio *uio;
891 int flag;
892{
893 struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;
894
895 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
896}
897
898/* Write to line */
899static int
900rcwrite(dev, uio, flag)
901 dev_t dev;
902 struct uio *uio;
903 int flag;
904{
905 struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;
906
907 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
908}
909
910/* Reset the bastard */
911static void rc_hwreset(unit, nec, chipid)
912 register int unit, nec;
913 unsigned int chipid;
914{
915 CCRCMD(unit, -1, CCR_HWRESET); /* Hardware reset */
916 DELAY(20000);
917 WAITFORCCR(unit, -1);
918
919 rcout(RC_CTOUT, 0); /* Clear timeout */
920 rcout(CD180_GIVR, chipid);
921 rcout(CD180_GICR, 0);
922
923 /* Set Prescaler Registers (1 msec) */
924 rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF);
925 rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8);
926
927 /* Initialize Priority Interrupt Level Registers */
928 rcout(CD180_PILR1, RC_PILR_MODEM);
929 rcout(CD180_PILR2, RC_PILR_TX);
930 rcout(CD180_PILR3, RC_PILR_RX);
931
932 /* Reset DTR */
933 rcout(RC_DTREG, ~0);
934}
935
936/* Set channel parameters */
937static int rc_param(tp, ts)
938 register struct tty *tp;
939 struct termios *ts;
940{
941 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
942 register int nec = rc->rc_rcb->rcb_addr;
943 int idivs, odivs, s, val, cflag, iflag, lflag, inpflow;
944
945 if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800
946 || ts->c_ispeed < 0 || ts->c_ispeed > 76800
947 )
948 return (EINVAL);
949 if (ts->c_ispeed == 0)
950 ts->c_ispeed = ts->c_ospeed;
951 odivs = RC_BRD(ts->c_ospeed);
952 idivs = RC_BRD(ts->c_ispeed);
953
954 s = spltty();
955
956 /* Select channel */
957 rcout(CD180_CAR, rc->rc_chan);
958
959 /* If speed == 0, hangup line */
960 if (ts->c_ospeed == 0) {
961 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
962 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
963 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
964 }
965
966 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
967 cflag = ts->c_cflag;
968 iflag = ts->c_iflag;
969 lflag = ts->c_lflag;
970
971 if (idivs > 0) {
972 rcout(CD180_RBPRL, idivs & 0xFF);
973 rcout(CD180_RBPRH, idivs >> 8);
974 }
975 if (odivs > 0) {
976 rcout(CD180_TBPRL, odivs & 0xFF);
977 rcout(CD180_TBPRH, odivs >> 8);
978 }
979
980 /* set timeout value */
981 if (ts->c_ispeed > 0) {
982 int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1;
983
984 if ( !(lflag & ICANON)
985 && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0
986 && ts->c_cc[VTIME] * 10 > itm)
987 itm = ts->c_cc[VTIME] * 10;
988
989 rcout(CD180_RTPR, itm <= 255 ? itm : 255);
990 }
991
992 switch (cflag & CSIZE) {
993 case CS5: val = COR1_5BITS; break;
994 case CS6: val = COR1_6BITS; break;
995 case CS7: val = COR1_7BITS; break;
996 default:
997 case CS8: val = COR1_8BITS; break;
998 }
999 if (cflag & PARENB) {
1000 val |= COR1_NORMPAR;
1001 if (cflag & PARODD)
1002 val |= COR1_ODDP;
1003 if (!(cflag & INPCK))
1004 val |= COR1_Ignore;
1005 } else
1006 val |= COR1_Ignore;
1007 if (cflag & CSTOPB)
1008 val |= COR1_2SB;
1009 rcout(CD180_COR1, val);
1010
1011 /* Set FIFO threshold */
1012 val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2;
1013 inpflow = 0;
1014 if ( (iflag & IXOFF)
1015 && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE
1016 && ( ts->c_cc[VSTART] != _POSIX_VDISABLE
1017 || (iflag & IXANY)
1018 )
1019 )
1020 ) {
1021 inpflow = 1;
1022 val |= COR3_SCDE|COR3_FCT;
1023 }
1024 rcout(CD180_COR3, val);
1025
1026 /* Initialize on-chip automatic flow control */
1027 val = 0;
1028 rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY);
1029 if (cflag & CCTS_OFLOW) {
1030 rc->rc_flags |= RC_CTSFLOW;
1031 val |= COR2_CtsAE;
1032 } else
1033 rc->rc_flags |= RC_SEND_RDY;
1034 if (tp->t_state & TS_TTSTOP)
1035 rc->rc_flags |= RC_OSUSP;
1036 else
1037 rc->rc_flags &= ~RC_OSUSP;
1038 if (cflag & CRTS_IFLOW)
1039 rc->rc_flags |= RC_RTSFLOW;
1040 else
1041 rc->rc_flags &= ~RC_RTSFLOW;
1042
1043 if (inpflow) {
1044 if (ts->c_cc[VSTART] != _POSIX_VDISABLE)
1045 rcout(CD180_SCHR1, ts->c_cc[VSTART]);
1046 rcout(CD180_SCHR2, ts->c_cc[VSTOP]);
1047 val |= COR2_TxIBE;
1048 if (iflag & IXANY)
1049 val |= COR2_IXM;
1050 }
1051
1052 rcout(CD180_COR2, rc->rc_cor2 = val);
1053
1054 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
1055 CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1056
1057 disc_optim(tp, ts, rc);
1058
1059 /* modem ctl */
1060 val = cflag & CLOCAL ? 0 : MCOR1_CDzd;
1061 if (cflag & CCTS_OFLOW)
1062 val |= MCOR1_CTSzd;
1063 rcout(CD180_MCOR1, val);
1064
1065 val = cflag & CLOCAL ? 0 : MCOR2_CDod;
1066 if (cflag & CCTS_OFLOW)
1067 val |= MCOR2_CTSod;
1068 rcout(CD180_MCOR2, val);
1069
1070 /* enable i/o and interrupts */
1071 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
1072 CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS));
1073 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
1074
1075 rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD;
1076 if (cflag & CCTS_OFLOW)
1077 rc->rc_ier |= IER_CTS;
1078 if (cflag & CREAD)
1079 rc->rc_ier |= IER_RxData;
1080 if (tp->t_state & TS_BUSY)
1081 rc->rc_ier |= IER_TxRdy;
1082 if (ts->c_ospeed != 0)
1083 rc_modctl(rc, TIOCM_DTR, DMBIS);
1084 if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS))
1085 rc->rc_flags |= RC_SEND_RDY;
1086 rcout(CD180_IER, rc->rc_ier);
1087 (void) splx(s);
1088 return 0;
1089}
1090
1091/* Re-initialize board after bogus interrupts */
1092static void rc_reinit(rcb)
1093struct rc_softc *rcb;
1094{
1095 register struct rc_chans *rc, *rce;
1096 register int nec;
1097
1098 nec = rcb->rcb_addr;
1099 rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID);
1100 rc = &rc_chans[rcb->rcb_unit * CD180_NCHAN];
1101 rce = rc + CD180_NCHAN;
1102 for (; rc < rce; rc++)
1103 (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios);
1104}
1105
1106static int
1107rcioctl(dev, cmd, data, flag, p)
1108dev_t dev;
1109u_long cmd;
1110int flag;
1111caddr_t data;
1112struct proc *p;
1113{
1114 register struct rc_chans *rc = &rc_chans[GET_UNIT(dev)];
1115 register int s, error;
1116 struct tty *tp = rc->rc_tp;
1117
1118 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1119 if (error != ENOIOCTL)
1120 return (error);
1121 error = ttioctl(tp, cmd, data, flag);
1122 disc_optim(tp, &tp->t_termios, rc);
1123 if (error != ENOIOCTL)
1124 return (error);
1125 s = spltty();
1126
1127 switch (cmd) {
1128 case TIOCSBRK:
1129 rc->rc_pendcmd = CD180_C_SBRK;
1130 break;
1131
1132 case TIOCCBRK:
1133 rc->rc_pendcmd = CD180_C_EBRK;
1134 break;
1135
1136 case TIOCSDTR:
1137 (void) rc_modctl(rc, TIOCM_DTR, DMBIS);
1138 break;
1139
1140 case TIOCCDTR:
1141 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
1142 break;
1143
1144 case TIOCMGET:
1145 *(int *) data = rc_modctl(rc, 0, DMGET);
1146 break;
1147
1148 case TIOCMSET:
1149 (void) rc_modctl(rc, *(int *) data, DMSET);
1150 break;
1151
1152 case TIOCMBIC:
1153 (void) rc_modctl(rc, *(int *) data, DMBIC);
1154 break;
1155
1156 case TIOCMBIS:
1157 (void) rc_modctl(rc, *(int *) data, DMBIS);
1158 break;
1159
1160 case TIOCMSDTRWAIT:
1161 error = suser(p);
1162 if (error != 0) {
1163 splx(s);
1164 return (error);
1165 }
1166 rc->rc_dtrwait = *(int *)data * hz / 100;
1167 break;
1168
1169 case TIOCMGDTRWAIT:
1170 *(int *)data = rc->rc_dtrwait * 100 / hz;
1171 break;
1172
1173 default:
1174 (void) splx(s);
1175 return ENOTTY;
1176 }
1177 (void) splx(s);
1178 return 0;
1179}
1180
1181
1182/* Modem control routines */
1183
1184static int rc_modctl(rc, bits, cmd)
1185register struct rc_chans *rc;
1186int bits, cmd;
1187{
1188 register int nec = rc->rc_rcb->rcb_addr;
1189 u_char *dtr = &rc->rc_rcb->rcb_dtr, msvr;
1190
1191 rcout(CD180_CAR, rc->rc_chan);
1192
1193 switch (cmd) {
1194 case DMSET:
1195 rcout(RC_DTREG, (bits & TIOCM_DTR) ?
1196 ~(*dtr |= 1 << rc->rc_chan) :
1197 ~(*dtr &= ~(1 << rc->rc_chan)));
1198 msvr = rcin(CD180_MSVR);
1199 if (bits & TIOCM_RTS)
1200 msvr |= MSVR_RTS;
1201 else
1202 msvr &= ~MSVR_RTS;
1203 if (bits & TIOCM_DTR)
1204 msvr |= MSVR_DTR;
1205 else
1206 msvr &= ~MSVR_DTR;
1207 rcout(CD180_MSVR, msvr);
1208 break;
1209
1210 case DMBIS:
1211 if (bits & TIOCM_DTR)
1212 rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan));
1213 msvr = rcin(CD180_MSVR);
1214 if (bits & TIOCM_RTS)
1215 msvr |= MSVR_RTS;
1216 if (bits & TIOCM_DTR)
1217 msvr |= MSVR_DTR;
1218 rcout(CD180_MSVR, msvr);
1219 break;
1220
1221 case DMGET:
1222 bits = TIOCM_LE;
1223 msvr = rc->rc_msvr = rcin(CD180_MSVR);
1224
1225 if (msvr & MSVR_RTS)
1226 bits |= TIOCM_RTS;
1227 if (msvr & MSVR_CTS)
1228 bits |= TIOCM_CTS;
1229 if (msvr & MSVR_DSR)
1230 bits |= TIOCM_DSR;
1231 if (msvr & MSVR_DTR)
1232 bits |= TIOCM_DTR;
1233 if (msvr & MSVR_CD)
1234 bits |= TIOCM_CD;
1235 if (~rcin(RC_RIREG) & (1 << rc->rc_chan))
1236 bits |= TIOCM_RI;
1237 return bits;
1238
1239 case DMBIC:
1240 if (bits & TIOCM_DTR)
1241 rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan)));
1242 msvr = rcin(CD180_MSVR);
1243 if (bits & TIOCM_RTS)
1244 msvr &= ~MSVR_RTS;
1245 if (bits & TIOCM_DTR)
1246 msvr &= ~MSVR_DTR;
1247 rcout(CD180_MSVR, msvr);
1248 break;
1249 }
1250 rc->rc_msvr = rcin(CD180_MSVR);
1251 return 0;
1252}
1253
1254/* Test the board. */
1255int rc_test(nec, unit)
1256 register int nec;
1257 int unit;
1258{
1259 int chan = 0;
1260 int i = 0, rcnt, old_level;
1261 unsigned int iack, chipid;
1262 unsigned short divs;
1263 static u_char ctest[] = "\377\125\252\045\244\0\377";
1264#define CTLEN 8
1265#define ERR(s) { \
1266 printf("rc%d: ", unit); printf s ; printf("\n"); \
1267 (void) splx(old_level); return 1; }
1268
1269 struct rtest {
1270 u_char txbuf[CD180_NFIFO]; /* TX buffer */
1271 u_char rxbuf[CD180_NFIFO]; /* RX buffer */
1272 int rxptr; /* RX pointer */
1273 int txptr; /* TX pointer */
1274 } tchans[CD180_NCHAN];
1275
1276 old_level = spltty();
1277
1278 chipid = RC_FAKEID;
1279
1280 /* First, reset board to inital state */
1281 rc_hwreset(unit, nec, chipid);
1282
1283 divs = RC_BRD(19200);
1284
1285 /* Initialize channels */
1286 for (chan = 0; chan < CD180_NCHAN; chan++) {
1287
1288 /* Select and reset channel */
1289 rcout(CD180_CAR, chan);
1290 CCRCMD(unit, chan, CCR_ResetChan);
1291 WAITFORCCR(unit, chan);
1292
1293 /* Set speed */
1294 rcout(CD180_RBPRL, divs & 0xFF);
1295 rcout(CD180_RBPRH, divs >> 8);
1296 rcout(CD180_TBPRL, divs & 0xFF);
1297 rcout(CD180_TBPRH, divs >> 8);
1298
1299 /* set timeout value */
1300 rcout(CD180_RTPR, 0);
1301
1302 /* Establish local loopback */
1303 rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB);
1304 rcout(CD180_COR2, COR2_LLM);
1305 rcout(CD180_COR3, CD180_NFIFO);
1306 CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1307 CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN);
1308 WAITFORCCR(unit, chan);
1309 rcout(CD180_MSVR, MSVR_RTS);
1310
1311 /* Fill TXBUF with test data */
1312 for (i = 0; i < CD180_NFIFO; i++) {
1313 tchans[chan].txbuf[i] = ctest[i];
1314 tchans[chan].rxbuf[i] = 0;
1315 }
1316 tchans[chan].txptr = tchans[chan].rxptr = 0;
1317
1318 /* Now, start transmit */
1319 rcout(CD180_IER, IER_TxMpty|IER_RxData);
1320 }
1321 /* Pseudo-interrupt poll stuff */
1322 for (rcnt = 10000; rcnt-- > 0; rcnt--) {
1323 i = ~(rcin(RC_BSR));
1324 if (i & RC_BSR_TOUT)
1325 ERR(("BSR timeout bit set\n"))
1326 else if (i & RC_BSR_TXINT) {
1327 iack = rcin(RC_PILR_TX);
1328 if (iack != (GIVR_IT_TDI | chipid))
1329 ERR(("Bad TX intr ack (%02x != %02x)\n",
1330 iack, GIVR_IT_TDI | chipid));
1331 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
1332 /* If no more data to transmit, disable TX intr */
1333 if (tchans[chan].txptr >= CD180_NFIFO) {
1334 iack = rcin(CD180_IER);
1335 rcout(CD180_IER, iack & ~IER_TxMpty);
1336 } else {
1337 for (iack = tchans[chan].txptr;
1338 iack < CD180_NFIFO; iack++)
1339 rcout(CD180_TDR,
1340 tchans[chan].txbuf[iack]);
1341 tchans[chan].txptr = iack;
1342 }
1343 rcout(CD180_EOIR, 0);
1344 } else if (i & RC_BSR_RXINT) {
1345 u_char ucnt;
1346
1347 iack = rcin(RC_PILR_RX);
1348 if (iack != (GIVR_IT_RGDI | chipid) &&
1349 iack != (GIVR_IT_REI | chipid))
1350 ERR(("Bad RX intr ack (%02x != %02x)\n",
1351 iack, GIVR_IT_RGDI | chipid))
1352 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
1353 ucnt = rcin(CD180_RDCR) & 0xF;
1354 while (ucnt-- > 0) {
1355 iack = rcin(CD180_RCSR);
1356 if (iack & RCSR_Timeout)
1357 break;
1358 if (iack & 0xF)
1359 ERR(("Bad char chan %d (RCSR = %02X)\n",
1360 chan, iack))
1361 if (tchans[chan].rxptr > CD180_NFIFO)
1362 ERR(("Got extra chars chan %d\n",
1363 chan))
1364 tchans[chan].rxbuf[tchans[chan].rxptr++] =
1365 rcin(CD180_RDR);
1366 }
1367 rcout(CD180_EOIR, 0);
1368 }
1369 rcout(RC_CTOUT, 0);
1370 for (iack = chan = 0; chan < CD180_NCHAN; chan++)
1371 if (tchans[chan].rxptr >= CD180_NFIFO)
1372 iack++;
1373 if (iack == CD180_NCHAN)
1374 break;
1375 }
1376 for (chan = 0; chan < CD180_NCHAN; chan++) {
1377 /* Select and reset channel */
1378 rcout(CD180_CAR, chan);
1379 CCRCMD(unit, chan, CCR_ResetChan);
1380 }
1381
1382 if (!rcnt)
1383 ERR(("looses characters during local loopback\n"))
1384 /* Now, check data */
1385 for (chan = 0; chan < CD180_NCHAN; chan++)
1386 for (i = 0; i < CD180_NFIFO; i++)
1387 if (ctest[i] != tchans[chan].rxbuf[i])
1388 ERR(("data mismatch chan %d ptr %d (%d != %d)\n",
1389 chan, i, ctest[i], tchans[chan].rxbuf[i]))
1390 (void) splx(old_level);
1391 return 0;
1392}
1393
1394#ifdef RCDEBUG
1395static void printrcflags(rc, comment)
1396struct rc_chans *rc;
1397char *comment;
1398{
1399 u_short f = rc->rc_flags;
1400 register int nec = rc->rc_rcb->rcb_addr;
1401
1402 printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n",
1403 rc->rc_rcb->rcb_unit, rc->rc_chan, comment,
1404 (f & RC_DTR_OFF)?"DTR_OFF " :"",
1405 (f & RC_ACTOUT) ?"ACTOUT " :"",
1406 (f & RC_RTSFLOW)?"RTSFLOW " :"",
1407 (f & RC_CTSFLOW)?"CTSFLOW " :"",
1408 (f & RC_DORXFER)?"DORXFER " :"",
1409 (f & RC_DOXXFER)?"DOXXFER " :"",
1410 (f & RC_MODCHG) ?"MODCHG " :"",
1411 (f & RC_OSUSP) ?"OSUSP " :"",
1412 (f & RC_OSBUSY) ?"OSBUSY " :"",
1413 (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"",
1414 (f & RC_WAS_SILOVFL) ?"SILOVFL " :"",
1415 (f & RC_SEND_RDY) ?"SEND_RDY":"");
1416
1417 rcout(CD180_CAR, rc->rc_chan);
1418
1419 printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n",
1420 rc->rc_rcb->rcb_unit, rc->rc_chan,
1421 rcin(CD180_MSVR),
1422 rcin(CD180_IER),
1423 rcin(CD180_CCSR));
1424}
1425#endif /* RCDEBUG */
1426
1427static struct tty *
1428rcdevtotty(dev)
1429 dev_t dev;
1430{
1431 int unit;
1432
1433 unit = GET_UNIT(dev);
1434 if (unit >= NRC * CD180_NCHAN)
1435 return NULL;
1436 return (&rc_tty[unit]);
1437}
1438
1439static void
1440rc_dtrwakeup(chan)
1441 void *chan;
1442{
1443 struct rc_chans *rc;
1444
1445 rc = (struct rc_chans *)chan;
1446 rc->rc_flags &= ~RC_DTR_OFF;
1447 wakeup(&rc->rc_dtrwait);
1448}
1449
1450static void
1451rc_discard_output(rc)
1452 struct rc_chans *rc;
1453{
1454 disable_intr();
1455 if (rc->rc_flags & RC_DOXXFER) {
1456 rc_scheduled_event -= LOTS_OF_EVENTS;
1457 rc->rc_flags &= ~RC_DOXXFER;
1458 }
1459 rc->rc_optr = rc->rc_obufend;
1460 rc->rc_tp->t_state &= ~TS_BUSY;
1461 enable_intr();
1462 ttwwakeup(rc->rc_tp);
1463}
1464
1465static void
1466rc_wakeup(chan)
1467 void *chan;
1468{
1469 timeout(rc_wakeup, (caddr_t)NULL, 1);
1470
1471 if (rc_scheduled_event != 0) {
1472 int s;
1473
1474 s = splsofttty();
1475 rcpoll();
1476 splx(s);
1477 }
1478}
1479
1480static void
1481disc_optim(tp, t, rc)
1482 struct tty *tp;
1483 struct termios *t;
1484 struct rc_chans *rc;
1485{
1486
1487 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1488 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1489 && (!(t->c_iflag & PARMRK)
1490 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1491 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1492 && linesw[tp->t_line].l_rint == ttyinput)
1493 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1494 else
1495 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1496 rc->rc_hotchar = linesw[tp->t_line].l_hotchar;
1497}
1498
1499static void
1500rc_wait0(nec, unit, chan, line)
1501 int nec, unit, chan, line;
1502{
1503 int rcnt;
1504
1505 for (rcnt = 50; rcnt && rcin(CD180_CCR); rcnt--)
1506 DELAY(30);
1507 if (rcnt == 0)
1508 printf("rc%d/%d: channel command timeout, rc.c line: %d\n",
1509 unit, chan, line);
1510}
1511
1512#endif /* NRC */
268 }
269 rcb->rcb_probed = RC_ATTACHED;
270 if (!rc_started) {
271 cdevsw_add(&rc_cdevsw);
272 register_swi(SWI_TTY, rcpoll);
273 rc_wakeup((void *)NULL);
274 rc_started = 1;
275 }
276 return 1;
277}
278
279/* RC interrupt handling */
280static void
281rcintr(unit)
282 int unit;
283{
284 register struct rc_softc *rcb = &rc_softc[unit];
285 register struct rc_chans *rc;
286 register int nec, resid;
287 register u_char val, iack, bsr, ucnt, *optr;
288 int good_data, t_state;
289
290 if (rcb->rcb_probed != RC_ATTACHED) {
291 printf("rc%d: bogus interrupt\n", unit);
292 return;
293 }
294 nec = rcb->rcb_addr;
295
296 bsr = ~(rcin(RC_BSR));
297
298 if (!(bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT))) {
299 printf("rc%d: extra interrupt\n", unit);
300 rcout(CD180_EOIR, 0);
301 return;
302 }
303
304 while (bsr & (RC_BSR_TOUT|RC_BSR_RXINT|RC_BSR_TXINT|RC_BSR_MOINT)) {
305#ifdef RCDEBUG_DETAILED
306 printf("rc%d: intr (%02x) %s%s%s%s\n", unit, bsr,
307 (bsr & RC_BSR_TOUT)?"TOUT ":"",
308 (bsr & RC_BSR_RXINT)?"RXINT ":"",
309 (bsr & RC_BSR_TXINT)?"TXINT ":"",
310 (bsr & RC_BSR_MOINT)?"MOINT":"");
311#endif
312 if (bsr & RC_BSR_TOUT) {
313 printf("rc%d: hardware failure, reset board\n", unit);
314 rcout(RC_CTOUT, 0);
315 rc_reinit(rcb);
316 return;
317 }
318 if (bsr & RC_BSR_RXINT) {
319 iack = rcin(RC_PILR_RX);
320 good_data = (iack == (GIVR_IT_RGDI | RC_FAKEID));
321 if (!good_data && iack != (GIVR_IT_REI | RC_FAKEID)) {
322 printf("rc%d: fake rxint: %02x\n", unit, iack);
323 goto more_intrs;
324 }
325 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
326 t_state = rc->rc_tp->t_state;
327 /* Do RTS flow control stuff */
328 if ( (rc->rc_flags & RC_RTSFLOW)
329 || !(t_state & TS_ISOPEN)
330 ) {
331 if ( ( !(t_state & TS_ISOPEN)
332 || (t_state & TS_TBLOCK)
333 )
334 && (rc->rc_msvr & MSVR_RTS)
335 )
336 rcout(CD180_MSVR,
337 rc->rc_msvr &= ~MSVR_RTS);
338 else if (!(rc->rc_msvr & MSVR_RTS))
339 rcout(CD180_MSVR,
340 rc->rc_msvr |= MSVR_RTS);
341 }
342 ucnt = rcin(CD180_RDCR) & 0xF;
343 resid = 0;
344
345 if (t_state & TS_ISOPEN) {
346 /* check for input buffer overflow */
347 if ((rc->rc_iptr + ucnt) >= rc->rc_bufend) {
348 resid = ucnt;
349 ucnt = rc->rc_bufend - rc->rc_iptr;
350 resid -= ucnt;
351 if (!(rc->rc_flags & RC_WAS_BUFOVFL)) {
352 rc->rc_flags |= RC_WAS_BUFOVFL;
353 rc_scheduled_event++;
354 }
355 }
356 optr = rc->rc_iptr;
357 /* check foor good data */
358 if (good_data) {
359 while (ucnt-- > 0) {
360 val = rcin(CD180_RDR);
361 optr[0] = val;
362 optr[INPUT_FLAGS_SHIFT] = 0;
363 optr++;
364 rc_scheduled_event++;
365 if (val != 0 && val == rc->rc_hotchar)
366 setsofttty();
367 }
368 } else {
369 /* Store also status data */
370 while (ucnt-- > 0) {
371 iack = rcin(CD180_RCSR);
372 if (iack & RCSR_Timeout)
373 break;
374 if ( (iack & RCSR_OE)
375 && !(rc->rc_flags & RC_WAS_SILOVFL)) {
376 rc->rc_flags |= RC_WAS_SILOVFL;
377 rc_scheduled_event++;
378 }
379 val = rcin(CD180_RDR);
380 /*
381 Don't store PE if IGNPAR and BREAK if IGNBRK,
382 this hack allows "raw" tty optimization
383 works even if IGN* is set.
384 */
385 if ( !(iack & (RCSR_PE|RCSR_FE|RCSR_Break))
386 || ((!(iack & (RCSR_PE|RCSR_FE))
387 || !(rc->rc_tp->t_iflag & IGNPAR))
388 && (!(iack & RCSR_Break)
389 || !(rc->rc_tp->t_iflag & IGNBRK)))) {
390 if ( (iack & (RCSR_PE|RCSR_FE))
391 && (t_state & TS_CAN_BYPASS_L_RINT)
392 && ((iack & RCSR_FE)
393 || ((iack & RCSR_PE)
394 && (rc->rc_tp->t_iflag & INPCK))))
395 val = 0;
396 else if (val != 0 && val == rc->rc_hotchar)
397 setsofttty();
398 optr[0] = val;
399 optr[INPUT_FLAGS_SHIFT] = iack;
400 optr++;
401 rc_scheduled_event++;
402 }
403 }
404 }
405 rc->rc_iptr = optr;
406 rc->rc_flags |= RC_DORXFER;
407 } else
408 resid = ucnt;
409 /* Clear FIFO if necessary */
410 while (resid-- > 0) {
411 if (!good_data)
412 iack = rcin(CD180_RCSR);
413 else
414 iack = 0;
415 if (iack & RCSR_Timeout)
416 break;
417 (void) rcin(CD180_RDR);
418 }
419 goto more_intrs;
420 }
421 if (bsr & RC_BSR_MOINT) {
422 iack = rcin(RC_PILR_MODEM);
423 if (iack != (GIVR_IT_MSCI | RC_FAKEID)) {
424 printf("rc%d: fake moint: %02x\n", unit, iack);
425 goto more_intrs;
426 }
427 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
428 iack = rcin(CD180_MCR);
429 rc->rc_msvr = rcin(CD180_MSVR);
430 rcout(CD180_MCR, 0);
431#ifdef RCDEBUG
432 printrcflags(rc, "moint");
433#endif
434 if (rc->rc_flags & RC_CTSFLOW) {
435 if (rc->rc_msvr & MSVR_CTS)
436 rc->rc_flags |= RC_SEND_RDY;
437 else
438 rc->rc_flags &= ~RC_SEND_RDY;
439 } else
440 rc->rc_flags |= RC_SEND_RDY;
441 if ((iack & MCR_CDchg) && !(rc->rc_flags & RC_MODCHG)) {
442 rc_scheduled_event += LOTS_OF_EVENTS;
443 rc->rc_flags |= RC_MODCHG;
444 setsofttty();
445 }
446 goto more_intrs;
447 }
448 if (bsr & RC_BSR_TXINT) {
449 iack = rcin(RC_PILR_TX);
450 if (iack != (GIVR_IT_TDI | RC_FAKEID)) {
451 printf("rc%d: fake txint: %02x\n", unit, iack);
452 goto more_intrs;
453 }
454 rc = rcb->rcb_baserc + ((rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH);
455 if ( (rc->rc_flags & RC_OSUSP)
456 || !(rc->rc_flags & RC_SEND_RDY)
457 )
458 goto more_intrs;
459 /* Handle breaks and other stuff */
460 if (rc->rc_pendcmd) {
461 rcout(CD180_COR2, rc->rc_cor2 |= COR2_ETC);
462 rcout(CD180_TDR, CD180_C_ESC);
463 rcout(CD180_TDR, rc->rc_pendcmd);
464 rcout(CD180_COR2, rc->rc_cor2 &= ~COR2_ETC);
465 rc->rc_pendcmd = 0;
466 goto more_intrs;
467 }
468 optr = rc->rc_optr;
469 resid = rc->rc_obufend - optr;
470 if (resid > CD180_NFIFO)
471 resid = CD180_NFIFO;
472 while (resid-- > 0)
473 rcout(CD180_TDR, *optr++);
474 rc->rc_optr = optr;
475
476 /* output completed? */
477 if (optr >= rc->rc_obufend) {
478 rcout(CD180_IER, rc->rc_ier &= ~IER_TxRdy);
479#ifdef RCDEBUG
480 printf("rc%d/%d: output completed\n", unit, rc->rc_chan);
481#endif
482 if (!(rc->rc_flags & RC_DOXXFER)) {
483 rc_scheduled_event += LOTS_OF_EVENTS;
484 rc->rc_flags |= RC_DOXXFER;
485 setsofttty();
486 }
487 }
488 }
489 more_intrs:
490 rcout(CD180_EOIR, 0); /* end of interrupt */
491 rcout(RC_CTOUT, 0);
492 bsr = ~(rcin(RC_BSR));
493 }
494}
495
496/* Feed characters to output buffer */
497static void rc_start(tp)
498register struct tty *tp;
499{
500 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
501 register int nec = rc->rc_rcb->rcb_addr, s;
502
503 if (rc->rc_flags & RC_OSBUSY)
504 return;
505 s = spltty();
506 rc->rc_flags |= RC_OSBUSY;
507 disable_intr();
508 if (tp->t_state & TS_TTSTOP)
509 rc->rc_flags |= RC_OSUSP;
510 else
511 rc->rc_flags &= ~RC_OSUSP;
512 /* Do RTS flow control stuff */
513 if ( (rc->rc_flags & RC_RTSFLOW)
514 && (tp->t_state & TS_TBLOCK)
515 && (rc->rc_msvr & MSVR_RTS)
516 ) {
517 rcout(CD180_CAR, rc->rc_chan);
518 rcout(CD180_MSVR, rc->rc_msvr &= ~MSVR_RTS);
519 } else if (!(rc->rc_msvr & MSVR_RTS)) {
520 rcout(CD180_CAR, rc->rc_chan);
521 rcout(CD180_MSVR, rc->rc_msvr |= MSVR_RTS);
522 }
523 enable_intr();
524 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
525 goto out;
526#ifdef RCDEBUG
527 printrcflags(rc, "rcstart");
528#endif
529 ttwwakeup(tp);
530#ifdef RCDEBUG
531 printf("rcstart: outq = %d obuf = %d\n",
532 tp->t_outq.c_cc, rc->rc_obufend - rc->rc_optr);
533#endif
534 if (tp->t_state & TS_BUSY)
535 goto out; /* output still in progress ... */
536
537 if (tp->t_outq.c_cc > 0) {
538 u_int ocnt;
539
540 tp->t_state |= TS_BUSY;
541 ocnt = q_to_b(&tp->t_outq, rc->rc_obuf, sizeof rc->rc_obuf);
542 disable_intr();
543 rc->rc_optr = rc->rc_obuf;
544 rc->rc_obufend = rc->rc_optr + ocnt;
545 enable_intr();
546 if (!(rc->rc_ier & IER_TxRdy)) {
547#ifdef RCDEBUG
548 printf("rc%d/%d: rcstart enable txint\n", rc->rc_rcb->rcb_unit, rc->rc_chan);
549#endif
550 rcout(CD180_CAR, rc->rc_chan);
551 rcout(CD180_IER, rc->rc_ier |= IER_TxRdy);
552 }
553 }
554out:
555 rc->rc_flags &= ~RC_OSBUSY;
556 (void) splx(s);
557}
558
559/* Handle delayed events. */
560void rcpoll()
561{
562 register struct rc_chans *rc;
563 register struct rc_softc *rcb;
564 register u_char *tptr, *eptr;
565 register struct tty *tp;
566 register int chan, icnt, nec, unit;
567
568 if (rc_scheduled_event == 0)
569 return;
570repeat:
571 for (unit = 0; unit < NRC; unit++) {
572 rcb = &rc_softc[unit];
573 rc = rcb->rcb_baserc;
574 nec = rc->rc_rcb->rcb_addr;
575 for (chan = 0; chan < CD180_NCHAN; rc++, chan++) {
576 tp = rc->rc_tp;
577#ifdef RCDEBUG
578 if (rc->rc_flags & (RC_DORXFER|RC_DOXXFER|RC_MODCHG|
579 RC_WAS_BUFOVFL|RC_WAS_SILOVFL))
580 printrcflags(rc, "rcevent");
581#endif
582 if (rc->rc_flags & RC_WAS_BUFOVFL) {
583 disable_intr();
584 rc->rc_flags &= ~RC_WAS_BUFOVFL;
585 rc_scheduled_event--;
586 enable_intr();
587 printf("rc%d/%d: interrupt-level buffer overflow\n",
588 unit, chan);
589 }
590 if (rc->rc_flags & RC_WAS_SILOVFL) {
591 disable_intr();
592 rc->rc_flags &= ~RC_WAS_SILOVFL;
593 rc_scheduled_event--;
594 enable_intr();
595 printf("rc%d/%d: silo overflow\n",
596 unit, chan);
597 }
598 if (rc->rc_flags & RC_MODCHG) {
599 disable_intr();
600 rc->rc_flags &= ~RC_MODCHG;
601 rc_scheduled_event -= LOTS_OF_EVENTS;
602 enable_intr();
603 (*linesw[tp->t_line].l_modem)(tp, !!(rc->rc_msvr & MSVR_CD));
604 }
605 if (rc->rc_flags & RC_DORXFER) {
606 disable_intr();
607 rc->rc_flags &= ~RC_DORXFER;
608 eptr = rc->rc_iptr;
609 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE])
610 tptr = &rc->rc_ibuf[RC_IBUFSIZE];
611 else
612 tptr = rc->rc_ibuf;
613 icnt = eptr - tptr;
614 if (icnt > 0) {
615 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
616 rc->rc_iptr = rc->rc_ibuf;
617 rc->rc_bufend = &rc->rc_ibuf[RC_IBUFSIZE];
618 rc->rc_hiwat = &rc->rc_ibuf[RC_IHIGHWATER];
619 } else {
620 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];
621 rc->rc_bufend = &rc->rc_ibuf[2 * RC_IBUFSIZE];
622 rc->rc_hiwat =
623 &rc->rc_ibuf[RC_IBUFSIZE + RC_IHIGHWATER];
624 }
625 if ( (rc->rc_flags & RC_RTSFLOW)
626 && (tp->t_state & TS_ISOPEN)
627 && !(tp->t_state & TS_TBLOCK)
628 && !(rc->rc_msvr & MSVR_RTS)
629 ) {
630 rcout(CD180_CAR, chan);
631 rcout(CD180_MSVR,
632 rc->rc_msvr |= MSVR_RTS);
633 }
634 rc_scheduled_event -= icnt;
635 }
636 enable_intr();
637
638 if (icnt <= 0 || !(tp->t_state & TS_ISOPEN))
639 goto done1;
640
641 if ( (tp->t_state & TS_CAN_BYPASS_L_RINT)
642 && !(tp->t_state & TS_LOCAL)) {
643 if ((tp->t_rawq.c_cc + icnt) >= RB_I_HIGH_WATER
644 && ((rc->rc_flags & RC_RTSFLOW) || (tp->t_iflag & IXOFF))
645 && !(tp->t_state & TS_TBLOCK))
646 ttyblock(tp);
647 tk_nin += icnt;
648 tk_rawcc += icnt;
649 tp->t_rawcc += icnt;
650 if (b_to_q(tptr, icnt, &tp->t_rawq))
651 printf("rc%d/%d: tty-level buffer overflow\n",
652 unit, chan);
653 ttwakeup(tp);
654 if ((tp->t_state & TS_TTSTOP) && ((tp->t_iflag & IXANY)
655 || (tp->t_cc[VSTART] == tp->t_cc[VSTOP]))) {
656 tp->t_state &= ~TS_TTSTOP;
657 tp->t_lflag &= ~FLUSHO;
658 rc_start(tp);
659 }
660 } else {
661 for (; tptr < eptr; tptr++)
662 (*linesw[tp->t_line].l_rint)
663 (tptr[0] |
664 rc_rcsrt[tptr[INPUT_FLAGS_SHIFT] & 0xF], tp);
665 }
666done1: ;
667 }
668 if (rc->rc_flags & RC_DOXXFER) {
669 disable_intr();
670 rc_scheduled_event -= LOTS_OF_EVENTS;
671 rc->rc_flags &= ~RC_DOXXFER;
672 rc->rc_tp->t_state &= ~TS_BUSY;
673 enable_intr();
674 (*linesw[tp->t_line].l_start)(tp);
675 }
676 }
677 if (rc_scheduled_event == 0)
678 break;
679 }
680 if (rc_scheduled_event >= LOTS_OF_EVENTS)
681 goto repeat;
682}
683
684static void
685rcstop(tp, rw)
686 register struct tty *tp;
687 int rw;
688{
689 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
690 u_char *tptr, *eptr;
691
692#ifdef RCDEBUG
693 printf("rc%d/%d: rcstop %s%s\n", rc->rc_rcb->rcb_unit, rc->rc_chan,
694 (rw & FWRITE)?"FWRITE ":"", (rw & FREAD)?"FREAD":"");
695#endif
696 if (rw & FWRITE)
697 rc_discard_output(rc);
698 disable_intr();
699 if (rw & FREAD) {
700 rc->rc_flags &= ~RC_DORXFER;
701 eptr = rc->rc_iptr;
702 if (rc->rc_bufend == &rc->rc_ibuf[2 * RC_IBUFSIZE]) {
703 tptr = &rc->rc_ibuf[RC_IBUFSIZE];
704 rc->rc_iptr = &rc->rc_ibuf[RC_IBUFSIZE];
705 } else {
706 tptr = rc->rc_ibuf;
707 rc->rc_iptr = rc->rc_ibuf;
708 }
709 rc_scheduled_event -= eptr - tptr;
710 }
711 if (tp->t_state & TS_TTSTOP)
712 rc->rc_flags |= RC_OSUSP;
713 else
714 rc->rc_flags &= ~RC_OSUSP;
715 enable_intr();
716}
717
718static int
719rcopen(dev, flag, mode, p)
720 dev_t dev;
721 int flag, mode;
722 struct proc *p;
723{
724 register struct rc_chans *rc;
725 register struct tty *tp;
726 int unit, nec, s, error = 0;
727
728 unit = GET_UNIT(dev);
729 if (unit >= NRC * CD180_NCHAN)
730 return ENXIO;
731 if (rc_softc[unit / CD180_NCHAN].rcb_probed != RC_ATTACHED)
732 return ENXIO;
733 rc = &rc_chans[unit];
734 tp = rc->rc_tp;
735 nec = rc->rc_rcb->rcb_addr;
736#ifdef RCDEBUG
737 printf("rc%d/%d: rcopen: dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
738#endif
739 s = spltty();
740
741again:
742 while (rc->rc_flags & RC_DTR_OFF) {
743 error = tsleep(&(rc->rc_dtrwait), TTIPRI | PCATCH, "rcdtr", 0);
744 if (error != 0)
745 goto out;
746 }
747 if (tp->t_state & TS_ISOPEN) {
748 if (CALLOUT(dev)) {
749 if (!(rc->rc_flags & RC_ACTOUT)) {
750 error = EBUSY;
751 goto out;
752 }
753 } else {
754 if (rc->rc_flags & RC_ACTOUT) {
755 if (flag & O_NONBLOCK) {
756 error = EBUSY;
757 goto out;
758 }
759 error = tsleep(&rc->rc_rcb,
760 TTIPRI|PCATCH, "rcbi", 0);
761 if (error)
762 goto out;
763 goto again;
764 }
765 }
766 if (tp->t_state & TS_XCLUDE &&
767 suser(p)) {
768 error = EBUSY;
769 goto out;
770 }
771 } else {
772 tp->t_oproc = rc_start;
773 tp->t_param = rc_param;
774 tp->t_dev = dev;
775
776 if (CALLOUT(dev))
777 tp->t_cflag |= CLOCAL;
778 else
779 tp->t_cflag &= ~CLOCAL;
780
781 error = rc_param(tp, &tp->t_termios);
782 if (error)
783 goto out;
784 (void) rc_modctl(rc, TIOCM_RTS|TIOCM_DTR, DMSET);
785
786 if ((rc->rc_msvr & MSVR_CD) || CALLOUT(dev))
787 (*linesw[tp->t_line].l_modem)(tp, 1);
788 }
789 if (!(tp->t_state & TS_CARR_ON) && !CALLOUT(dev)
790 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
791 rc->rc_dcdwaits++;
792 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "rcdcd", 0);
793 rc->rc_dcdwaits--;
794 if (error != 0)
795 goto out;
796 goto again;
797 }
798 error = (*linesw[tp->t_line].l_open)(dev, tp);
799 disc_optim(tp, &tp->t_termios, rc);
800 if ((tp->t_state & TS_ISOPEN) && CALLOUT(dev))
801 rc->rc_flags |= RC_ACTOUT;
802out:
803 (void) splx(s);
804
805 if(rc->rc_dcdwaits == 0 && !(tp->t_state & TS_ISOPEN))
806 rc_hardclose(rc);
807
808 return error;
809}
810
811static int
812rcclose(dev, flag, mode, p)
813 dev_t dev;
814 int flag, mode;
815 struct proc *p;
816{
817 register struct rc_chans *rc;
818 register struct tty *tp;
819 int s, unit = GET_UNIT(dev);
820
821 if (unit >= NRC * CD180_NCHAN)
822 return ENXIO;
823 rc = &rc_chans[unit];
824 tp = rc->rc_tp;
825#ifdef RCDEBUG
826 printf("rc%d/%d: rcclose dev %x\n", rc->rc_rcb->rcb_unit, unit, dev);
827#endif
828 s = spltty();
829 (*linesw[tp->t_line].l_close)(tp, flag);
830 disc_optim(tp, &tp->t_termios, rc);
831 rcstop(tp, FREAD | FWRITE);
832 rc_hardclose(rc);
833 ttyclose(tp);
834 splx(s);
835 return 0;
836}
837
838static void rc_hardclose(rc)
839register struct rc_chans *rc;
840{
841 register int s, nec = rc->rc_rcb->rcb_addr;
842 register struct tty *tp = rc->rc_tp;
843
844 s = spltty();
845 rcout(CD180_CAR, rc->rc_chan);
846
847 /* Disable rx/tx intrs */
848 rcout(CD180_IER, rc->rc_ier = 0);
849 if ( (tp->t_cflag & HUPCL)
850 || (!(rc->rc_flags & RC_ACTOUT)
851 && !(rc->rc_msvr & MSVR_CD)
852 && !(tp->t_cflag & CLOCAL))
853 || !(tp->t_state & TS_ISOPEN)
854 ) {
855 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
856 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
857 (void) rc_modctl(rc, TIOCM_RTS, DMSET);
858 if (rc->rc_dtrwait) {
859 timeout(rc_dtrwakeup, rc, rc->rc_dtrwait);
860 rc->rc_flags |= RC_DTR_OFF;
861 }
862 }
863 rc->rc_flags &= ~RC_ACTOUT;
864 wakeup((caddr_t) &rc->rc_rcb); /* wake bi */
865 wakeup(TSA_CARR_ON(tp));
866 (void) splx(s);
867}
868
869/* Read from line */
870static int
871rcread(dev, uio, flag)
872 dev_t dev;
873 struct uio *uio;
874 int flag;
875{
876 struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;
877
878 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
879}
880
881/* Write to line */
882static int
883rcwrite(dev, uio, flag)
884 dev_t dev;
885 struct uio *uio;
886 int flag;
887{
888 struct tty *tp = rc_chans[GET_UNIT(dev)].rc_tp;
889
890 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
891}
892
893/* Reset the bastard */
894static void rc_hwreset(unit, nec, chipid)
895 register int unit, nec;
896 unsigned int chipid;
897{
898 CCRCMD(unit, -1, CCR_HWRESET); /* Hardware reset */
899 DELAY(20000);
900 WAITFORCCR(unit, -1);
901
902 rcout(RC_CTOUT, 0); /* Clear timeout */
903 rcout(CD180_GIVR, chipid);
904 rcout(CD180_GICR, 0);
905
906 /* Set Prescaler Registers (1 msec) */
907 rcout(CD180_PPRL, ((RC_OSCFREQ + 999) / 1000) & 0xFF);
908 rcout(CD180_PPRH, ((RC_OSCFREQ + 999) / 1000) >> 8);
909
910 /* Initialize Priority Interrupt Level Registers */
911 rcout(CD180_PILR1, RC_PILR_MODEM);
912 rcout(CD180_PILR2, RC_PILR_TX);
913 rcout(CD180_PILR3, RC_PILR_RX);
914
915 /* Reset DTR */
916 rcout(RC_DTREG, ~0);
917}
918
919/* Set channel parameters */
920static int rc_param(tp, ts)
921 register struct tty *tp;
922 struct termios *ts;
923{
924 register struct rc_chans *rc = &rc_chans[GET_UNIT(tp->t_dev)];
925 register int nec = rc->rc_rcb->rcb_addr;
926 int idivs, odivs, s, val, cflag, iflag, lflag, inpflow;
927
928 if ( ts->c_ospeed < 0 || ts->c_ospeed > 76800
929 || ts->c_ispeed < 0 || ts->c_ispeed > 76800
930 )
931 return (EINVAL);
932 if (ts->c_ispeed == 0)
933 ts->c_ispeed = ts->c_ospeed;
934 odivs = RC_BRD(ts->c_ospeed);
935 idivs = RC_BRD(ts->c_ispeed);
936
937 s = spltty();
938
939 /* Select channel */
940 rcout(CD180_CAR, rc->rc_chan);
941
942 /* If speed == 0, hangup line */
943 if (ts->c_ospeed == 0) {
944 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan, CCR_ResetChan);
945 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
946 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
947 }
948
949 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
950 cflag = ts->c_cflag;
951 iflag = ts->c_iflag;
952 lflag = ts->c_lflag;
953
954 if (idivs > 0) {
955 rcout(CD180_RBPRL, idivs & 0xFF);
956 rcout(CD180_RBPRH, idivs >> 8);
957 }
958 if (odivs > 0) {
959 rcout(CD180_TBPRL, odivs & 0xFF);
960 rcout(CD180_TBPRH, odivs >> 8);
961 }
962
963 /* set timeout value */
964 if (ts->c_ispeed > 0) {
965 int itm = ts->c_ispeed > 2400 ? 5 : 10000 / ts->c_ispeed + 1;
966
967 if ( !(lflag & ICANON)
968 && ts->c_cc[VMIN] != 0 && ts->c_cc[VTIME] != 0
969 && ts->c_cc[VTIME] * 10 > itm)
970 itm = ts->c_cc[VTIME] * 10;
971
972 rcout(CD180_RTPR, itm <= 255 ? itm : 255);
973 }
974
975 switch (cflag & CSIZE) {
976 case CS5: val = COR1_5BITS; break;
977 case CS6: val = COR1_6BITS; break;
978 case CS7: val = COR1_7BITS; break;
979 default:
980 case CS8: val = COR1_8BITS; break;
981 }
982 if (cflag & PARENB) {
983 val |= COR1_NORMPAR;
984 if (cflag & PARODD)
985 val |= COR1_ODDP;
986 if (!(cflag & INPCK))
987 val |= COR1_Ignore;
988 } else
989 val |= COR1_Ignore;
990 if (cflag & CSTOPB)
991 val |= COR1_2SB;
992 rcout(CD180_COR1, val);
993
994 /* Set FIFO threshold */
995 val = ts->c_ospeed <= 4800 ? 1 : CD180_NFIFO / 2;
996 inpflow = 0;
997 if ( (iflag & IXOFF)
998 && ( ts->c_cc[VSTOP] != _POSIX_VDISABLE
999 && ( ts->c_cc[VSTART] != _POSIX_VDISABLE
1000 || (iflag & IXANY)
1001 )
1002 )
1003 ) {
1004 inpflow = 1;
1005 val |= COR3_SCDE|COR3_FCT;
1006 }
1007 rcout(CD180_COR3, val);
1008
1009 /* Initialize on-chip automatic flow control */
1010 val = 0;
1011 rc->rc_flags &= ~(RC_CTSFLOW|RC_SEND_RDY);
1012 if (cflag & CCTS_OFLOW) {
1013 rc->rc_flags |= RC_CTSFLOW;
1014 val |= COR2_CtsAE;
1015 } else
1016 rc->rc_flags |= RC_SEND_RDY;
1017 if (tp->t_state & TS_TTSTOP)
1018 rc->rc_flags |= RC_OSUSP;
1019 else
1020 rc->rc_flags &= ~RC_OSUSP;
1021 if (cflag & CRTS_IFLOW)
1022 rc->rc_flags |= RC_RTSFLOW;
1023 else
1024 rc->rc_flags &= ~RC_RTSFLOW;
1025
1026 if (inpflow) {
1027 if (ts->c_cc[VSTART] != _POSIX_VDISABLE)
1028 rcout(CD180_SCHR1, ts->c_cc[VSTART]);
1029 rcout(CD180_SCHR2, ts->c_cc[VSTOP]);
1030 val |= COR2_TxIBE;
1031 if (iflag & IXANY)
1032 val |= COR2_IXM;
1033 }
1034
1035 rcout(CD180_COR2, rc->rc_cor2 = val);
1036
1037 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
1038 CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1039
1040 disc_optim(tp, ts, rc);
1041
1042 /* modem ctl */
1043 val = cflag & CLOCAL ? 0 : MCOR1_CDzd;
1044 if (cflag & CCTS_OFLOW)
1045 val |= MCOR1_CTSzd;
1046 rcout(CD180_MCOR1, val);
1047
1048 val = cflag & CLOCAL ? 0 : MCOR2_CDod;
1049 if (cflag & CCTS_OFLOW)
1050 val |= MCOR2_CTSod;
1051 rcout(CD180_MCOR2, val);
1052
1053 /* enable i/o and interrupts */
1054 CCRCMD(rc->rc_rcb->rcb_unit, rc->rc_chan,
1055 CCR_XMTREN | ((cflag & CREAD) ? CCR_RCVREN : CCR_RCVRDIS));
1056 WAITFORCCR(rc->rc_rcb->rcb_unit, rc->rc_chan);
1057
1058 rc->rc_ier = cflag & CLOCAL ? 0 : IER_CD;
1059 if (cflag & CCTS_OFLOW)
1060 rc->rc_ier |= IER_CTS;
1061 if (cflag & CREAD)
1062 rc->rc_ier |= IER_RxData;
1063 if (tp->t_state & TS_BUSY)
1064 rc->rc_ier |= IER_TxRdy;
1065 if (ts->c_ospeed != 0)
1066 rc_modctl(rc, TIOCM_DTR, DMBIS);
1067 if ((cflag & CCTS_OFLOW) && (rc->rc_msvr & MSVR_CTS))
1068 rc->rc_flags |= RC_SEND_RDY;
1069 rcout(CD180_IER, rc->rc_ier);
1070 (void) splx(s);
1071 return 0;
1072}
1073
1074/* Re-initialize board after bogus interrupts */
1075static void rc_reinit(rcb)
1076struct rc_softc *rcb;
1077{
1078 register struct rc_chans *rc, *rce;
1079 register int nec;
1080
1081 nec = rcb->rcb_addr;
1082 rc_hwreset(rcb->rcb_unit, nec, RC_FAKEID);
1083 rc = &rc_chans[rcb->rcb_unit * CD180_NCHAN];
1084 rce = rc + CD180_NCHAN;
1085 for (; rc < rce; rc++)
1086 (void) rc_param(rc->rc_tp, &rc->rc_tp->t_termios);
1087}
1088
1089static int
1090rcioctl(dev, cmd, data, flag, p)
1091dev_t dev;
1092u_long cmd;
1093int flag;
1094caddr_t data;
1095struct proc *p;
1096{
1097 register struct rc_chans *rc = &rc_chans[GET_UNIT(dev)];
1098 register int s, error;
1099 struct tty *tp = rc->rc_tp;
1100
1101 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1102 if (error != ENOIOCTL)
1103 return (error);
1104 error = ttioctl(tp, cmd, data, flag);
1105 disc_optim(tp, &tp->t_termios, rc);
1106 if (error != ENOIOCTL)
1107 return (error);
1108 s = spltty();
1109
1110 switch (cmd) {
1111 case TIOCSBRK:
1112 rc->rc_pendcmd = CD180_C_SBRK;
1113 break;
1114
1115 case TIOCCBRK:
1116 rc->rc_pendcmd = CD180_C_EBRK;
1117 break;
1118
1119 case TIOCSDTR:
1120 (void) rc_modctl(rc, TIOCM_DTR, DMBIS);
1121 break;
1122
1123 case TIOCCDTR:
1124 (void) rc_modctl(rc, TIOCM_DTR, DMBIC);
1125 break;
1126
1127 case TIOCMGET:
1128 *(int *) data = rc_modctl(rc, 0, DMGET);
1129 break;
1130
1131 case TIOCMSET:
1132 (void) rc_modctl(rc, *(int *) data, DMSET);
1133 break;
1134
1135 case TIOCMBIC:
1136 (void) rc_modctl(rc, *(int *) data, DMBIC);
1137 break;
1138
1139 case TIOCMBIS:
1140 (void) rc_modctl(rc, *(int *) data, DMBIS);
1141 break;
1142
1143 case TIOCMSDTRWAIT:
1144 error = suser(p);
1145 if (error != 0) {
1146 splx(s);
1147 return (error);
1148 }
1149 rc->rc_dtrwait = *(int *)data * hz / 100;
1150 break;
1151
1152 case TIOCMGDTRWAIT:
1153 *(int *)data = rc->rc_dtrwait * 100 / hz;
1154 break;
1155
1156 default:
1157 (void) splx(s);
1158 return ENOTTY;
1159 }
1160 (void) splx(s);
1161 return 0;
1162}
1163
1164
1165/* Modem control routines */
1166
1167static int rc_modctl(rc, bits, cmd)
1168register struct rc_chans *rc;
1169int bits, cmd;
1170{
1171 register int nec = rc->rc_rcb->rcb_addr;
1172 u_char *dtr = &rc->rc_rcb->rcb_dtr, msvr;
1173
1174 rcout(CD180_CAR, rc->rc_chan);
1175
1176 switch (cmd) {
1177 case DMSET:
1178 rcout(RC_DTREG, (bits & TIOCM_DTR) ?
1179 ~(*dtr |= 1 << rc->rc_chan) :
1180 ~(*dtr &= ~(1 << rc->rc_chan)));
1181 msvr = rcin(CD180_MSVR);
1182 if (bits & TIOCM_RTS)
1183 msvr |= MSVR_RTS;
1184 else
1185 msvr &= ~MSVR_RTS;
1186 if (bits & TIOCM_DTR)
1187 msvr |= MSVR_DTR;
1188 else
1189 msvr &= ~MSVR_DTR;
1190 rcout(CD180_MSVR, msvr);
1191 break;
1192
1193 case DMBIS:
1194 if (bits & TIOCM_DTR)
1195 rcout(RC_DTREG, ~(*dtr |= 1 << rc->rc_chan));
1196 msvr = rcin(CD180_MSVR);
1197 if (bits & TIOCM_RTS)
1198 msvr |= MSVR_RTS;
1199 if (bits & TIOCM_DTR)
1200 msvr |= MSVR_DTR;
1201 rcout(CD180_MSVR, msvr);
1202 break;
1203
1204 case DMGET:
1205 bits = TIOCM_LE;
1206 msvr = rc->rc_msvr = rcin(CD180_MSVR);
1207
1208 if (msvr & MSVR_RTS)
1209 bits |= TIOCM_RTS;
1210 if (msvr & MSVR_CTS)
1211 bits |= TIOCM_CTS;
1212 if (msvr & MSVR_DSR)
1213 bits |= TIOCM_DSR;
1214 if (msvr & MSVR_DTR)
1215 bits |= TIOCM_DTR;
1216 if (msvr & MSVR_CD)
1217 bits |= TIOCM_CD;
1218 if (~rcin(RC_RIREG) & (1 << rc->rc_chan))
1219 bits |= TIOCM_RI;
1220 return bits;
1221
1222 case DMBIC:
1223 if (bits & TIOCM_DTR)
1224 rcout(RC_DTREG, ~(*dtr &= ~(1 << rc->rc_chan)));
1225 msvr = rcin(CD180_MSVR);
1226 if (bits & TIOCM_RTS)
1227 msvr &= ~MSVR_RTS;
1228 if (bits & TIOCM_DTR)
1229 msvr &= ~MSVR_DTR;
1230 rcout(CD180_MSVR, msvr);
1231 break;
1232 }
1233 rc->rc_msvr = rcin(CD180_MSVR);
1234 return 0;
1235}
1236
1237/* Test the board. */
1238int rc_test(nec, unit)
1239 register int nec;
1240 int unit;
1241{
1242 int chan = 0;
1243 int i = 0, rcnt, old_level;
1244 unsigned int iack, chipid;
1245 unsigned short divs;
1246 static u_char ctest[] = "\377\125\252\045\244\0\377";
1247#define CTLEN 8
1248#define ERR(s) { \
1249 printf("rc%d: ", unit); printf s ; printf("\n"); \
1250 (void) splx(old_level); return 1; }
1251
1252 struct rtest {
1253 u_char txbuf[CD180_NFIFO]; /* TX buffer */
1254 u_char rxbuf[CD180_NFIFO]; /* RX buffer */
1255 int rxptr; /* RX pointer */
1256 int txptr; /* TX pointer */
1257 } tchans[CD180_NCHAN];
1258
1259 old_level = spltty();
1260
1261 chipid = RC_FAKEID;
1262
1263 /* First, reset board to inital state */
1264 rc_hwreset(unit, nec, chipid);
1265
1266 divs = RC_BRD(19200);
1267
1268 /* Initialize channels */
1269 for (chan = 0; chan < CD180_NCHAN; chan++) {
1270
1271 /* Select and reset channel */
1272 rcout(CD180_CAR, chan);
1273 CCRCMD(unit, chan, CCR_ResetChan);
1274 WAITFORCCR(unit, chan);
1275
1276 /* Set speed */
1277 rcout(CD180_RBPRL, divs & 0xFF);
1278 rcout(CD180_RBPRH, divs >> 8);
1279 rcout(CD180_TBPRL, divs & 0xFF);
1280 rcout(CD180_TBPRH, divs >> 8);
1281
1282 /* set timeout value */
1283 rcout(CD180_RTPR, 0);
1284
1285 /* Establish local loopback */
1286 rcout(CD180_COR1, COR1_NOPAR | COR1_8BITS | COR1_1SB);
1287 rcout(CD180_COR2, COR2_LLM);
1288 rcout(CD180_COR3, CD180_NFIFO);
1289 CCRCMD(unit, chan, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3);
1290 CCRCMD(unit, chan, CCR_RCVREN | CCR_XMTREN);
1291 WAITFORCCR(unit, chan);
1292 rcout(CD180_MSVR, MSVR_RTS);
1293
1294 /* Fill TXBUF with test data */
1295 for (i = 0; i < CD180_NFIFO; i++) {
1296 tchans[chan].txbuf[i] = ctest[i];
1297 tchans[chan].rxbuf[i] = 0;
1298 }
1299 tchans[chan].txptr = tchans[chan].rxptr = 0;
1300
1301 /* Now, start transmit */
1302 rcout(CD180_IER, IER_TxMpty|IER_RxData);
1303 }
1304 /* Pseudo-interrupt poll stuff */
1305 for (rcnt = 10000; rcnt-- > 0; rcnt--) {
1306 i = ~(rcin(RC_BSR));
1307 if (i & RC_BSR_TOUT)
1308 ERR(("BSR timeout bit set\n"))
1309 else if (i & RC_BSR_TXINT) {
1310 iack = rcin(RC_PILR_TX);
1311 if (iack != (GIVR_IT_TDI | chipid))
1312 ERR(("Bad TX intr ack (%02x != %02x)\n",
1313 iack, GIVR_IT_TDI | chipid));
1314 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
1315 /* If no more data to transmit, disable TX intr */
1316 if (tchans[chan].txptr >= CD180_NFIFO) {
1317 iack = rcin(CD180_IER);
1318 rcout(CD180_IER, iack & ~IER_TxMpty);
1319 } else {
1320 for (iack = tchans[chan].txptr;
1321 iack < CD180_NFIFO; iack++)
1322 rcout(CD180_TDR,
1323 tchans[chan].txbuf[iack]);
1324 tchans[chan].txptr = iack;
1325 }
1326 rcout(CD180_EOIR, 0);
1327 } else if (i & RC_BSR_RXINT) {
1328 u_char ucnt;
1329
1330 iack = rcin(RC_PILR_RX);
1331 if (iack != (GIVR_IT_RGDI | chipid) &&
1332 iack != (GIVR_IT_REI | chipid))
1333 ERR(("Bad RX intr ack (%02x != %02x)\n",
1334 iack, GIVR_IT_RGDI | chipid))
1335 chan = (rcin(CD180_GICR) & GICR_CHAN) >> GICR_LSH;
1336 ucnt = rcin(CD180_RDCR) & 0xF;
1337 while (ucnt-- > 0) {
1338 iack = rcin(CD180_RCSR);
1339 if (iack & RCSR_Timeout)
1340 break;
1341 if (iack & 0xF)
1342 ERR(("Bad char chan %d (RCSR = %02X)\n",
1343 chan, iack))
1344 if (tchans[chan].rxptr > CD180_NFIFO)
1345 ERR(("Got extra chars chan %d\n",
1346 chan))
1347 tchans[chan].rxbuf[tchans[chan].rxptr++] =
1348 rcin(CD180_RDR);
1349 }
1350 rcout(CD180_EOIR, 0);
1351 }
1352 rcout(RC_CTOUT, 0);
1353 for (iack = chan = 0; chan < CD180_NCHAN; chan++)
1354 if (tchans[chan].rxptr >= CD180_NFIFO)
1355 iack++;
1356 if (iack == CD180_NCHAN)
1357 break;
1358 }
1359 for (chan = 0; chan < CD180_NCHAN; chan++) {
1360 /* Select and reset channel */
1361 rcout(CD180_CAR, chan);
1362 CCRCMD(unit, chan, CCR_ResetChan);
1363 }
1364
1365 if (!rcnt)
1366 ERR(("looses characters during local loopback\n"))
1367 /* Now, check data */
1368 for (chan = 0; chan < CD180_NCHAN; chan++)
1369 for (i = 0; i < CD180_NFIFO; i++)
1370 if (ctest[i] != tchans[chan].rxbuf[i])
1371 ERR(("data mismatch chan %d ptr %d (%d != %d)\n",
1372 chan, i, ctest[i], tchans[chan].rxbuf[i]))
1373 (void) splx(old_level);
1374 return 0;
1375}
1376
1377#ifdef RCDEBUG
1378static void printrcflags(rc, comment)
1379struct rc_chans *rc;
1380char *comment;
1381{
1382 u_short f = rc->rc_flags;
1383 register int nec = rc->rc_rcb->rcb_addr;
1384
1385 printf("rc%d/%d: %s flags: %s%s%s%s%s%s%s%s%s%s%s%s\n",
1386 rc->rc_rcb->rcb_unit, rc->rc_chan, comment,
1387 (f & RC_DTR_OFF)?"DTR_OFF " :"",
1388 (f & RC_ACTOUT) ?"ACTOUT " :"",
1389 (f & RC_RTSFLOW)?"RTSFLOW " :"",
1390 (f & RC_CTSFLOW)?"CTSFLOW " :"",
1391 (f & RC_DORXFER)?"DORXFER " :"",
1392 (f & RC_DOXXFER)?"DOXXFER " :"",
1393 (f & RC_MODCHG) ?"MODCHG " :"",
1394 (f & RC_OSUSP) ?"OSUSP " :"",
1395 (f & RC_OSBUSY) ?"OSBUSY " :"",
1396 (f & RC_WAS_BUFOVFL) ?"BUFOVFL " :"",
1397 (f & RC_WAS_SILOVFL) ?"SILOVFL " :"",
1398 (f & RC_SEND_RDY) ?"SEND_RDY":"");
1399
1400 rcout(CD180_CAR, rc->rc_chan);
1401
1402 printf("rc%d/%d: msvr %02x ier %02x ccsr %02x\n",
1403 rc->rc_rcb->rcb_unit, rc->rc_chan,
1404 rcin(CD180_MSVR),
1405 rcin(CD180_IER),
1406 rcin(CD180_CCSR));
1407}
1408#endif /* RCDEBUG */
1409
1410static struct tty *
1411rcdevtotty(dev)
1412 dev_t dev;
1413{
1414 int unit;
1415
1416 unit = GET_UNIT(dev);
1417 if (unit >= NRC * CD180_NCHAN)
1418 return NULL;
1419 return (&rc_tty[unit]);
1420}
1421
1422static void
1423rc_dtrwakeup(chan)
1424 void *chan;
1425{
1426 struct rc_chans *rc;
1427
1428 rc = (struct rc_chans *)chan;
1429 rc->rc_flags &= ~RC_DTR_OFF;
1430 wakeup(&rc->rc_dtrwait);
1431}
1432
1433static void
1434rc_discard_output(rc)
1435 struct rc_chans *rc;
1436{
1437 disable_intr();
1438 if (rc->rc_flags & RC_DOXXFER) {
1439 rc_scheduled_event -= LOTS_OF_EVENTS;
1440 rc->rc_flags &= ~RC_DOXXFER;
1441 }
1442 rc->rc_optr = rc->rc_obufend;
1443 rc->rc_tp->t_state &= ~TS_BUSY;
1444 enable_intr();
1445 ttwwakeup(rc->rc_tp);
1446}
1447
1448static void
1449rc_wakeup(chan)
1450 void *chan;
1451{
1452 timeout(rc_wakeup, (caddr_t)NULL, 1);
1453
1454 if (rc_scheduled_event != 0) {
1455 int s;
1456
1457 s = splsofttty();
1458 rcpoll();
1459 splx(s);
1460 }
1461}
1462
1463static void
1464disc_optim(tp, t, rc)
1465 struct tty *tp;
1466 struct termios *t;
1467 struct rc_chans *rc;
1468{
1469
1470 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1471 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1472 && (!(t->c_iflag & PARMRK)
1473 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1474 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1475 && linesw[tp->t_line].l_rint == ttyinput)
1476 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1477 else
1478 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1479 rc->rc_hotchar = linesw[tp->t_line].l_hotchar;
1480}
1481
1482static void
1483rc_wait0(nec, unit, chan, line)
1484 int nec, unit, chan, line;
1485{
1486 int rcnt;
1487
1488 for (rcnt = 50; rcnt && rcin(CD180_CCR); rcnt--)
1489 DELAY(30);
1490 if (rcnt == 0)
1491 printf("rc%d/%d: channel command timeout, rc.c line: %d\n",
1492 unit, chan, line);
1493}
1494
1495#endif /* NRC */