Deleted Added
full compact
cy.c (50477) cy.c (51654)
1/*-
2 * cyclades cyclom-y serial driver
3 * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
4 *
5 * Copyright (c) 1993 Andrew Herbert.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name Andrew Herbert may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
1/*-
2 * cyclades cyclom-y serial driver
3 * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993
4 *
5 * Copyright (c) 1993 Andrew Herbert.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name Andrew Herbert may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
22 * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: head/sys/dev/cy/cy.c 50477 1999-08-28 01:08:13Z peter $
30 * $FreeBSD: head/sys/dev/cy/cy.c 51654 1999-09-25 16:21:39Z phk $
31 */
32
33#include "opt_compat.h"
34#include "cy.h"
35
36/*
37 * TODO:
38 * Atomic COR change.
39 * Consoles.
40 */
41
42/*
43 * Temporary compile-time configuration options.
44 */
45#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2)
46 /* Number of chars in the receiver FIFO before an
47 * an interrupt is generated. Should depend on
48 * line speed. Needs to be about 6 on a 486DX33
49 * for 4 active ports at 115200 bps. Why doesn't
50 * 10 work?
51 */
52#define PollMode /* Use polling-based irq service routine, not the
53 * hardware svcack lines. Must be defined for
54 * Cyclom-16Y boards. Less efficient for Cyclom-8Ys,
55 * and stops 4 * 115200 bps from working.
56 */
57#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly
58 * the output CR/LF processing, plus we can avoid a
59 * few checks usually done in ttyinput().
60 *
61 * XXX not fully implemented, and not particularly
62 * worthwhile.
63 */
64#undef CyDebug /* Include debugging code (not very expensive). */
65
66/* These will go away. */
67#undef SOFT_CTS_OFLOW
68#define SOFT_HOTCHAR
69
70#include <sys/param.h>
71#include <sys/systm.h>
72#include <sys/tty.h>
73#include <sys/proc.h>
74#include <sys/conf.h>
75#include <sys/dkstat.h>
76#include <sys/fcntl.h>
77#include <sys/interrupt.h>
78#include <sys/kernel.h>
79#include <sys/malloc.h>
80#include <sys/syslog.h>
81#include <machine/clock.h>
82#include <machine/ipl.h>
83#ifndef SMP
84#include <machine/lock.h>
85#endif
86#include <machine/psl.h>
87
88#include <i386/isa/isa_device.h>
89#include <i386/isa/cyreg.h>
90#include <i386/isa/ic/cd1400.h>
91
92#ifdef SMP
93#define disable_intr() COM_DISABLE_INTR()
94#define enable_intr() COM_ENABLE_INTR()
95#endif /* SMP */
96
97/*
98 * Dictionary so that I can name everything *sio* or *com* to compare with
99 * sio.c. There is also lots of ugly formatting and unnecessary ifdefs to
100 * simplify the comparision. These will go away.
101 */
102#define LSR_BI CD1400_RDSR_BREAK
103#define LSR_FE CD1400_RDSR_FE
104#define LSR_OE CD1400_RDSR_OE
105#define LSR_PE CD1400_RDSR_PE
106#define MCR_DTR CD1400_MSVR2_DTR
107#define MCR_RTS CD1400_MSVR1_RTS
108#define MSR_CTS CD1400_MSVR2_CTS
109#define MSR_DCD CD1400_MSVR2_CD
110#define MSR_DSR CD1400_MSVR2_DSR
111#define MSR_RI CD1400_MSVR2_RI
112#define NSIO (NCY * CY_MAX_PORTS)
113#define comconsole cyconsole
114#define comdefaultrate cydefaultrate
115#define com_events cy_events
116#define comhardclose cyhardclose
117#define commctl cymctl
118#define comparam cyparam
119#define comspeed cyspeed
120#define comstart cystart
121#define comwakeup cywakeup
122#define nsio_tty ncy_tty
123#define p_com_addr p_cy_addr
124#define sioattach cyattach
125#define sioclose cyclose
31 */
32
33#include "opt_compat.h"
34#include "cy.h"
35
36/*
37 * TODO:
38 * Atomic COR change.
39 * Consoles.
40 */
41
42/*
43 * Temporary compile-time configuration options.
44 */
45#define RxFifoThreshold (CD1400_RX_FIFO_SIZE / 2)
46 /* Number of chars in the receiver FIFO before an
47 * an interrupt is generated. Should depend on
48 * line speed. Needs to be about 6 on a 486DX33
49 * for 4 active ports at 115200 bps. Why doesn't
50 * 10 work?
51 */
52#define PollMode /* Use polling-based irq service routine, not the
53 * hardware svcack lines. Must be defined for
54 * Cyclom-16Y boards. Less efficient for Cyclom-8Ys,
55 * and stops 4 * 115200 bps from working.
56 */
57#undef Smarts /* Enable slightly more CD1400 intelligence. Mainly
58 * the output CR/LF processing, plus we can avoid a
59 * few checks usually done in ttyinput().
60 *
61 * XXX not fully implemented, and not particularly
62 * worthwhile.
63 */
64#undef CyDebug /* Include debugging code (not very expensive). */
65
66/* These will go away. */
67#undef SOFT_CTS_OFLOW
68#define SOFT_HOTCHAR
69
70#include <sys/param.h>
71#include <sys/systm.h>
72#include <sys/tty.h>
73#include <sys/proc.h>
74#include <sys/conf.h>
75#include <sys/dkstat.h>
76#include <sys/fcntl.h>
77#include <sys/interrupt.h>
78#include <sys/kernel.h>
79#include <sys/malloc.h>
80#include <sys/syslog.h>
81#include <machine/clock.h>
82#include <machine/ipl.h>
83#ifndef SMP
84#include <machine/lock.h>
85#endif
86#include <machine/psl.h>
87
88#include <i386/isa/isa_device.h>
89#include <i386/isa/cyreg.h>
90#include <i386/isa/ic/cd1400.h>
91
92#ifdef SMP
93#define disable_intr() COM_DISABLE_INTR()
94#define enable_intr() COM_ENABLE_INTR()
95#endif /* SMP */
96
97/*
98 * Dictionary so that I can name everything *sio* or *com* to compare with
99 * sio.c. There is also lots of ugly formatting and unnecessary ifdefs to
100 * simplify the comparision. These will go away.
101 */
102#define LSR_BI CD1400_RDSR_BREAK
103#define LSR_FE CD1400_RDSR_FE
104#define LSR_OE CD1400_RDSR_OE
105#define LSR_PE CD1400_RDSR_PE
106#define MCR_DTR CD1400_MSVR2_DTR
107#define MCR_RTS CD1400_MSVR1_RTS
108#define MSR_CTS CD1400_MSVR2_CTS
109#define MSR_DCD CD1400_MSVR2_CD
110#define MSR_DSR CD1400_MSVR2_DSR
111#define MSR_RI CD1400_MSVR2_RI
112#define NSIO (NCY * CY_MAX_PORTS)
113#define comconsole cyconsole
114#define comdefaultrate cydefaultrate
115#define com_events cy_events
116#define comhardclose cyhardclose
117#define commctl cymctl
118#define comparam cyparam
119#define comspeed cyspeed
120#define comstart cystart
121#define comwakeup cywakeup
122#define nsio_tty ncy_tty
123#define p_com_addr p_cy_addr
124#define sioattach cyattach
125#define sioclose cyclose
126#define siodevtotty cydevtotty
127#define siodriver cydriver
128#define siodtrwakeup cydtrwakeup
129#define sioinput cyinput
130#define siointr cyintr
131#define siointr1 cyintr1
132#define sioioctl cyioctl
133#define sioopen cyopen
134#define siopoll cypoll
135#define sioprobe cyprobe
136#define sioread cyread
137#define siosettimeout cysettimeout
138#define siosetwater cysetwater
126#define siodriver cydriver
127#define siodtrwakeup cydtrwakeup
128#define sioinput cyinput
129#define siointr cyintr
130#define siointr1 cyintr1
131#define sioioctl cyioctl
132#define sioopen cyopen
133#define siopoll cypoll
134#define sioprobe cyprobe
135#define sioread cyread
136#define siosettimeout cysettimeout
137#define siosetwater cysetwater
139#define siostop cystop
138#define comstop cystop
140#define siowrite cywrite
141#define sio_registered cy_registered
142#define sio_timeout cy_timeout
143#define sio_timeout_handle cy_timeout_handle
144#define sio_timeouts_until_log cy_timeouts_until_log
145#define sio_tty cy_tty
146
147#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)
148
149/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
150#define CD1400_xIVR_CHAN_SHIFT 3
151#define CD1400_xIVR_CHAN 0x1F
152
153/*
154 * ETC states. com->etc may also contain a hardware ETC command value,
155 * meaning that execution of that command is pending.
156 */
157#define ETC_NONE 0 /* we depend on bzero() setting this */
158#define ETC_BREAK_STARTING 1
159#define ETC_BREAK_STARTED 2
160#define ETC_BREAK_ENDING 3
161#define ETC_BREAK_ENDED 4
162
163#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
164
165#define CALLOUT_MASK 0x80
166#define CONTROL_MASK 0x60
167#define CONTROL_INIT_STATE 0x20
168#define CONTROL_LOCK_STATE 0x40
169#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
170#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
171#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS \
172 | (((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
173
174/*
175 * com state bits.
176 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
177 * than the other bits so that they can be tested as a group without masking
178 * off the low bits.
179 *
180 * The following com and tty flags correspond closely:
181 * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and
139#define siowrite cywrite
140#define sio_registered cy_registered
141#define sio_timeout cy_timeout
142#define sio_timeout_handle cy_timeout_handle
143#define sio_timeouts_until_log cy_timeouts_until_log
144#define sio_tty cy_tty
145
146#define CY_MAX_PORTS (CD1400_NO_OF_CHANNELS * CY_MAX_CD1400s)
147
148/* We encode the cyclom unit number (cyu) in spare bits in the IVR's. */
149#define CD1400_xIVR_CHAN_SHIFT 3
150#define CD1400_xIVR_CHAN 0x1F
151
152/*
153 * ETC states. com->etc may also contain a hardware ETC command value,
154 * meaning that execution of that command is pending.
155 */
156#define ETC_NONE 0 /* we depend on bzero() setting this */
157#define ETC_BREAK_STARTING 1
158#define ETC_BREAK_STARTED 2
159#define ETC_BREAK_ENDING 3
160#define ETC_BREAK_ENDED 4
161
162#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
163
164#define CALLOUT_MASK 0x80
165#define CONTROL_MASK 0x60
166#define CONTROL_INIT_STATE 0x20
167#define CONTROL_LOCK_STATE 0x40
168#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
169#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
170#define MINOR_TO_UNIT(mynor) (((mynor) >> 16) * CY_MAX_PORTS \
171 | (((mynor) & 0xff) & ~MINOR_MAGIC_MASK))
172
173/*
174 * com state bits.
175 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
176 * than the other bits so that they can be tested as a group without masking
177 * off the low bits.
178 *
179 * The following com and tty flags correspond closely:
180 * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and
182 * siostop())
181 * comstop())
183 * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart())
184 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
185 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
186 * TS_FLUSH is not used.
187 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
188 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
189 */
190#define CS_BUSY 0x80 /* output in progress */
191#define CS_TTGO 0x40 /* output not stopped by XOFF */
192#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
193#define CS_CHECKMSR 1 /* check of MSR scheduled */
194#define CS_CTS_OFLOW 2 /* use CTS output flow control */
195#define CS_DTR_OFF 0x10 /* DTR held off */
196#define CS_ODONE 4 /* output completed */
197#define CS_RTS_IFLOW 8 /* use RTS input flow control */
198#define CSE_ODONE 1 /* output transmitted */
199
200static char const * const error_desc[] = {
201#define CE_OVERRUN 0
202 "silo overflow",
203#define CE_INTERRUPT_BUF_OVERFLOW 1
204 "interrupt-level buffer overflow",
205#define CE_TTY_BUF_OVERFLOW 2
206 "tty-level buffer overflow",
207};
208
209#define CE_NTYPES 3
210#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
211
212/* types. XXX - should be elsewhere */
213typedef u_char bool_t; /* boolean */
214typedef u_char volatile *cy_addr;
215
216/* queue of linear buffers */
217struct lbq {
218 u_char *l_head; /* next char to process */
219 u_char *l_tail; /* one past the last char to process */
220 struct lbq *l_next; /* next in queue */
221 bool_t l_queued; /* nonzero if queued */
222};
223
224/* com device structure */
225struct com_s {
226 u_char state; /* miscellaneous flag bits */
227 bool_t active_out; /* nonzero if the callout device is open */
228#if 0
229 u_char cfcr_image; /* copy of value written to CFCR */
230#endif
231 u_char etc; /* pending Embedded Transmit Command */
232 u_char extra_state; /* more flag bits, separate for order trick */
233#if 0
234 u_char fifo_image; /* copy of value written to FIFO */
235#endif
236 u_char gfrcr_image; /* copy of value read from GFRCR */
237#if 0
238 bool_t hasfifo; /* nonzero for 16550 UARTs */
239 bool_t loses_outints; /* nonzero if device loses output interrupts */
240#endif
241 u_char mcr_dtr; /* MCR bit that is wired to DTR */
242 u_char mcr_image; /* copy of value written to MCR */
243 u_char mcr_rts; /* MCR bit that is wired to RTS */
244#if 0
245#ifdef COM_MULTIPORT
246 bool_t multiport; /* is this unit part of a multiport device? */
247#endif /* COM_MULTIPORT */
248 bool_t no_irq; /* nonzero if irq is not attached */
249 bool_t poll; /* nonzero if polling is required */
250 bool_t poll_output; /* nonzero if polling for output is required */
251#endif
252 int unit; /* unit number */
253 int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
254#if 0
255 u_int tx_fifo_size;
256#endif
257 u_int wopeners; /* # processes waiting for DCD in open() */
258
259 /*
260 * The high level of the driver never reads status registers directly
261 * because there would be too many side effects to handle conveniently.
262 * Instead, it reads copies of the registers stored here by the
263 * interrupt handler.
264 */
265 u_char last_modem_status; /* last MSR read by intr handler */
266 u_char prev_modem_status; /* last MSR handled by high level */
267
268 u_char hotchar; /* ldisc-specific char to be handled ASAP */
269 u_char *ibuf; /* start of input buffer */
270 u_char *ibufend; /* end of input buffer */
271 u_char *ibufold; /* old input buffer, to be freed */
272 u_char *ihighwater; /* threshold in input buffer */
273 u_char *iptr; /* next free spot in input buffer */
274 int ibufsize; /* size of ibuf (not include error bytes) */
275 int ierroff; /* offset of error bytes in ibuf */
276
277 struct lbq obufq; /* head of queue of output buffers */
278 struct lbq obufs[2]; /* output buffers */
279
280 int cy_align; /* index for register alignment */
281 cy_addr cy_iobase; /* base address of this port's cyclom */
282 cy_addr iobase; /* base address of this port's cd1400 */
283 int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */
284
285 struct tty *tp; /* cross reference */
286
287 /* Initial state. */
288 struct termios it_in; /* should be in struct tty */
289 struct termios it_out;
290
291 /* Lock state. */
292 struct termios lt_in; /* should be in struct tty */
293 struct termios lt_out;
294
295 bool_t do_timestamp;
296 bool_t do_dcd_timestamp;
297 struct timeval timestamp;
298 struct timeval dcd_timestamp;
299
300 u_long bytes_in; /* statistics */
301 u_long bytes_out;
302 u_int delta_error_counts[CE_NTYPES];
303 u_long error_counts[CE_NTYPES];
304
305 u_int recv_exception; /* exception chars received */
306 u_int mdm; /* modem signal changes */
307#ifdef CyDebug
308 u_int start_count; /* no. of calls to comstart() */
309 u_int start_real; /* no. of calls that did something */
310#endif
311 u_char car; /* CD1400 CAR shadow (if first unit in cd) */
312 u_char channel_control;/* CD1400 CCR control command shadow */
313 u_char cor[3]; /* CD1400 COR1-3 shadows */
314 u_char intr_enable; /* CD1400 SRER shadow */
315
316 /*
317 * Data area for output buffers. Someday we should build the output
318 * buffer queue without copying data.
319 */
320 u_char obuf1[256];
321 u_char obuf2[256];
322};
323
324/* PCI driver entry point. */
325int cyattach_common __P((cy_addr cy_iobase, int cy_align));
326ointhand2_t siointr;
327
328static int cy_units __P((cy_addr cy_iobase, int cy_align));
329static int sioattach __P((struct isa_device *dev));
330static void cd1400_channel_cmd __P((struct com_s *com, int cmd));
331static void cd1400_channel_cmd_wait __P((struct com_s *com));
332static void cd_etc __P((struct com_s *com, int etc));
333static int cd_getreg __P((struct com_s *com, int reg));
334static void cd_setreg __P((struct com_s *com, int reg, int val));
335static timeout_t siodtrwakeup;
336static void comhardclose __P((struct com_s *com));
337static void sioinput __P((struct com_s *com));
338#if 0
339static void siointr1 __P((struct com_s *com));
340#endif
341static int commctl __P((struct com_s *com, int bits, int how));
342static int comparam __P((struct tty *tp, struct termios *t));
343static swihand_t siopoll;
344static int sioprobe __P((struct isa_device *dev));
345static void siosettimeout __P((void));
346static int siosetwater __P((struct com_s *com, speed_t speed));
347static int comspeed __P((speed_t speed, u_long cy_clock,
348 int *prescaler_io));
349static void comstart __P((struct tty *tp));
182 * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart())
183 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
184 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
185 * TS_FLUSH is not used.
186 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
187 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
188 */
189#define CS_BUSY 0x80 /* output in progress */
190#define CS_TTGO 0x40 /* output not stopped by XOFF */
191#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
192#define CS_CHECKMSR 1 /* check of MSR scheduled */
193#define CS_CTS_OFLOW 2 /* use CTS output flow control */
194#define CS_DTR_OFF 0x10 /* DTR held off */
195#define CS_ODONE 4 /* output completed */
196#define CS_RTS_IFLOW 8 /* use RTS input flow control */
197#define CSE_ODONE 1 /* output transmitted */
198
199static char const * const error_desc[] = {
200#define CE_OVERRUN 0
201 "silo overflow",
202#define CE_INTERRUPT_BUF_OVERFLOW 1
203 "interrupt-level buffer overflow",
204#define CE_TTY_BUF_OVERFLOW 2
205 "tty-level buffer overflow",
206};
207
208#define CE_NTYPES 3
209#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
210
211/* types. XXX - should be elsewhere */
212typedef u_char bool_t; /* boolean */
213typedef u_char volatile *cy_addr;
214
215/* queue of linear buffers */
216struct lbq {
217 u_char *l_head; /* next char to process */
218 u_char *l_tail; /* one past the last char to process */
219 struct lbq *l_next; /* next in queue */
220 bool_t l_queued; /* nonzero if queued */
221};
222
223/* com device structure */
224struct com_s {
225 u_char state; /* miscellaneous flag bits */
226 bool_t active_out; /* nonzero if the callout device is open */
227#if 0
228 u_char cfcr_image; /* copy of value written to CFCR */
229#endif
230 u_char etc; /* pending Embedded Transmit Command */
231 u_char extra_state; /* more flag bits, separate for order trick */
232#if 0
233 u_char fifo_image; /* copy of value written to FIFO */
234#endif
235 u_char gfrcr_image; /* copy of value read from GFRCR */
236#if 0
237 bool_t hasfifo; /* nonzero for 16550 UARTs */
238 bool_t loses_outints; /* nonzero if device loses output interrupts */
239#endif
240 u_char mcr_dtr; /* MCR bit that is wired to DTR */
241 u_char mcr_image; /* copy of value written to MCR */
242 u_char mcr_rts; /* MCR bit that is wired to RTS */
243#if 0
244#ifdef COM_MULTIPORT
245 bool_t multiport; /* is this unit part of a multiport device? */
246#endif /* COM_MULTIPORT */
247 bool_t no_irq; /* nonzero if irq is not attached */
248 bool_t poll; /* nonzero if polling is required */
249 bool_t poll_output; /* nonzero if polling for output is required */
250#endif
251 int unit; /* unit number */
252 int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
253#if 0
254 u_int tx_fifo_size;
255#endif
256 u_int wopeners; /* # processes waiting for DCD in open() */
257
258 /*
259 * The high level of the driver never reads status registers directly
260 * because there would be too many side effects to handle conveniently.
261 * Instead, it reads copies of the registers stored here by the
262 * interrupt handler.
263 */
264 u_char last_modem_status; /* last MSR read by intr handler */
265 u_char prev_modem_status; /* last MSR handled by high level */
266
267 u_char hotchar; /* ldisc-specific char to be handled ASAP */
268 u_char *ibuf; /* start of input buffer */
269 u_char *ibufend; /* end of input buffer */
270 u_char *ibufold; /* old input buffer, to be freed */
271 u_char *ihighwater; /* threshold in input buffer */
272 u_char *iptr; /* next free spot in input buffer */
273 int ibufsize; /* size of ibuf (not include error bytes) */
274 int ierroff; /* offset of error bytes in ibuf */
275
276 struct lbq obufq; /* head of queue of output buffers */
277 struct lbq obufs[2]; /* output buffers */
278
279 int cy_align; /* index for register alignment */
280 cy_addr cy_iobase; /* base address of this port's cyclom */
281 cy_addr iobase; /* base address of this port's cd1400 */
282 int mcr_rts_reg; /* cd1400 reg number of reg holding mcr_rts */
283
284 struct tty *tp; /* cross reference */
285
286 /* Initial state. */
287 struct termios it_in; /* should be in struct tty */
288 struct termios it_out;
289
290 /* Lock state. */
291 struct termios lt_in; /* should be in struct tty */
292 struct termios lt_out;
293
294 bool_t do_timestamp;
295 bool_t do_dcd_timestamp;
296 struct timeval timestamp;
297 struct timeval dcd_timestamp;
298
299 u_long bytes_in; /* statistics */
300 u_long bytes_out;
301 u_int delta_error_counts[CE_NTYPES];
302 u_long error_counts[CE_NTYPES];
303
304 u_int recv_exception; /* exception chars received */
305 u_int mdm; /* modem signal changes */
306#ifdef CyDebug
307 u_int start_count; /* no. of calls to comstart() */
308 u_int start_real; /* no. of calls that did something */
309#endif
310 u_char car; /* CD1400 CAR shadow (if first unit in cd) */
311 u_char channel_control;/* CD1400 CCR control command shadow */
312 u_char cor[3]; /* CD1400 COR1-3 shadows */
313 u_char intr_enable; /* CD1400 SRER shadow */
314
315 /*
316 * Data area for output buffers. Someday we should build the output
317 * buffer queue without copying data.
318 */
319 u_char obuf1[256];
320 u_char obuf2[256];
321};
322
323/* PCI driver entry point. */
324int cyattach_common __P((cy_addr cy_iobase, int cy_align));
325ointhand2_t siointr;
326
327static int cy_units __P((cy_addr cy_iobase, int cy_align));
328static int sioattach __P((struct isa_device *dev));
329static void cd1400_channel_cmd __P((struct com_s *com, int cmd));
330static void cd1400_channel_cmd_wait __P((struct com_s *com));
331static void cd_etc __P((struct com_s *com, int etc));
332static int cd_getreg __P((struct com_s *com, int reg));
333static void cd_setreg __P((struct com_s *com, int reg, int val));
334static timeout_t siodtrwakeup;
335static void comhardclose __P((struct com_s *com));
336static void sioinput __P((struct com_s *com));
337#if 0
338static void siointr1 __P((struct com_s *com));
339#endif
340static int commctl __P((struct com_s *com, int bits, int how));
341static int comparam __P((struct tty *tp, struct termios *t));
342static swihand_t siopoll;
343static int sioprobe __P((struct isa_device *dev));
344static void siosettimeout __P((void));
345static int siosetwater __P((struct com_s *com, speed_t speed));
346static int comspeed __P((speed_t speed, u_long cy_clock,
347 int *prescaler_io));
348static void comstart __P((struct tty *tp));
349static void comstop __P((struct tty *tp, int rw));
350static timeout_t comwakeup;
351static void disc_optim __P((struct tty *tp, struct termios *t,
352 struct com_s *com));
353
354#ifdef CyDebug
355void cystatus __P((int unit));
356#endif
357
358static char driver_name[] = "cy";
359
360/* table and macro for fast conversion from a unit number to its com struct */
361static struct com_s *p_com_addr[NSIO];
362#define com_addr(unit) (p_com_addr[unit])
363
364struct isa_driver siodriver = {
365 sioprobe, sioattach, driver_name
366};
367
368static d_open_t sioopen;
369static d_close_t sioclose;
370static d_read_t sioread;
371static d_write_t siowrite;
372static d_ioctl_t sioioctl;
350static timeout_t comwakeup;
351static void disc_optim __P((struct tty *tp, struct termios *t,
352 struct com_s *com));
353
354#ifdef CyDebug
355void cystatus __P((int unit));
356#endif
357
358static char driver_name[] = "cy";
359
360/* table and macro for fast conversion from a unit number to its com struct */
361static struct com_s *p_com_addr[NSIO];
362#define com_addr(unit) (p_com_addr[unit])
363
364struct isa_driver siodriver = {
365 sioprobe, sioattach, driver_name
366};
367
368static d_open_t sioopen;
369static d_close_t sioclose;
370static d_read_t sioread;
371static d_write_t siowrite;
372static d_ioctl_t sioioctl;
373static d_stop_t siostop;
374static d_devtotty_t siodevtotty;
375
376#define CDEV_MAJOR 48
377static struct cdevsw sio_cdevsw = {
378 /* open */ sioopen,
379 /* close */ sioclose,
380 /* read */ sioread,
381 /* write */ siowrite,
382 /* ioctl */ sioioctl,
373
374#define CDEV_MAJOR 48
375static struct cdevsw sio_cdevsw = {
376 /* open */ sioopen,
377 /* close */ sioclose,
378 /* read */ sioread,
379 /* write */ siowrite,
380 /* ioctl */ sioioctl,
383 /* stop */ siostop,
381 /* stop */ nostop,
384 /* reset */ noreset,
382 /* reset */ noreset,
385 /* devtotty */ siodevtotty,
386 /* poll */ ttpoll,
383 /* devtotty */ nodevtotty,
384 /* poll */ ttypoll,
387 /* mmap */ nommap,
388 /* strategy */ nostrategy,
389 /* name */ driver_name,
390 /* parms */ noparms,
391 /* maj */ CDEV_MAJOR,
392 /* dump */ nodump,
393 /* psize */ nopsize,
394 /* flags */ D_TTY,
395 /* maxio */ 0,
396 /* bmaj */ -1
397};
398
399static int comconsole = -1;
400static speed_t comdefaultrate = TTYDEF_SPEED;
401static u_int com_events; /* input chars + weighted output completions */
402static bool_t sio_registered;
403static int sio_timeout;
404static int sio_timeouts_until_log;
405static struct callout_handle sio_timeout_handle
406 = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
407#if 0 /* XXX */
408static struct tty *sio_tty[NSIO];
409#else
410static struct tty sio_tty[NSIO];
411#endif
412static const int nsio_tty = NSIO;
413
414#ifdef CyDebug
415static u_int cd_inbs;
416static u_int cy_inbs;
417static u_int cd_outbs;
418static u_int cy_outbs;
419static u_int cy_svrr_probes;
420static u_int cy_timeouts;
421#endif
422
423static int cy_chip_offset[] = {
424 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00,
425};
426static int cy_nr_cd1400s[NCY];
427static int cy_total_devices;
428#undef RxFifoThreshold
429static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
430
431static int
432sioprobe(dev)
433 struct isa_device *dev;
434{
435 cy_addr iobase;
436
437 iobase = (cy_addr)dev->id_maddr;
438
439 /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
440 cy_inb(iobase, CY16_RESET, 0); /* XXX? */
441 DELAY(500); /* wait for the board to get its act together */
442
443 /* this is needed to get the board out of reset */
444 cy_outb(iobase, CY_CLEAR_INTR, 0, 0);
445 DELAY(500);
446
447 return (cy_units(iobase, 0) == 0 ? 0 : -1);
448}
449
450static int
451cy_units(cy_iobase, cy_align)
452 cy_addr cy_iobase;
453 int cy_align;
454{
455 int cyu;
456 u_char firmware_version;
457 int i;
458 cy_addr iobase;
459
460 for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
461 iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
462
463 /* wait for chip to become ready for new command */
464 for (i = 0; i < 10; i++) {
465 DELAY(50);
466 if (!cd_inb(iobase, CD1400_CCR, cy_align))
467 break;
468 }
469
470 /* clear the GFRCR register */
471 cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
472
473 /* issue a reset command */
474 cd_outb(iobase, CD1400_CCR, cy_align,
475 CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
476
477 /* wait for the CD1400 to initialize itself */
478 for (i = 0; i < 200; i++) {
479 DELAY(50);
480
481 /* retrieve firmware version */
482 firmware_version = cd_inb(iobase, CD1400_GFRCR,
483 cy_align);
484 if ((firmware_version & 0xf0) == 0x40)
485 break;
486 }
487
488 /*
489 * Anything in the 0x40-0x4F range is fine.
490 * If one CD1400 is bad then we don't support higher
491 * numbered good ones on this board.
492 */
493 if ((firmware_version & 0xf0) != 0x40)
494 break;
495 }
496 return (cyu);
497}
498
499static int
500sioattach(isdp)
501 struct isa_device *isdp;
502{
503 int adapter;
504
505 adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
506 if (adapter < 0)
507 return (0);
508
509 /*
510 * XXX
511 * This kludge is to allow ISA/PCI device specifications in the
512 * kernel config file to be in any order.
513 */
514 if (isdp->id_unit != adapter) {
515 printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
516 isdp->id_unit = adapter; /* XXX */
517 }
518 isdp->id_ointr = siointr;
519 isdp->id_ri_flags |= RI_FAST;
520 return (1);
521}
522
523int
524cyattach_common(cy_iobase, cy_align)
525 cy_addr cy_iobase;
526 int cy_align;
527{
528 int adapter;
529 int cyu;
530 u_char firmware_version;
531 cy_addr iobase;
532 int ncyu;
533 int unit;
534
535 adapter = cy_total_devices;
536 if ((u_int)adapter >= NCY) {
537 printf(
538 "cy%d: can't attach adapter: insufficient cy devices configured\n",
539 adapter);
540 return (-1);
541 }
542 ncyu = cy_units(cy_iobase, cy_align);
543 if (ncyu == 0)
544 return (-1);
545 cy_nr_cd1400s[adapter] = ncyu;
546 cy_total_devices++;
547
548 unit = adapter * CY_MAX_PORTS;
549 for (cyu = 0; cyu < ncyu; ++cyu) {
550 int cdu;
551
552 iobase = (cy_addr) (cy_iobase
553 + (cy_chip_offset[cyu] << cy_align));
554 firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
555
556 /* Set up a receive timeout period of than 1+ ms. */
557 cd_outb(iobase, CD1400_PPR, cy_align,
558 howmany(CY_CLOCK(firmware_version)
559 / CD1400_PPR_PRESCALER, 1000));
560
561 for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
562 struct com_s *com;
563 int s;
564
565 com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
566 if (com == NULL)
567 break;
568 bzero(com, sizeof *com);
569 com->unit = unit;
570 com->gfrcr_image = firmware_version;
571 if (CY_RTS_DTR_SWAPPED(firmware_version)) {
572 com->mcr_dtr = MCR_RTS;
573 com->mcr_rts = MCR_DTR;
574 com->mcr_rts_reg = CD1400_MSVR2;
575 } else {
576 com->mcr_dtr = MCR_DTR;
577 com->mcr_rts = MCR_RTS;
578 com->mcr_rts_reg = CD1400_MSVR1;
579 }
580 com->dtr_wait = 3 * hz;
581 com->obufs[0].l_head = com->obuf1;
582 com->obufs[1].l_head = com->obuf2;
583
584 com->cy_align = cy_align;
585 com->cy_iobase = cy_iobase;
586 com->iobase = iobase;
587 com->car = ~CD1400_CAR_CHAN;
588
589 /*
590 * We don't use all the flags from <sys/ttydefaults.h> since they
591 * are only relevant for logins. It's important to have echo off
592 * initially so that the line doesn't start blathering before the
593 * echo flag can be turned off.
594 */
595 com->it_in.c_iflag = 0;
596 com->it_in.c_oflag = 0;
597 com->it_in.c_cflag = TTYDEF_CFLAG;
598 com->it_in.c_lflag = 0;
599 if (unit == comconsole) {
600 com->it_in.c_iflag = TTYDEF_IFLAG;
601 com->it_in.c_oflag = TTYDEF_OFLAG;
602 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
603 com->it_in.c_lflag = TTYDEF_LFLAG;
604 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
605 }
606 if (siosetwater(com, com->it_in.c_ispeed) != 0) {
607 enable_intr();
608 free(com, M_DEVBUF);
609 return (0);
610 }
611 enable_intr();
612 termioschars(&com->it_in);
613 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
614 com->it_out = com->it_in;
615
616 s = spltty();
617 com_addr(unit) = com;
618 splx(s);
619
620 if (!sio_registered) {
621 cdevsw_add(&sio_cdevsw);
622 register_swi(SWI_TTY, siopoll);
623 sio_registered = TRUE;
624 }
625 make_dev(&sio_cdevsw, unit,
626 UID_ROOT, GID_WHEEL, 0600, "ttyc%r%r", adapter,
627 unit % CY_MAX_PORTS);
628 make_dev(&sio_cdevsw, unit | CONTROL_INIT_STATE,
629 UID_ROOT, GID_WHEEL, 0600, "ttyic%r%r", adapter,
630 unit % CY_MAX_PORTS);
631 make_dev(&sio_cdevsw, unit | CONTROL_LOCK_STATE,
632 UID_ROOT, GID_WHEEL, 0600, "ttylc%r%r", adapter,
633 unit % CY_MAX_PORTS);
634 make_dev(&sio_cdevsw, unit | CALLOUT_MASK,
635 UID_UUCP, GID_DIALER, 0660, "cuac%r%r", adapter,
636 unit % CY_MAX_PORTS);
637 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_INIT_STATE,
638 UID_UUCP, GID_DIALER, 0660, "cuaic%r%r", adapter,
639 unit % CY_MAX_PORTS);
640 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_LOCK_STATE,
641 UID_UUCP, GID_DIALER, 0660, "cualc%r%r", adapter,
642 unit % CY_MAX_PORTS);
643 }
644 }
645
646 /* ensure an edge for the next interrupt */
647 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
648
649 return (adapter);
650}
651
652static int
653sioopen(dev, flag, mode, p)
654 dev_t dev;
655 int flag;
656 int mode;
657 struct proc *p;
658{
659 struct com_s *com;
660 int error;
661 int mynor;
662 int s;
663 struct tty *tp;
664 int unit;
665
666 mynor = minor(dev);
667 unit = MINOR_TO_UNIT(mynor);
668 if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
669 return (ENXIO);
670 if (mynor & CONTROL_MASK)
671 return (0);
672#if 0 /* XXX */
673 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
674#else
675 tp = com->tp = &sio_tty[unit];
676#endif
385 /* mmap */ nommap,
386 /* strategy */ nostrategy,
387 /* name */ driver_name,
388 /* parms */ noparms,
389 /* maj */ CDEV_MAJOR,
390 /* dump */ nodump,
391 /* psize */ nopsize,
392 /* flags */ D_TTY,
393 /* maxio */ 0,
394 /* bmaj */ -1
395};
396
397static int comconsole = -1;
398static speed_t comdefaultrate = TTYDEF_SPEED;
399static u_int com_events; /* input chars + weighted output completions */
400static bool_t sio_registered;
401static int sio_timeout;
402static int sio_timeouts_until_log;
403static struct callout_handle sio_timeout_handle
404 = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
405#if 0 /* XXX */
406static struct tty *sio_tty[NSIO];
407#else
408static struct tty sio_tty[NSIO];
409#endif
410static const int nsio_tty = NSIO;
411
412#ifdef CyDebug
413static u_int cd_inbs;
414static u_int cy_inbs;
415static u_int cd_outbs;
416static u_int cy_outbs;
417static u_int cy_svrr_probes;
418static u_int cy_timeouts;
419#endif
420
421static int cy_chip_offset[] = {
422 0x0000, 0x0400, 0x0800, 0x0c00, 0x0200, 0x0600, 0x0a00, 0x0e00,
423};
424static int cy_nr_cd1400s[NCY];
425static int cy_total_devices;
426#undef RxFifoThreshold
427static int volatile RxFifoThreshold = (CD1400_RX_FIFO_SIZE / 2);
428
429static int
430sioprobe(dev)
431 struct isa_device *dev;
432{
433 cy_addr iobase;
434
435 iobase = (cy_addr)dev->id_maddr;
436
437 /* Cyclom-16Y hardware reset (Cyclom-8Ys don't care) */
438 cy_inb(iobase, CY16_RESET, 0); /* XXX? */
439 DELAY(500); /* wait for the board to get its act together */
440
441 /* this is needed to get the board out of reset */
442 cy_outb(iobase, CY_CLEAR_INTR, 0, 0);
443 DELAY(500);
444
445 return (cy_units(iobase, 0) == 0 ? 0 : -1);
446}
447
448static int
449cy_units(cy_iobase, cy_align)
450 cy_addr cy_iobase;
451 int cy_align;
452{
453 int cyu;
454 u_char firmware_version;
455 int i;
456 cy_addr iobase;
457
458 for (cyu = 0; cyu < CY_MAX_CD1400s; ++cyu) {
459 iobase = cy_iobase + (cy_chip_offset[cyu] << cy_align);
460
461 /* wait for chip to become ready for new command */
462 for (i = 0; i < 10; i++) {
463 DELAY(50);
464 if (!cd_inb(iobase, CD1400_CCR, cy_align))
465 break;
466 }
467
468 /* clear the GFRCR register */
469 cd_outb(iobase, CD1400_GFRCR, cy_align, 0);
470
471 /* issue a reset command */
472 cd_outb(iobase, CD1400_CCR, cy_align,
473 CD1400_CCR_CMDRESET | CD1400_CCR_FULLRESET);
474
475 /* wait for the CD1400 to initialize itself */
476 for (i = 0; i < 200; i++) {
477 DELAY(50);
478
479 /* retrieve firmware version */
480 firmware_version = cd_inb(iobase, CD1400_GFRCR,
481 cy_align);
482 if ((firmware_version & 0xf0) == 0x40)
483 break;
484 }
485
486 /*
487 * Anything in the 0x40-0x4F range is fine.
488 * If one CD1400 is bad then we don't support higher
489 * numbered good ones on this board.
490 */
491 if ((firmware_version & 0xf0) != 0x40)
492 break;
493 }
494 return (cyu);
495}
496
497static int
498sioattach(isdp)
499 struct isa_device *isdp;
500{
501 int adapter;
502
503 adapter = cyattach_common((cy_addr) isdp->id_maddr, 0);
504 if (adapter < 0)
505 return (0);
506
507 /*
508 * XXX
509 * This kludge is to allow ISA/PCI device specifications in the
510 * kernel config file to be in any order.
511 */
512 if (isdp->id_unit != adapter) {
513 printf("cy%d: attached as cy%d\n", isdp->id_unit, adapter);
514 isdp->id_unit = adapter; /* XXX */
515 }
516 isdp->id_ointr = siointr;
517 isdp->id_ri_flags |= RI_FAST;
518 return (1);
519}
520
521int
522cyattach_common(cy_iobase, cy_align)
523 cy_addr cy_iobase;
524 int cy_align;
525{
526 int adapter;
527 int cyu;
528 u_char firmware_version;
529 cy_addr iobase;
530 int ncyu;
531 int unit;
532
533 adapter = cy_total_devices;
534 if ((u_int)adapter >= NCY) {
535 printf(
536 "cy%d: can't attach adapter: insufficient cy devices configured\n",
537 adapter);
538 return (-1);
539 }
540 ncyu = cy_units(cy_iobase, cy_align);
541 if (ncyu == 0)
542 return (-1);
543 cy_nr_cd1400s[adapter] = ncyu;
544 cy_total_devices++;
545
546 unit = adapter * CY_MAX_PORTS;
547 for (cyu = 0; cyu < ncyu; ++cyu) {
548 int cdu;
549
550 iobase = (cy_addr) (cy_iobase
551 + (cy_chip_offset[cyu] << cy_align));
552 firmware_version = cd_inb(iobase, CD1400_GFRCR, cy_align);
553
554 /* Set up a receive timeout period of than 1+ ms. */
555 cd_outb(iobase, CD1400_PPR, cy_align,
556 howmany(CY_CLOCK(firmware_version)
557 / CD1400_PPR_PRESCALER, 1000));
558
559 for (cdu = 0; cdu < CD1400_NO_OF_CHANNELS; ++cdu, ++unit) {
560 struct com_s *com;
561 int s;
562
563 com = malloc(sizeof *com, M_DEVBUF, M_NOWAIT);
564 if (com == NULL)
565 break;
566 bzero(com, sizeof *com);
567 com->unit = unit;
568 com->gfrcr_image = firmware_version;
569 if (CY_RTS_DTR_SWAPPED(firmware_version)) {
570 com->mcr_dtr = MCR_RTS;
571 com->mcr_rts = MCR_DTR;
572 com->mcr_rts_reg = CD1400_MSVR2;
573 } else {
574 com->mcr_dtr = MCR_DTR;
575 com->mcr_rts = MCR_RTS;
576 com->mcr_rts_reg = CD1400_MSVR1;
577 }
578 com->dtr_wait = 3 * hz;
579 com->obufs[0].l_head = com->obuf1;
580 com->obufs[1].l_head = com->obuf2;
581
582 com->cy_align = cy_align;
583 com->cy_iobase = cy_iobase;
584 com->iobase = iobase;
585 com->car = ~CD1400_CAR_CHAN;
586
587 /*
588 * We don't use all the flags from <sys/ttydefaults.h> since they
589 * are only relevant for logins. It's important to have echo off
590 * initially so that the line doesn't start blathering before the
591 * echo flag can be turned off.
592 */
593 com->it_in.c_iflag = 0;
594 com->it_in.c_oflag = 0;
595 com->it_in.c_cflag = TTYDEF_CFLAG;
596 com->it_in.c_lflag = 0;
597 if (unit == comconsole) {
598 com->it_in.c_iflag = TTYDEF_IFLAG;
599 com->it_in.c_oflag = TTYDEF_OFLAG;
600 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
601 com->it_in.c_lflag = TTYDEF_LFLAG;
602 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
603 }
604 if (siosetwater(com, com->it_in.c_ispeed) != 0) {
605 enable_intr();
606 free(com, M_DEVBUF);
607 return (0);
608 }
609 enable_intr();
610 termioschars(&com->it_in);
611 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
612 com->it_out = com->it_in;
613
614 s = spltty();
615 com_addr(unit) = com;
616 splx(s);
617
618 if (!sio_registered) {
619 cdevsw_add(&sio_cdevsw);
620 register_swi(SWI_TTY, siopoll);
621 sio_registered = TRUE;
622 }
623 make_dev(&sio_cdevsw, unit,
624 UID_ROOT, GID_WHEEL, 0600, "ttyc%r%r", adapter,
625 unit % CY_MAX_PORTS);
626 make_dev(&sio_cdevsw, unit | CONTROL_INIT_STATE,
627 UID_ROOT, GID_WHEEL, 0600, "ttyic%r%r", adapter,
628 unit % CY_MAX_PORTS);
629 make_dev(&sio_cdevsw, unit | CONTROL_LOCK_STATE,
630 UID_ROOT, GID_WHEEL, 0600, "ttylc%r%r", adapter,
631 unit % CY_MAX_PORTS);
632 make_dev(&sio_cdevsw, unit | CALLOUT_MASK,
633 UID_UUCP, GID_DIALER, 0660, "cuac%r%r", adapter,
634 unit % CY_MAX_PORTS);
635 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_INIT_STATE,
636 UID_UUCP, GID_DIALER, 0660, "cuaic%r%r", adapter,
637 unit % CY_MAX_PORTS);
638 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_LOCK_STATE,
639 UID_UUCP, GID_DIALER, 0660, "cualc%r%r", adapter,
640 unit % CY_MAX_PORTS);
641 }
642 }
643
644 /* ensure an edge for the next interrupt */
645 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
646
647 return (adapter);
648}
649
650static int
651sioopen(dev, flag, mode, p)
652 dev_t dev;
653 int flag;
654 int mode;
655 struct proc *p;
656{
657 struct com_s *com;
658 int error;
659 int mynor;
660 int s;
661 struct tty *tp;
662 int unit;
663
664 mynor = minor(dev);
665 unit = MINOR_TO_UNIT(mynor);
666 if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
667 return (ENXIO);
668 if (mynor & CONTROL_MASK)
669 return (0);
670#if 0 /* XXX */
671 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
672#else
673 tp = com->tp = &sio_tty[unit];
674#endif
675 dev->si_tty = tp;
677 s = spltty();
678 /*
679 * We jump to this label after all non-interrupted sleeps to pick
680 * up any changes of the device state.
681 */
682open_top:
683 while (com->state & CS_DTR_OFF) {
684 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0);
685 if (error != 0)
686 goto out;
687 }
688 if (tp->t_state & TS_ISOPEN) {
689 /*
690 * The device is open, so everything has been initialized.
691 * Handle conflicts.
692 */
693 if (mynor & CALLOUT_MASK) {
694 if (!com->active_out) {
695 error = EBUSY;
696 goto out;
697 }
698 } else {
699 if (com->active_out) {
700 if (flag & O_NONBLOCK) {
701 error = EBUSY;
702 goto out;
703 }
704 error = tsleep(&com->active_out,
705 TTIPRI | PCATCH, "cybi", 0);
706 if (error != 0)
707 goto out;
708 goto open_top;
709 }
710 }
711 if (tp->t_state & TS_XCLUDE &&
712 suser(p)) {
713 error = EBUSY;
714 goto out;
715 }
716 } else {
717 /*
718 * The device isn't open, so there are no conflicts.
719 * Initialize it. Initialization is done twice in many
720 * cases: to preempt sleeping callin opens if we are
721 * callout, and to complete a callin open after DCD rises.
722 */
723 tp->t_oproc = comstart;
676 s = spltty();
677 /*
678 * We jump to this label after all non-interrupted sleeps to pick
679 * up any changes of the device state.
680 */
681open_top:
682 while (com->state & CS_DTR_OFF) {
683 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "cydtr", 0);
684 if (error != 0)
685 goto out;
686 }
687 if (tp->t_state & TS_ISOPEN) {
688 /*
689 * The device is open, so everything has been initialized.
690 * Handle conflicts.
691 */
692 if (mynor & CALLOUT_MASK) {
693 if (!com->active_out) {
694 error = EBUSY;
695 goto out;
696 }
697 } else {
698 if (com->active_out) {
699 if (flag & O_NONBLOCK) {
700 error = EBUSY;
701 goto out;
702 }
703 error = tsleep(&com->active_out,
704 TTIPRI | PCATCH, "cybi", 0);
705 if (error != 0)
706 goto out;
707 goto open_top;
708 }
709 }
710 if (tp->t_state & TS_XCLUDE &&
711 suser(p)) {
712 error = EBUSY;
713 goto out;
714 }
715 } else {
716 /*
717 * The device isn't open, so there are no conflicts.
718 * Initialize it. Initialization is done twice in many
719 * cases: to preempt sleeping callin opens if we are
720 * callout, and to complete a callin open after DCD rises.
721 */
722 tp->t_oproc = comstart;
723 tp->t_stop = comstop;
724 tp->t_param = comparam;
725 tp->t_dev = dev;
726 tp->t_termios = mynor & CALLOUT_MASK
727 ? com->it_out : com->it_in;
728
729 /* Encode per-board unit in LIVR for access in intr routines. */
730 cd_setreg(com, CD1400_LIVR,
731 (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
732
733 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
734#if 0
735 com->poll = com->no_irq;
736 com->poll_output = com->loses_outints;
737#endif
738 ++com->wopeners;
739 error = comparam(tp, &tp->t_termios);
740 --com->wopeners;
741 if (error != 0)
742 goto out;
743#if 0
744 if (com->hasfifo) {
745 /*
746 * (Re)enable and flush fifos.
747 *
748 * Certain SMC chips cause problems if the fifos
749 * are enabled while input is ready. Turn off the
750 * fifo if necessary to clear the input. We test
751 * the input ready bit after enabling the fifos
752 * since we've already enabled them in comparam()
753 * and to handle races between enabling and fresh
754 * input.
755 */
756 while (TRUE) {
757 outb(iobase + com_fifo,
758 FIFO_RCV_RST | FIFO_XMT_RST
759 | com->fifo_image);
760 DELAY(100);
761 if (!(inb(com->line_status_port) & LSR_RXRDY))
762 break;
763 outb(iobase + com_fifo, 0);
764 DELAY(100);
765 (void) inb(com->data_port);
766 }
767 }
768
769 disable_intr();
770 (void) inb(com->line_status_port);
771 (void) inb(com->data_port);
772 com->prev_modem_status = com->last_modem_status
773 = inb(com->modem_status_port);
774 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
775 | IER_EMSC);
776 enable_intr();
777#else /* !0 */
778 /*
779 * Flush fifos. This requires a full channel reset which
780 * also disables the transmitter and receiver. Recover
781 * from this.
782 */
783 cd1400_channel_cmd(com,
784 CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET);
785 cd1400_channel_cmd(com, com->channel_control);
786
787 disable_intr();
788 com->prev_modem_status = com->last_modem_status
789 = cd_getreg(com, CD1400_MSVR2);
790 cd_setreg(com, CD1400_SRER,
791 com->intr_enable
792 = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
793 enable_intr();
794#endif /* 0 */
795 /*
796 * Handle initial DCD. Callout devices get a fake initial
797 * DCD (trapdoor DCD). If we are callout, then any sleeping
798 * callin opens get woken up and resume sleeping on "cybi"
799 * instead of "cydcd".
800 */
801 /*
802 * XXX `mynor & CALLOUT_MASK' should be
803 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
804 * TRAPDOOR_CARRIER is the default initial state for callout
805 * devices and SOFT_CARRIER is like CLOCAL except it hides
806 * the true carrier.
807 */
808 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
809 (*linesw[tp->t_line].l_modem)(tp, 1);
810 }
811 /*
812 * Wait for DCD if necessary.
813 */
814 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
815 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
816 ++com->wopeners;
817 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0);
818 --com->wopeners;
819 if (error != 0)
820 goto out;
821 goto open_top;
822 }
823 error = (*linesw[tp->t_line].l_open)(dev, tp);
824 disc_optim(tp, &tp->t_termios, com);
825 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
826 com->active_out = TRUE;
827 siosettimeout();
828out:
829 splx(s);
830 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
831 comhardclose(com);
832 return (error);
833}
834
835static int
836sioclose(dev, flag, mode, p)
837 dev_t dev;
838 int flag;
839 int mode;
840 struct proc *p;
841{
842 struct com_s *com;
843 int mynor;
844 int s;
845 struct tty *tp;
846
847 mynor = minor(dev);
848 if (mynor & CONTROL_MASK)
849 return (0);
850 com = com_addr(MINOR_TO_UNIT(mynor));
851 tp = com->tp;
852 s = spltty();
853 cd_etc(com, CD1400_ETC_STOPBREAK);
854 (*linesw[tp->t_line].l_close)(tp, flag);
855 disc_optim(tp, &tp->t_termios, com);
724 tp->t_param = comparam;
725 tp->t_dev = dev;
726 tp->t_termios = mynor & CALLOUT_MASK
727 ? com->it_out : com->it_in;
728
729 /* Encode per-board unit in LIVR for access in intr routines. */
730 cd_setreg(com, CD1400_LIVR,
731 (unit & CD1400_xIVR_CHAN) << CD1400_xIVR_CHAN_SHIFT);
732
733 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
734#if 0
735 com->poll = com->no_irq;
736 com->poll_output = com->loses_outints;
737#endif
738 ++com->wopeners;
739 error = comparam(tp, &tp->t_termios);
740 --com->wopeners;
741 if (error != 0)
742 goto out;
743#if 0
744 if (com->hasfifo) {
745 /*
746 * (Re)enable and flush fifos.
747 *
748 * Certain SMC chips cause problems if the fifos
749 * are enabled while input is ready. Turn off the
750 * fifo if necessary to clear the input. We test
751 * the input ready bit after enabling the fifos
752 * since we've already enabled them in comparam()
753 * and to handle races between enabling and fresh
754 * input.
755 */
756 while (TRUE) {
757 outb(iobase + com_fifo,
758 FIFO_RCV_RST | FIFO_XMT_RST
759 | com->fifo_image);
760 DELAY(100);
761 if (!(inb(com->line_status_port) & LSR_RXRDY))
762 break;
763 outb(iobase + com_fifo, 0);
764 DELAY(100);
765 (void) inb(com->data_port);
766 }
767 }
768
769 disable_intr();
770 (void) inb(com->line_status_port);
771 (void) inb(com->data_port);
772 com->prev_modem_status = com->last_modem_status
773 = inb(com->modem_status_port);
774 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
775 | IER_EMSC);
776 enable_intr();
777#else /* !0 */
778 /*
779 * Flush fifos. This requires a full channel reset which
780 * also disables the transmitter and receiver. Recover
781 * from this.
782 */
783 cd1400_channel_cmd(com,
784 CD1400_CCR_CMDRESET | CD1400_CCR_CHANRESET);
785 cd1400_channel_cmd(com, com->channel_control);
786
787 disable_intr();
788 com->prev_modem_status = com->last_modem_status
789 = cd_getreg(com, CD1400_MSVR2);
790 cd_setreg(com, CD1400_SRER,
791 com->intr_enable
792 = CD1400_SRER_MDMCH | CD1400_SRER_RXDATA);
793 enable_intr();
794#endif /* 0 */
795 /*
796 * Handle initial DCD. Callout devices get a fake initial
797 * DCD (trapdoor DCD). If we are callout, then any sleeping
798 * callin opens get woken up and resume sleeping on "cybi"
799 * instead of "cydcd".
800 */
801 /*
802 * XXX `mynor & CALLOUT_MASK' should be
803 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
804 * TRAPDOOR_CARRIER is the default initial state for callout
805 * devices and SOFT_CARRIER is like CLOCAL except it hides
806 * the true carrier.
807 */
808 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
809 (*linesw[tp->t_line].l_modem)(tp, 1);
810 }
811 /*
812 * Wait for DCD if necessary.
813 */
814 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
815 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
816 ++com->wopeners;
817 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "cydcd", 0);
818 --com->wopeners;
819 if (error != 0)
820 goto out;
821 goto open_top;
822 }
823 error = (*linesw[tp->t_line].l_open)(dev, tp);
824 disc_optim(tp, &tp->t_termios, com);
825 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
826 com->active_out = TRUE;
827 siosettimeout();
828out:
829 splx(s);
830 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
831 comhardclose(com);
832 return (error);
833}
834
835static int
836sioclose(dev, flag, mode, p)
837 dev_t dev;
838 int flag;
839 int mode;
840 struct proc *p;
841{
842 struct com_s *com;
843 int mynor;
844 int s;
845 struct tty *tp;
846
847 mynor = minor(dev);
848 if (mynor & CONTROL_MASK)
849 return (0);
850 com = com_addr(MINOR_TO_UNIT(mynor));
851 tp = com->tp;
852 s = spltty();
853 cd_etc(com, CD1400_ETC_STOPBREAK);
854 (*linesw[tp->t_line].l_close)(tp, flag);
855 disc_optim(tp, &tp->t_termios, com);
856 siostop(tp, FREAD | FWRITE);
856 comstop(tp, FREAD | FWRITE);
857 comhardclose(com);
858 ttyclose(tp);
859 siosettimeout();
860 splx(s);
861#ifdef broken /* session holds a ref to the tty; can't deallocate */
862 ttyfree(tp);
863 com->tp = sio_tty[unit] = NULL;
864#endif
865 return (0);
866}
867
868static void
869comhardclose(com)
870 struct com_s *com;
871{
872 cy_addr iobase;
873 int s;
874 struct tty *tp;
875 int unit;
876
877 unit = com->unit;
878 iobase = com->iobase;
879 s = spltty();
880#if 0
881 com->poll = FALSE;
882 com->poll_output = FALSE;
883#endif
884 com->do_timestamp = 0;
885#if 0
886 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
887#else
888 /* XXX */
889 disable_intr();
890 com->etc = ETC_NONE;
891 cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC);
892 enable_intr();
893 cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
894#endif
895
896 {
897#if 0
898 outb(iobase + com_ier, 0);
899#else
900 disable_intr();
901 cd_setreg(com, CD1400_SRER, com->intr_enable = 0);
902 enable_intr();
903#endif
904 tp = com->tp;
905 if ((tp->t_cflag & HUPCL)
906 /*
907 * XXX we will miss any carrier drop between here and the
908 * next open. Perhaps we should watch DCD even when the
909 * port is closed; it is not sufficient to check it at
910 * the next open because it might go up and down while
911 * we're not watching.
912 */
913 || (!com->active_out
914 && !(com->prev_modem_status & MSR_DCD)
915 && !(com->it_in.c_cflag & CLOCAL))
916 || !(tp->t_state & TS_ISOPEN)) {
917 (void)commctl(com, TIOCM_DTR, DMBIC);
918
919 /* Disable receiver (leave transmitter enabled). */
920 com->channel_control = CD1400_CCR_CMDCHANCTL
921 | CD1400_CCR_XMTEN
922 | CD1400_CCR_RCVDIS;
923 cd1400_channel_cmd(com, com->channel_control);
924
925 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
926 timeout(siodtrwakeup, com, com->dtr_wait);
927 com->state |= CS_DTR_OFF;
928 }
929 }
930 }
931#if 0
932 if (com->hasfifo) {
933 /*
934 * Disable fifos so that they are off after controlled
935 * reboots. Some BIOSes fail to detect 16550s when the
936 * fifos are enabled.
937 */
938 outb(iobase + com_fifo, 0);
939 }
940#endif
941 com->active_out = FALSE;
942 wakeup(&com->active_out);
943 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
944 splx(s);
945}
946
947static int
948sioread(dev, uio, flag)
949 dev_t dev;
950 struct uio *uio;
951 int flag;
952{
953 int mynor;
954 struct tty *tp;
955
956 mynor = minor(dev);
957 if (mynor & CONTROL_MASK)
958 return (ENODEV);
959 tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
960 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
961}
962
963static int
964siowrite(dev, uio, flag)
965 dev_t dev;
966 struct uio *uio;
967 int flag;
968{
969 int mynor;
970 struct tty *tp;
971 int unit;
972
973 mynor = minor(dev);
974 if (mynor & CONTROL_MASK)
975 return (ENODEV);
976
977 unit = MINOR_TO_UNIT(mynor);
978 tp = com_addr(unit)->tp;
979 /*
980 * (XXX) We disallow virtual consoles if the physical console is
981 * a serial port. This is in case there is a display attached that
982 * is not the console. In that situation we don't need/want the X
983 * server taking over the console.
984 */
985 if (constty != NULL && unit == comconsole)
986 constty = NULL;
987#ifdef Smarts
988 /* XXX duplicate ttwrite(), but without so much output processing on
989 * CR & LF chars. Hardly worth the effort, given that high-throughput
990 * sessions are raw anyhow.
991 */
992#else
993 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
994#endif
995}
996
997static void
998siodtrwakeup(chan)
999 void *chan;
1000{
1001 struct com_s *com;
1002
1003 com = (struct com_s *)chan;
1004 com->state &= ~CS_DTR_OFF;
1005 wakeup(&com->dtr_wait);
1006}
1007
1008static void
1009sioinput(com)
1010 struct com_s *com;
1011{
1012 u_char *buf;
1013 int incc;
1014 u_char line_status;
1015 int recv_data;
1016 struct tty *tp;
1017
1018 buf = com->ibuf;
1019 tp = com->tp;
1020 if (!(tp->t_state & TS_ISOPEN)) {
1021 com_events -= (com->iptr - com->ibuf);
1022 com->iptr = com->ibuf;
1023 return;
1024 }
1025 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1026 /*
1027 * Avoid the grotesquely inefficient lineswitch routine
1028 * (ttyinput) in "raw" mode. It usually takes about 450
1029 * instructions (that's without canonical processing or echo!).
1030 * slinput is reasonably fast (usually 40 instructions plus
1031 * call overhead).
1032 */
1033 do {
1034 enable_intr();
1035 incc = com->iptr - buf;
1036 if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
1037 && (com->state & CS_RTS_IFLOW
1038 || tp->t_iflag & IXOFF)
1039 && !(tp->t_state & TS_TBLOCK))
1040 ttyblock(tp);
1041 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1042 += b_to_q((char *)buf, incc, &tp->t_rawq);
1043 buf += incc;
1044 tk_nin += incc;
1045 tk_rawcc += incc;
1046 tp->t_rawcc += incc;
1047 ttwakeup(tp);
1048 if (tp->t_state & TS_TTSTOP
1049 && (tp->t_iflag & IXANY
1050 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1051 tp->t_state &= ~TS_TTSTOP;
1052 tp->t_lflag &= ~FLUSHO;
1053 comstart(tp);
1054 }
1055 disable_intr();
1056 } while (buf < com->iptr);
1057 } else {
1058 do {
1059 enable_intr();
1060 line_status = buf[com->ierroff];
1061 recv_data = *buf++;
1062 if (line_status
1063 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1064 if (line_status & LSR_BI)
1065 recv_data |= TTY_BI;
1066 if (line_status & LSR_FE)
1067 recv_data |= TTY_FE;
1068 if (line_status & LSR_OE)
1069 recv_data |= TTY_OE;
1070 if (line_status & LSR_PE)
1071 recv_data |= TTY_PE;
1072 }
1073 (*linesw[tp->t_line].l_rint)(recv_data, tp);
1074 disable_intr();
1075 } while (buf < com->iptr);
1076 }
1077 com_events -= (com->iptr - com->ibuf);
1078 com->iptr = com->ibuf;
1079
1080 /*
1081 * There is now room for another low-level buffer full of input,
1082 * so enable RTS if it is now disabled and there is room in the
1083 * high-level buffer.
1084 */
1085 if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & com->mcr_rts) &&
1086 !(tp->t_state & TS_TBLOCK))
1087#if 0
1088 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1089#else
1090 cd_setreg(com, com->mcr_rts_reg,
1091 com->mcr_image |= com->mcr_rts);
1092#endif
1093}
1094
1095void
1096siointr(unit)
1097 int unit;
1098{
1099 int baseu;
1100 int cy_align;
1101 cy_addr cy_iobase;
1102 int cyu;
1103 cy_addr iobase;
1104 u_char status;
1105
1106 COM_LOCK(); /* XXX could this be placed down lower in the loop? */
1107
1108 baseu = unit * CY_MAX_PORTS;
1109 cy_align = com_addr(baseu)->cy_align;
1110 cy_iobase = com_addr(baseu)->cy_iobase;
1111
1112 /* check each CD1400 in turn */
1113 for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
1114 iobase = (cy_addr) (cy_iobase
1115 + (cy_chip_offset[cyu] << cy_align));
1116 /* poll to see if it has any work */
1117 status = cd_inb(iobase, CD1400_SVRR, cy_align);
1118 if (status == 0)
1119 continue;
1120#ifdef CyDebug
1121 ++cy_svrr_probes;
1122#endif
1123 /* service requests as appropriate, giving priority to RX */
1124 if (status & CD1400_SVRR_RXRDY) {
1125 struct com_s *com;
1126 u_int count;
1127 u_char *ioptr;
1128 u_char line_status;
1129 u_char recv_data;
1130 u_char serv_type;
1131#ifdef PollMode
1132 u_char save_rir;
1133#endif
1134
1135#ifdef PollMode
1136 save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
1137
1138 /* enter rx service */
1139 cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
1140 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1141 = save_rir & CD1400_CAR_CHAN;
1142
1143 serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
1144 com = com_addr(baseu
1145 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1146 & CD1400_xIVR_CHAN));
1147#else
1148 /* ack receive service */
1149 serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align);
1150
1151 com = com_addr(baseu +
1152 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1153 & CD1400_xIVR_CHAN));
1154#endif
1155
1156 if (serv_type & CD1400_RIVR_EXCEPTION) {
1157 ++com->recv_exception;
1158 line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
1159 /* break/unnattached error bits or real input? */
1160 recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
1161#ifndef SOFT_HOTCHAR
1162 if (line_status & CD1400_RDSR_SPECIAL
1163 && com->hotchar != 0)
1164 setsofttty();
1165#endif
1166#if 1 /* XXX "intelligent" PFO error handling would break O error handling */
1167 if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {
1168 /*
1169 Don't store PE if IGNPAR and BI if IGNBRK,
1170 this hack allows "raw" tty optimization
1171 works even if IGN* is set.
1172 */
1173 if ( com->tp == NULL
1174 || !(com->tp->t_state & TS_ISOPEN)
1175 || ((line_status & (LSR_PE|LSR_FE))
1176 && (com->tp->t_iflag & IGNPAR))
1177 || ((line_status & LSR_BI)
1178 && (com->tp->t_iflag & IGNBRK)))
1179 goto cont;
1180 if ( (line_status & (LSR_PE|LSR_FE))
1181 && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)
1182 && ((line_status & LSR_FE)
1183 || ((line_status & LSR_PE)
1184 && (com->tp->t_iflag & INPCK))))
1185 recv_data = 0;
1186 }
1187#endif /* 1 */
1188 ++com->bytes_in;
1189#ifdef SOFT_HOTCHAR
1190 if (com->hotchar != 0 && recv_data == com->hotchar)
1191 setsofttty();
1192#endif
1193 ioptr = com->iptr;
1194 if (ioptr >= com->ibufend)
1195 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1196 else {
1197 if (com->do_timestamp)
1198 microtime(&com->timestamp);
1199 ++com_events;
1200 ioptr[0] = recv_data;
1201 ioptr[com->ierroff] = line_status;
1202 com->iptr = ++ioptr;
1203 if (ioptr == com->ihighwater
1204 && com->state & CS_RTS_IFLOW)
1205#if 0
1206 outb(com->modem_ctl_port,
1207 com->mcr_image &= ~MCR_RTS);
1208#else
1209 cd_outb(iobase, com->mcr_rts_reg,
1210 cy_align,
1211 com->mcr_image &=
1212 ~com->mcr_rts);
1213#endif
1214 if (line_status & LSR_OE)
1215 CE_RECORD(com, CE_OVERRUN);
1216 }
1217 goto cont;
1218 } else {
1219 int ifree;
1220
1221 count = cd_inb(iobase, CD1400_RDCR, cy_align);
1222 if (!count)
1223 goto cont;
1224 com->bytes_in += count;
1225 ioptr = com->iptr;
1226 ifree = com->ibufend - ioptr;
1227 if (count > ifree) {
1228 count -= ifree;
1229 com_events += ifree;
1230 if (ifree != 0) {
1231 if (com->do_timestamp)
1232 microtime(&com->timestamp);
1233 do {
1234 recv_data = cd_inb(iobase,
1235 CD1400_RDSR,
1236 cy_align);
1237#ifdef SOFT_HOTCHAR
1238 if (com->hotchar != 0
1239 && recv_data
1240 == com->hotchar)
1241 setsofttty();
1242#endif
1243 ioptr[0] = recv_data;
1244 ioptr[com->ierroff] = 0;
1245 ++ioptr;
1246 } while (--ifree != 0);
1247 }
1248 com->delta_error_counts
1249 [CE_INTERRUPT_BUF_OVERFLOW] += count;
1250 do {
1251 recv_data = cd_inb(iobase, CD1400_RDSR,
1252 cy_align);
1253#ifdef SOFT_HOTCHAR
1254 if (com->hotchar != 0
1255 && recv_data == com->hotchar)
1256 setsofttty();
1257#endif
1258 } while (--count != 0);
1259 } else {
1260 if (com->do_timestamp)
1261 microtime(&com->timestamp);
1262 if (ioptr <= com->ihighwater
1263 && ioptr + count > com->ihighwater
1264 && com->state & CS_RTS_IFLOW)
1265#if 0
1266 outb(com->modem_ctl_port,
1267 com->mcr_image &= ~MCR_RTS);
1268#else
1269 cd_outb(iobase, com->mcr_rts_reg,
1270 cy_align,
1271 com->mcr_image
1272 &= ~com->mcr_rts);
1273#endif
1274 com_events += count;
1275 do {
1276 recv_data = cd_inb(iobase, CD1400_RDSR,
1277 cy_align);
1278#ifdef SOFT_HOTCHAR
1279 if (com->hotchar != 0
1280 && recv_data == com->hotchar)
1281 setsofttty();
1282#endif
1283 ioptr[0] = recv_data;
1284 ioptr[com->ierroff] = 0;
1285 ++ioptr;
1286 } while (--count != 0);
1287 }
1288 com->iptr = ioptr;
1289 }
1290cont:
1291
1292 /* terminate service context */
1293#ifdef PollMode
1294 cd_outb(iobase, CD1400_RIR, cy_align,
1295 save_rir
1296 & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
1297#else
1298 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1299#endif
1300 }
1301 if (status & CD1400_SVRR_MDMCH) {
1302 struct com_s *com;
1303 u_char modem_status;
1304#ifdef PollMode
1305 u_char save_mir;
1306#else
1307 u_char vector;
1308#endif
1309
1310#ifdef PollMode
1311 save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
1312
1313 /* enter modem service */
1314 cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
1315 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1316 = save_mir & CD1400_CAR_CHAN;
1317
1318 com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
1319 + (save_mir & CD1400_MIR_CHAN));
1320#else
1321 /* ack modem service */
1322 vector = cy_inb(iobase, CY8_SVCACKM, cy_align);
1323
1324 com = com_addr(baseu
1325 + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1326 & CD1400_xIVR_CHAN));
1327#endif
1328 ++com->mdm;
1329 modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
1330 if (modem_status != com->last_modem_status) {
1331 if (com->do_dcd_timestamp
1332 && !(com->last_modem_status & MSR_DCD)
1333 && modem_status & MSR_DCD)
1334 microtime(&com->dcd_timestamp);
1335
1336 /*
1337 * Schedule high level to handle DCD changes. Note
1338 * that we don't use the delta bits anywhere. Some
1339 * UARTs mess them up, and it's easy to remember the
1340 * previous bits and calculate the delta.
1341 */
1342 com->last_modem_status = modem_status;
1343 if (!(com->state & CS_CHECKMSR)) {
1344 com_events += LOTS_OF_EVENTS;
1345 com->state |= CS_CHECKMSR;
1346 setsofttty();
1347 }
1348
1349#ifdef SOFT_CTS_OFLOW
1350 /* handle CTS change immediately for crisp flow ctl */
1351 if (com->state & CS_CTS_OFLOW) {
1352 if (modem_status & MSR_CTS) {
1353 com->state |= CS_ODEVREADY;
1354 if (com->state >= (CS_BUSY | CS_TTGO
1355 | CS_ODEVREADY)
1356 && !(com->intr_enable
1357 & CD1400_SRER_TXRDY))
1358 cd_outb(iobase, CD1400_SRER,
1359 cy_align,
1360 com->intr_enable
1361 = com->intr_enable
1362 & ~CD1400_SRER_TXMPTY
1363 | CD1400_SRER_TXRDY);
1364 } else {
1365 com->state &= ~CS_ODEVREADY;
1366 if (com->intr_enable
1367 & CD1400_SRER_TXRDY)
1368 cd_outb(iobase, CD1400_SRER,
1369 cy_align,
1370 com->intr_enable
1371 = com->intr_enable
1372 & ~CD1400_SRER_TXRDY
1373 | CD1400_SRER_TXMPTY);
1374 }
1375 }
1376#endif
1377 }
1378
1379 /* terminate service context */
1380#ifdef PollMode
1381 cd_outb(iobase, CD1400_MIR, cy_align,
1382 save_mir
1383 & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
1384#else
1385 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1386#endif
1387 }
1388 if (status & CD1400_SVRR_TXRDY) {
1389 struct com_s *com;
1390#ifdef PollMode
1391 u_char save_tir;
1392#else
1393 u_char vector;
1394#endif
1395
1396#ifdef PollMode
1397 save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
1398
1399 /* enter tx service */
1400 cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
1401 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1402 = save_tir & CD1400_CAR_CHAN;
1403
1404 com = com_addr(baseu
1405 + cyu * CD1400_NO_OF_CHANNELS
1406 + (save_tir & CD1400_TIR_CHAN));
1407#else
1408 /* ack transmit service */
1409 vector = cy_inb(iobase, CY8_SVCACKT, cy_align);
1410
1411 com = com_addr(baseu
1412 + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1413 & CD1400_xIVR_CHAN));
1414#endif
1415
1416 if (com->etc != ETC_NONE) {
1417 if (com->intr_enable & CD1400_SRER_TXRDY) {
1418 /*
1419 * Here due to sloppy SRER_TXRDY
1420 * enabling. Ignore. Come back when
1421 * tx is empty.
1422 */
1423 cd_outb(iobase, CD1400_SRER, cy_align,
1424 com->intr_enable
1425 = (com->intr_enable
1426 & ~CD1400_SRER_TXRDY)
1427 | CD1400_SRER_TXMPTY);
1428 goto terminate_tx_service;
1429 }
1430 switch (com->etc) {
1431 case CD1400_ETC_SENDBREAK:
1432 case CD1400_ETC_STOPBREAK:
1433 /*
1434 * Start the command. Come back on
1435 * next tx empty interrupt, hopefully
1436 * after command has been executed.
1437 */
1438 cd_outb(iobase, CD1400_COR2, cy_align,
1439 com->cor[1] |= CD1400_COR2_ETC);
1440 cd_outb(iobase, CD1400_TDR, cy_align,
1441 CD1400_ETC_CMD);
1442 cd_outb(iobase, CD1400_TDR, cy_align,
1443 com->etc);
1444 if (com->etc == CD1400_ETC_SENDBREAK)
1445 com->etc = ETC_BREAK_STARTING;
1446 else
1447 com->etc = ETC_BREAK_ENDING;
1448 goto terminate_tx_service;
1449 case ETC_BREAK_STARTING:
1450 /*
1451 * BREAK is now on. Continue with
1452 * SRER_TXMPTY processing, hopefully
1453 * don't come back.
1454 */
1455 com->etc = ETC_BREAK_STARTED;
1456 break;
1457 case ETC_BREAK_STARTED:
1458 /*
1459 * Came back due to sloppy SRER_TXMPTY
1460 * enabling. Hope again.
1461 */
1462 break;
1463 case ETC_BREAK_ENDING:
1464 /*
1465 * BREAK is now off. Continue with
1466 * SRER_TXMPTY processing and don't
1467 * come back. The SWI handler will
1468 * restart tx interrupts if necessary.
1469 */
1470 cd_outb(iobase, CD1400_COR2, cy_align,
1471 com->cor[1]
1472 &= ~CD1400_COR2_ETC);
1473 com->etc = ETC_BREAK_ENDED;
1474 if (!(com->state & CS_ODONE)) {
1475 com_events += LOTS_OF_EVENTS;
1476 com->state |= CS_ODONE;
1477 setsofttty();
1478 }
1479 break;
1480 case ETC_BREAK_ENDED:
1481 /*
1482 * Shouldn't get here. Hope again.
1483 */
1484 break;
1485 }
1486 }
1487 if (com->intr_enable & CD1400_SRER_TXMPTY) {
1488 if (!(com->extra_state & CSE_ODONE)) {
1489 com_events += LOTS_OF_EVENTS;
1490 com->extra_state |= CSE_ODONE;
1491 setsofttty();
1492 }
1493 cd_outb(iobase, CD1400_SRER, cy_align,
1494 com->intr_enable
1495 &= ~CD1400_SRER_TXMPTY);
1496 goto terminate_tx_service;
1497 }
1498 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1499 u_char *ioptr;
1500 u_int ocount;
1501
1502 ioptr = com->obufq.l_head;
1503 ocount = com->obufq.l_tail - ioptr;
1504 if (ocount > CD1400_TX_FIFO_SIZE)
1505 ocount = CD1400_TX_FIFO_SIZE;
1506 com->bytes_out += ocount;
1507 do
1508 cd_outb(iobase, CD1400_TDR, cy_align,
1509 *ioptr++);
1510 while (--ocount != 0);
1511 com->obufq.l_head = ioptr;
1512 if (ioptr >= com->obufq.l_tail) {
1513 struct lbq *qp;
1514
1515 qp = com->obufq.l_next;
1516 qp->l_queued = FALSE;
1517 qp = qp->l_next;
1518 if (qp != NULL) {
1519 com->obufq.l_head = qp->l_head;
1520 com->obufq.l_tail = qp->l_tail;
1521 com->obufq.l_next = qp;
1522 } else {
1523 /* output just completed */
1524 com->state &= ~CS_BUSY;
1525
1526 /*
1527 * The setting of CSE_ODONE may be
1528 * stale here. We currently only
1529 * use it when CS_BUSY is set, and
1530 * fixing it when we clear CS_BUSY
1531 * is easiest.
1532 */
1533 if (com->extra_state & CSE_ODONE) {
1534 com_events -= LOTS_OF_EVENTS;
1535 com->extra_state &= ~CSE_ODONE;
1536 }
1537
1538 cd_outb(iobase, CD1400_SRER, cy_align,
1539 com->intr_enable
1540 = (com->intr_enable
1541 & ~CD1400_SRER_TXRDY)
1542 | CD1400_SRER_TXMPTY);
1543 }
1544 if (!(com->state & CS_ODONE)) {
1545 com_events += LOTS_OF_EVENTS;
1546 com->state |= CS_ODONE;
1547
1548 /* handle at high level ASAP */
1549 setsofttty();
1550 }
1551 }
1552 }
1553
1554 /* terminate service context */
1555terminate_tx_service:
1556#ifdef PollMode
1557 cd_outb(iobase, CD1400_TIR, cy_align,
1558 save_tir
1559 & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
1560#else
1561 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1562#endif
1563 }
1564 }
1565
1566 /* ensure an edge for the next interrupt */
1567 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
1568
1569 schedsofttty();
1570
1571 COM_UNLOCK();
1572}
1573
1574#if 0
1575static void
1576siointr1(com)
1577 struct com_s *com;
1578{
1579}
1580#endif
1581
1582static int
1583sioioctl(dev, cmd, data, flag, p)
1584 dev_t dev;
1585 u_long cmd;
1586 caddr_t data;
1587 int flag;
1588 struct proc *p;
1589{
1590 struct com_s *com;
1591 int error;
1592 int mynor;
1593 int s;
1594 struct tty *tp;
1595#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1596 int oldcmd;
1597 struct termios term;
1598#endif
1599
1600 mynor = minor(dev);
1601 com = com_addr(MINOR_TO_UNIT(mynor));
1602 if (mynor & CONTROL_MASK) {
1603 struct termios *ct;
1604
1605 switch (mynor & CONTROL_MASK) {
1606 case CONTROL_INIT_STATE:
1607 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1608 break;
1609 case CONTROL_LOCK_STATE:
1610 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1611 break;
1612 default:
1613 return (ENODEV); /* /dev/nodev */
1614 }
1615 switch (cmd) {
1616 case TIOCSETA:
1617 error = suser(p);
1618 if (error != 0)
1619 return (error);
1620 *ct = *(struct termios *)data;
1621 return (0);
1622 case TIOCGETA:
1623 *(struct termios *)data = *ct;
1624 return (0);
1625 case TIOCGETD:
1626 *(int *)data = TTYDISC;
1627 return (0);
1628 case TIOCGWINSZ:
1629 bzero(data, sizeof(struct winsize));
1630 return (0);
1631 default:
1632 return (ENOTTY);
1633 }
1634 }
1635 tp = com->tp;
1636#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1637 term = tp->t_termios;
1638 oldcmd = cmd;
1639 error = ttsetcompat(tp, &cmd, data, &term);
1640 if (error != 0)
1641 return (error);
1642 if (cmd != oldcmd)
1643 data = (caddr_t)&term;
1644#endif
1645 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1646 int cc;
1647 struct termios *dt = (struct termios *)data;
1648 struct termios *lt = mynor & CALLOUT_MASK
1649 ? &com->lt_out : &com->lt_in;
1650
1651 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1652 | (dt->c_iflag & ~lt->c_iflag);
1653 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1654 | (dt->c_oflag & ~lt->c_oflag);
1655 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1656 | (dt->c_cflag & ~lt->c_cflag);
1657 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1658 | (dt->c_lflag & ~lt->c_lflag);
1659 for (cc = 0; cc < NCCS; ++cc)
1660 if (lt->c_cc[cc] != 0)
1661 dt->c_cc[cc] = tp->t_cc[cc];
1662 if (lt->c_ispeed != 0)
1663 dt->c_ispeed = tp->t_ispeed;
1664 if (lt->c_ospeed != 0)
1665 dt->c_ospeed = tp->t_ospeed;
1666 }
1667 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1668 if (error != ENOIOCTL)
1669 return (error);
1670 s = spltty();
1671 error = ttioctl(tp, cmd, data, flag);
1672 disc_optim(tp, &tp->t_termios, com);
1673 if (error != ENOIOCTL) {
1674 splx(s);
1675 return (error);
1676 }
1677 switch (cmd) {
1678 case TIOCSBRK:
1679#if 0
1680 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1681#else
1682 cd_etc(com, CD1400_ETC_SENDBREAK);
1683#endif
1684 break;
1685 case TIOCCBRK:
1686#if 0
1687 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1688#else
1689 cd_etc(com, CD1400_ETC_STOPBREAK);
1690#endif
1691 break;
1692 case TIOCSDTR:
1693 (void)commctl(com, TIOCM_DTR, DMBIS);
1694 break;
1695 case TIOCCDTR:
1696 (void)commctl(com, TIOCM_DTR, DMBIC);
1697 break;
1698 /*
1699 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The
1700 * changes get undone on the next call to comparam().
1701 */
1702 case TIOCMSET:
1703 (void)commctl(com, *(int *)data, DMSET);
1704 break;
1705 case TIOCMBIS:
1706 (void)commctl(com, *(int *)data, DMBIS);
1707 break;
1708 case TIOCMBIC:
1709 (void)commctl(com, *(int *)data, DMBIC);
1710 break;
1711 case TIOCMGET:
1712 *(int *)data = commctl(com, 0, DMGET);
1713 break;
1714 case TIOCMSDTRWAIT:
1715 /* must be root since the wait applies to following logins */
1716 error = suser(p);
1717 if (error != 0) {
1718 splx(s);
1719 return (error);
1720 }
1721 com->dtr_wait = *(int *)data * hz / 100;
1722 break;
1723 case TIOCMGDTRWAIT:
1724 *(int *)data = com->dtr_wait * 100 / hz;
1725 break;
1726 case TIOCTIMESTAMP:
1727 com->do_timestamp = TRUE;
1728 *(struct timeval *)data = com->timestamp;
1729 break;
1730 case TIOCDCDTIMESTAMP:
1731 com->do_dcd_timestamp = TRUE;
1732 *(struct timeval *)data = com->dcd_timestamp;
1733 break;
1734 default:
1735 splx(s);
1736 return (ENOTTY);
1737 }
1738 splx(s);
1739 return (0);
1740}
1741
1742static void
1743siopoll()
1744{
1745 int unit;
1746
1747#ifdef CyDebug
1748 ++cy_timeouts;
1749#endif
1750 if (com_events == 0)
1751 return;
1752repeat:
1753 for (unit = 0; unit < NSIO; ++unit) {
1754 struct com_s *com;
1755 int incc;
1756 struct tty *tp;
1757
1758 com = com_addr(unit);
1759 if (com == NULL)
1760 continue;
1761 tp = com->tp;
1762 if (tp == NULL) {
1763 /*
1764 * XXX forget any events related to closed devices
1765 * (actually never opened devices) so that we don't
1766 * loop.
1767 */
1768 disable_intr();
1769 incc = com->iptr - com->ibuf;
1770 com->iptr = com->ibuf;
1771 if (com->state & CS_CHECKMSR) {
1772 incc += LOTS_OF_EVENTS;
1773 com->state &= ~CS_CHECKMSR;
1774 }
1775 com_events -= incc;
1776 enable_intr();
1777 if (incc != 0)
1778 log(LOG_DEBUG,
1779 "sio%d: %d events for device with no tp\n",
1780 unit, incc);
1781 continue;
1782 }
1783 if (com->iptr != com->ibuf) {
1784 disable_intr();
1785 sioinput(com);
1786 enable_intr();
1787 }
1788 if (com->state & CS_CHECKMSR) {
1789 u_char delta_modem_status;
1790
1791 disable_intr();
1792 delta_modem_status = com->last_modem_status
1793 ^ com->prev_modem_status;
1794 com->prev_modem_status = com->last_modem_status;
1795 com_events -= LOTS_OF_EVENTS;
1796 com->state &= ~CS_CHECKMSR;
1797 enable_intr();
1798 if (delta_modem_status & MSR_DCD)
1799 (*linesw[tp->t_line].l_modem)
1800 (tp, com->prev_modem_status & MSR_DCD);
1801 }
1802 if (com->extra_state & CSE_ODONE) {
1803 disable_intr();
1804 com_events -= LOTS_OF_EVENTS;
1805 com->extra_state &= ~CSE_ODONE;
1806 enable_intr();
1807 if (!(com->state & CS_BUSY)) {
1808 tp->t_state &= ~TS_BUSY;
1809 ttwwakeup(com->tp);
1810 }
1811 if (com->etc != ETC_NONE) {
1812 if (com->etc == ETC_BREAK_ENDED)
1813 com->etc = ETC_NONE;
1814 wakeup(&com->etc);
1815 }
1816 }
1817 if (com->state & CS_ODONE) {
1818 disable_intr();
1819 com_events -= LOTS_OF_EVENTS;
1820 com->state &= ~CS_ODONE;
1821 enable_intr();
1822 (*linesw[tp->t_line].l_start)(tp);
1823 }
1824 if (com_events == 0)
1825 break;
1826 }
1827 if (com_events >= LOTS_OF_EVENTS)
1828 goto repeat;
1829}
1830
1831static int
1832comparam(tp, t)
1833 struct tty *tp;
1834 struct termios *t;
1835{
1836 int bits;
1837 int cflag;
1838 struct com_s *com;
1839 u_char cor_change;
1840 u_long cy_clock;
1841 int idivisor;
1842 int iflag;
1843 int iprescaler;
1844 int itimeout;
1845 int odivisor;
1846 int oprescaler;
1847 u_char opt;
1848 int s;
1849 int unit;
1850
1851 /* do historical conversions */
1852 if (t->c_ispeed == 0)
1853 t->c_ispeed = t->c_ospeed;
1854
1855 unit = DEV_TO_UNIT(tp->t_dev);
1856 com = com_addr(unit);
1857
1858 /* check requested parameters */
1859 cy_clock = CY_CLOCK(com->gfrcr_image);
1860 idivisor = comspeed(t->c_ispeed, cy_clock, &iprescaler);
1861 if (idivisor < 0)
1862 return (EINVAL);
1863 odivisor = comspeed(t->c_ospeed, cy_clock, &oprescaler);
1864 if (odivisor < 0)
1865 return (EINVAL);
1866
1867 /* parameters are OK, convert them to the com struct and the device */
1868 s = spltty();
1869 if (odivisor == 0)
1870 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
1871 else
1872 (void)commctl(com, TIOCM_DTR, DMBIS);
1873
1874 /*
1875 * This returns with interrupts disabled so that we can complete
1876 * the speed change atomically.
1877 */
1878 (void) siosetwater(com, t->c_ispeed);
1879
1880 /* XXX we don't actually change the speed atomically. */
1881 enable_intr();
1882
1883 if (idivisor != 0) {
1884 cd_setreg(com, CD1400_RBPR, idivisor);
1885 cd_setreg(com, CD1400_RCOR, iprescaler);
1886 }
1887 if (odivisor != 0) {
1888 cd_setreg(com, CD1400_TBPR, odivisor);
1889 cd_setreg(com, CD1400_TCOR, oprescaler);
1890 }
1891
1892 /*
1893 * channel control
1894 * receiver enable
1895 * transmitter enable (always set)
1896 */
1897 cflag = t->c_cflag;
1898 opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
1899 | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
1900 if (opt != com->channel_control) {
1901 com->channel_control = opt;
1902 cd1400_channel_cmd(com, opt);
1903 }
1904
1905#ifdef Smarts
1906 /* set special chars */
1907 /* XXX if one is _POSIX_VDISABLE, can't use some others */
1908 if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
1909 cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]);
1910 if (t->c_cc[VSTART] != _POSIX_VDISABLE)
1911 cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]);
1912 if (t->c_cc[VINTR] != _POSIX_VDISABLE)
1913 cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]);
1914 if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
1915 cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]);
1916#endif
1917
1918 /*
1919 * set channel option register 1 -
1920 * parity mode
1921 * stop bits
1922 * char length
1923 */
1924 opt = 0;
1925 /* parity */
1926 if (cflag & PARENB) {
1927 if (cflag & PARODD)
1928 opt |= CD1400_COR1_PARODD;
1929 opt |= CD1400_COR1_PARNORMAL;
1930 }
1931 iflag = t->c_iflag;
1932 if (!(iflag & INPCK))
1933 opt |= CD1400_COR1_NOINPCK;
1934 bits = 1 + 1;
1935 /* stop bits */
1936 if (cflag & CSTOPB) {
1937 ++bits;
1938 opt |= CD1400_COR1_STOP2;
1939 }
1940 /* char length */
1941 switch (cflag & CSIZE) {
1942 case CS5:
1943 bits += 5;
1944 opt |= CD1400_COR1_CS5;
1945 break;
1946 case CS6:
1947 bits += 6;
1948 opt |= CD1400_COR1_CS6;
1949 break;
1950 case CS7:
1951 bits += 7;
1952 opt |= CD1400_COR1_CS7;
1953 break;
1954 default:
1955 bits += 8;
1956 opt |= CD1400_COR1_CS8;
1957 break;
1958 }
1959 cor_change = 0;
1960 if (opt != com->cor[0]) {
1961 cor_change |= CD1400_CCR_COR1;
1962 cd_setreg(com, CD1400_COR1, com->cor[0] = opt);
1963 }
1964
1965 /*
1966 * Set receive time-out period, normally to max(one char time, 5 ms).
1967 */
1968 if (t->c_ispeed == 0)
1969 itimeout = cd_getreg(com, CD1400_RTPR);
1970 else {
1971 itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
1972#ifdef SOFT_HOTCHAR
1973#define MIN_RTP 1
1974#else
1975#define MIN_RTP 5
1976#endif
1977 if (itimeout < MIN_RTP)
1978 itimeout = MIN_RTP;
1979 }
1980 if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
1981 && t->c_cc[VTIME] * 10 > itimeout)
1982 itimeout = t->c_cc[VTIME] * 10;
1983 if (itimeout > 255)
1984 itimeout = 255;
1985 cd_setreg(com, CD1400_RTPR, itimeout);
1986
1987 /*
1988 * set channel option register 2 -
1989 * flow control
1990 */
1991 opt = 0;
1992#ifdef Smarts
1993 if (iflag & IXANY)
1994 opt |= CD1400_COR2_IXANY;
1995 if (iflag & IXOFF)
1996 opt |= CD1400_COR2_IXOFF;
1997#endif
1998#ifndef SOFT_CTS_OFLOW
1999 if (cflag & CCTS_OFLOW)
2000 opt |= CD1400_COR2_CCTS_OFLOW;
2001#endif
2002 disable_intr();
2003 if (opt != com->cor[1]) {
2004 cor_change |= CD1400_CCR_COR2;
2005 cd_setreg(com, CD1400_COR2, com->cor[1] = opt);
2006 }
2007 enable_intr();
2008
2009 /*
2010 * set channel option register 3 -
2011 * receiver FIFO interrupt threshold
2012 * flow control
2013 */
2014 opt = RxFifoThreshold;
2015#ifdef Smarts
2016 if (t->c_lflag & ICANON)
2017 opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */
2018 if (iflag & IXOFF)
2019 /* detect and transparently handle START and STOP chars */
2020 opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
2021#endif
2022 if (opt != com->cor[2]) {
2023 cor_change |= CD1400_CCR_COR3;
2024 cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
2025 }
2026
2027 /* notify the CD1400 if COR1-3 have changed */
2028 if (cor_change)
2029 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change);
2030
2031 /*
2032 * set channel option register 4 -
2033 * CR/NL processing
2034 * break processing
2035 * received exception processing
2036 */
2037 opt = 0;
2038 if (iflag & IGNCR)
2039 opt |= CD1400_COR4_IGNCR;
2040#ifdef Smarts
2041 /*
2042 * we need a new ttyinput() for this, as we don't want to
2043 * have ICRNL && INLCR being done in both layers, or to have
2044 * synchronisation problems
2045 */
2046 if (iflag & ICRNL)
2047 opt |= CD1400_COR4_ICRNL;
2048 if (iflag & INLCR)
2049 opt |= CD1400_COR4_INLCR;
2050#endif
2051 if (iflag & IGNBRK)
2052 opt |= CD1400_COR4_IGNBRK | CD1400_COR4_NOBRKINT;
2053 /*
2054 * The `-ignbrk -brkint parmrk' case is not handled by the hardware,
2055 * so only tell the hardware about -brkint if -parmrk.
2056 */
2057 if (!(iflag & (BRKINT | PARMRK)))
2058 opt |= CD1400_COR4_NOBRKINT;
2059#if 0
2060 /* XXX using this "intelligence" breaks reporting of overruns. */
2061 if (iflag & IGNPAR)
2062 opt |= CD1400_COR4_PFO_DISCARD;
2063 else {
2064 if (iflag & PARMRK)
2065 opt |= CD1400_COR4_PFO_ESC;
2066 else
2067 opt |= CD1400_COR4_PFO_NUL;
2068 }
2069#else
2070 opt |= CD1400_COR4_PFO_EXCEPTION;
2071#endif
2072 cd_setreg(com, CD1400_COR4, opt);
2073
2074 /*
2075 * set channel option register 5 -
2076 */
2077 opt = 0;
2078 if (iflag & ISTRIP)
2079 opt |= CD1400_COR5_ISTRIP;
2080 if (t->c_iflag & IEXTEN)
2081 /* enable LNEXT (e.g. ctrl-v quoting) handling */
2082 opt |= CD1400_COR5_LNEXT;
2083#ifdef Smarts
2084 if (t->c_oflag & ONLCR)
2085 opt |= CD1400_COR5_ONLCR;
2086 if (t->c_oflag & OCRNL)
2087 opt |= CD1400_COR5_OCRNL;
2088#endif
2089 cd_setreg(com, CD1400_COR5, opt);
2090
2091 /*
2092 * We always generate modem status change interrupts for CD changes.
2093 * Among other things, this is necessary to track TS_CARR_ON for
2094 * pstat to print even when the driver doesn't care. CD changes
2095 * should be rare so interrupts for them are not worth extra code to
2096 * avoid. We avoid interrupts for other modem status changes (except
2097 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is
2098 * simplest and best.
2099 */
2100
2101 /*
2102 * set modem change option register 1
2103 * generate modem interrupts on which 1 -> 0 input transitions
2104 * also controls auto-DTR output flow-control, which we don't use
2105 */
2106 opt = CD1400_MCOR1_CDzd;
2107#ifdef SOFT_CTS_OFLOW
2108 if (cflag & CCTS_OFLOW)
2109 opt |= CD1400_MCOR1_CTSzd;
2110#endif
2111 cd_setreg(com, CD1400_MCOR1, opt);
2112
2113 /*
2114 * set modem change option register 2
2115 * generate modem interrupts on specific 0 -> 1 input transitions
2116 */
2117 opt = CD1400_MCOR2_CDod;
2118#ifdef SOFT_CTS_OFLOW
2119 if (cflag & CCTS_OFLOW)
2120 opt |= CD1400_MCOR2_CTSod;
2121#endif
2122 cd_setreg(com, CD1400_MCOR2, opt);
2123
2124 /*
2125 * XXX should have done this long ago, but there is too much state
2126 * to change all atomically.
2127 */
2128 disable_intr();
2129
2130 com->state &= ~CS_TTGO;
2131 if (!(tp->t_state & TS_TTSTOP))
2132 com->state |= CS_TTGO;
2133 if (cflag & CRTS_IFLOW) {
2134 com->state |= CS_RTS_IFLOW;
2135 /*
2136 * If CS_RTS_IFLOW just changed from off to on, the change
2137 * needs to be propagated to MCR_RTS. This isn't urgent,
2138 * so do it later by calling comstart() instead of repeating
2139 * a lot of code from comstart() here.
2140 */
2141 } else if (com->state & CS_RTS_IFLOW) {
2142 com->state &= ~CS_RTS_IFLOW;
2143 /*
2144 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS
2145 * on here, since comstart() won't do it later.
2146 */
2147#if 0
2148 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2149#else
2150 cd_setreg(com, com->mcr_rts_reg,
2151 com->mcr_image |= com->mcr_rts);
2152#endif
2153 }
2154
2155 /*
2156 * Set up state to handle output flow control.
2157 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2158 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2159 */
2160 com->state |= CS_ODEVREADY;
2161#ifdef SOFT_CTS_OFLOW
2162 com->state &= ~CS_CTS_OFLOW;
2163 if (cflag & CCTS_OFLOW) {
2164 com->state |= CS_CTS_OFLOW;
2165 if (!(com->last_modem_status & MSR_CTS))
2166 com->state &= ~CS_ODEVREADY;
2167 }
2168#endif
2169 /* XXX shouldn't call functions while intrs are disabled. */
2170 disc_optim(tp, t, com);
2171#if 0
2172 /*
2173 * Recover from fiddling with CS_TTGO. We used to call siointr1()
2174 * unconditionally, but that defeated the careful discarding of
2175 * stale input in sioopen().
2176 */
2177 if (com->state >= (CS_BUSY | CS_TTGO))
2178 siointr1(com);
2179#endif
2180 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2181 if (!(com->intr_enable & CD1400_SRER_TXRDY))
2182 cd_setreg(com, CD1400_SRER,
2183 com->intr_enable
2184 = (com->intr_enable & ~CD1400_SRER_TXMPTY)
2185 | CD1400_SRER_TXRDY);
2186 } else {
2187 if (com->intr_enable & CD1400_SRER_TXRDY)
2188 cd_setreg(com, CD1400_SRER,
2189 com->intr_enable
2190 = (com->intr_enable & ~CD1400_SRER_TXRDY)
2191 | CD1400_SRER_TXMPTY);
2192 }
2193
2194 enable_intr();
2195 splx(s);
2196 comstart(tp);
2197 if (com->ibufold != NULL) {
2198 free(com->ibufold, M_DEVBUF);
2199 com->ibufold = NULL;
2200 }
2201 return (0);
2202}
2203
2204static int
2205siosetwater(com, speed)
2206 struct com_s *com;
2207 speed_t speed;
2208{
2209 int cp4ticks;
2210 u_char *ibuf;
2211 int ibufsize;
2212 struct tty *tp;
2213
2214 /*
2215 * Make the buffer size large enough to handle a softtty interrupt
2216 * latency of about 2 ticks without loss of throughput or data
2217 * (about 3 ticks if input flow control is not used or not honoured,
2218 * but a bit less for CS5-CS7 modes).
2219 */
2220 cp4ticks = speed / 10 / hz * 4;
2221 for (ibufsize = 128; ibufsize < cp4ticks;)
2222 ibufsize <<= 1;
2223 if (ibufsize == com->ibufsize) {
2224 disable_intr();
2225 return (0);
2226 }
2227
2228 /*
2229 * Allocate input buffer. The extra factor of 2 in the size is
2230 * to allow for an error byte for each input byte.
2231 */
2232 ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
2233 if (ibuf == NULL) {
2234 disable_intr();
2235 return (ENOMEM);
2236 }
2237
2238 /* Initialize non-critical variables. */
2239 com->ibufold = com->ibuf;
2240 com->ibufsize = ibufsize;
2241 tp = com->tp;
2242 if (tp != NULL) {
2243 tp->t_ififosize = 2 * ibufsize;
2244 tp->t_ispeedwat = (speed_t)-1;
2245 tp->t_ospeedwat = (speed_t)-1;
2246 }
2247
2248 /*
2249 * Read current input buffer, if any. Continue with interrupts
2250 * disabled.
2251 */
2252 disable_intr();
2253 if (com->iptr != com->ibuf)
2254 sioinput(com);
2255
2256 /*-
2257 * Initialize critical variables, including input buffer watermarks.
2258 * The external device is asked to stop sending when the buffer
2259 * exactly reaches high water, or when the high level requests it.
2260 * The high level is notified immediately (rather than at a later
2261 * clock tick) when this watermark is reached.
2262 * The buffer size is chosen so the watermark should almost never
2263 * be reached.
2264 * The low watermark is invisibly 0 since the buffer is always
2265 * emptied all at once.
2266 */
2267 com->iptr = com->ibuf = ibuf;
2268 com->ibufend = ibuf + ibufsize;
2269 com->ierroff = ibufsize;
2270 com->ihighwater = ibuf + 3 * ibufsize / 4;
2271 return (0);
2272}
2273
2274static void
2275comstart(tp)
2276 struct tty *tp;
2277{
2278 struct com_s *com;
2279 int s;
2280#ifdef CyDebug
2281 bool_t started;
2282#endif
2283 int unit;
2284
2285 unit = DEV_TO_UNIT(tp->t_dev);
2286 com = com_addr(unit);
2287 s = spltty();
2288
2289#ifdef CyDebug
2290 ++com->start_count;
2291 started = FALSE;
2292#endif
2293
2294 disable_intr();
2295 if (tp->t_state & TS_TTSTOP) {
2296 com->state &= ~CS_TTGO;
2297 if (com->intr_enable & CD1400_SRER_TXRDY)
2298 cd_setreg(com, CD1400_SRER,
2299 com->intr_enable
2300 = (com->intr_enable & ~CD1400_SRER_TXRDY)
2301 | CD1400_SRER_TXMPTY);
2302 } else {
2303 com->state |= CS_TTGO;
2304 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
2305 && !(com->intr_enable & CD1400_SRER_TXRDY))
2306 cd_setreg(com, CD1400_SRER,
2307 com->intr_enable
2308 = (com->intr_enable & ~CD1400_SRER_TXMPTY)
2309 | CD1400_SRER_TXRDY);
2310 }
2311 if (tp->t_state & TS_TBLOCK) {
2312 if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW)
2313#if 0
2314 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2315#else
2316 cd_setreg(com, com->mcr_rts_reg,
2317 com->mcr_image &= ~com->mcr_rts);
2318#endif
2319 } else {
2320 if (!(com->mcr_image & com->mcr_rts)
2321 && com->iptr < com->ihighwater
2322 && com->state & CS_RTS_IFLOW)
2323#if 0
2324 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2325#else
2326 cd_setreg(com, com->mcr_rts_reg,
2327 com->mcr_image |= com->mcr_rts);
2328#endif
2329 }
2330 enable_intr();
2331 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2332 ttwwakeup(tp);
2333 splx(s);
2334 return;
2335 }
2336 if (tp->t_outq.c_cc != 0) {
2337 struct lbq *qp;
2338 struct lbq *next;
2339
2340 if (!com->obufs[0].l_queued) {
2341#ifdef CyDebug
2342 started = TRUE;
2343#endif
2344 com->obufs[0].l_tail
2345 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2346 sizeof com->obuf1);
2347 com->obufs[0].l_next = NULL;
2348 com->obufs[0].l_queued = TRUE;
2349 disable_intr();
2350 if (com->state & CS_BUSY) {
2351 qp = com->obufq.l_next;
2352 while ((next = qp->l_next) != NULL)
2353 qp = next;
2354 qp->l_next = &com->obufs[0];
2355 } else {
2356 com->obufq.l_head = com->obufs[0].l_head;
2357 com->obufq.l_tail = com->obufs[0].l_tail;
2358 com->obufq.l_next = &com->obufs[0];
2359 com->state |= CS_BUSY;
2360 if (com->state >= (CS_BUSY | CS_TTGO
2361 | CS_ODEVREADY))
2362 cd_setreg(com, CD1400_SRER,
2363 com->intr_enable
2364 = (com->intr_enable
2365 & ~CD1400_SRER_TXMPTY)
2366 | CD1400_SRER_TXRDY);
2367 }
2368 enable_intr();
2369 }
2370 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2371#ifdef CyDebug
2372 started = TRUE;
2373#endif
2374 com->obufs[1].l_tail
2375 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2376 sizeof com->obuf2);
2377 com->obufs[1].l_next = NULL;
2378 com->obufs[1].l_queued = TRUE;
2379 disable_intr();
2380 if (com->state & CS_BUSY) {
2381 qp = com->obufq.l_next;
2382 while ((next = qp->l_next) != NULL)
2383 qp = next;
2384 qp->l_next = &com->obufs[1];
2385 } else {
2386 com->obufq.l_head = com->obufs[1].l_head;
2387 com->obufq.l_tail = com->obufs[1].l_tail;
2388 com->obufq.l_next = &com->obufs[1];
2389 com->state |= CS_BUSY;
2390 if (com->state >= (CS_BUSY | CS_TTGO
2391 | CS_ODEVREADY))
2392 cd_setreg(com, CD1400_SRER,
2393 com->intr_enable
2394 = (com->intr_enable
2395 & ~CD1400_SRER_TXMPTY)
2396 | CD1400_SRER_TXRDY);
2397 }
2398 enable_intr();
2399 }
2400 tp->t_state |= TS_BUSY;
2401 }
2402#ifdef CyDebug
2403 if (started)
2404 ++com->start_real;
2405#endif
2406#if 0
2407 disable_intr();
2408 if (com->state >= (CS_BUSY | CS_TTGO))
2409 siointr1(com); /* fake interrupt to start output */
2410 enable_intr();
2411#endif
2412 ttwwakeup(tp);
2413 splx(s);
2414}
2415
2416static void
857 comhardclose(com);
858 ttyclose(tp);
859 siosettimeout();
860 splx(s);
861#ifdef broken /* session holds a ref to the tty; can't deallocate */
862 ttyfree(tp);
863 com->tp = sio_tty[unit] = NULL;
864#endif
865 return (0);
866}
867
868static void
869comhardclose(com)
870 struct com_s *com;
871{
872 cy_addr iobase;
873 int s;
874 struct tty *tp;
875 int unit;
876
877 unit = com->unit;
878 iobase = com->iobase;
879 s = spltty();
880#if 0
881 com->poll = FALSE;
882 com->poll_output = FALSE;
883#endif
884 com->do_timestamp = 0;
885#if 0
886 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
887#else
888 /* XXX */
889 disable_intr();
890 com->etc = ETC_NONE;
891 cd_setreg(com, CD1400_COR2, com->cor[1] &= ~CD1400_COR2_ETC);
892 enable_intr();
893 cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
894#endif
895
896 {
897#if 0
898 outb(iobase + com_ier, 0);
899#else
900 disable_intr();
901 cd_setreg(com, CD1400_SRER, com->intr_enable = 0);
902 enable_intr();
903#endif
904 tp = com->tp;
905 if ((tp->t_cflag & HUPCL)
906 /*
907 * XXX we will miss any carrier drop between here and the
908 * next open. Perhaps we should watch DCD even when the
909 * port is closed; it is not sufficient to check it at
910 * the next open because it might go up and down while
911 * we're not watching.
912 */
913 || (!com->active_out
914 && !(com->prev_modem_status & MSR_DCD)
915 && !(com->it_in.c_cflag & CLOCAL))
916 || !(tp->t_state & TS_ISOPEN)) {
917 (void)commctl(com, TIOCM_DTR, DMBIC);
918
919 /* Disable receiver (leave transmitter enabled). */
920 com->channel_control = CD1400_CCR_CMDCHANCTL
921 | CD1400_CCR_XMTEN
922 | CD1400_CCR_RCVDIS;
923 cd1400_channel_cmd(com, com->channel_control);
924
925 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
926 timeout(siodtrwakeup, com, com->dtr_wait);
927 com->state |= CS_DTR_OFF;
928 }
929 }
930 }
931#if 0
932 if (com->hasfifo) {
933 /*
934 * Disable fifos so that they are off after controlled
935 * reboots. Some BIOSes fail to detect 16550s when the
936 * fifos are enabled.
937 */
938 outb(iobase + com_fifo, 0);
939 }
940#endif
941 com->active_out = FALSE;
942 wakeup(&com->active_out);
943 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
944 splx(s);
945}
946
947static int
948sioread(dev, uio, flag)
949 dev_t dev;
950 struct uio *uio;
951 int flag;
952{
953 int mynor;
954 struct tty *tp;
955
956 mynor = minor(dev);
957 if (mynor & CONTROL_MASK)
958 return (ENODEV);
959 tp = com_addr(MINOR_TO_UNIT(mynor))->tp;
960 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
961}
962
963static int
964siowrite(dev, uio, flag)
965 dev_t dev;
966 struct uio *uio;
967 int flag;
968{
969 int mynor;
970 struct tty *tp;
971 int unit;
972
973 mynor = minor(dev);
974 if (mynor & CONTROL_MASK)
975 return (ENODEV);
976
977 unit = MINOR_TO_UNIT(mynor);
978 tp = com_addr(unit)->tp;
979 /*
980 * (XXX) We disallow virtual consoles if the physical console is
981 * a serial port. This is in case there is a display attached that
982 * is not the console. In that situation we don't need/want the X
983 * server taking over the console.
984 */
985 if (constty != NULL && unit == comconsole)
986 constty = NULL;
987#ifdef Smarts
988 /* XXX duplicate ttwrite(), but without so much output processing on
989 * CR & LF chars. Hardly worth the effort, given that high-throughput
990 * sessions are raw anyhow.
991 */
992#else
993 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
994#endif
995}
996
997static void
998siodtrwakeup(chan)
999 void *chan;
1000{
1001 struct com_s *com;
1002
1003 com = (struct com_s *)chan;
1004 com->state &= ~CS_DTR_OFF;
1005 wakeup(&com->dtr_wait);
1006}
1007
1008static void
1009sioinput(com)
1010 struct com_s *com;
1011{
1012 u_char *buf;
1013 int incc;
1014 u_char line_status;
1015 int recv_data;
1016 struct tty *tp;
1017
1018 buf = com->ibuf;
1019 tp = com->tp;
1020 if (!(tp->t_state & TS_ISOPEN)) {
1021 com_events -= (com->iptr - com->ibuf);
1022 com->iptr = com->ibuf;
1023 return;
1024 }
1025 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1026 /*
1027 * Avoid the grotesquely inefficient lineswitch routine
1028 * (ttyinput) in "raw" mode. It usually takes about 450
1029 * instructions (that's without canonical processing or echo!).
1030 * slinput is reasonably fast (usually 40 instructions plus
1031 * call overhead).
1032 */
1033 do {
1034 enable_intr();
1035 incc = com->iptr - buf;
1036 if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
1037 && (com->state & CS_RTS_IFLOW
1038 || tp->t_iflag & IXOFF)
1039 && !(tp->t_state & TS_TBLOCK))
1040 ttyblock(tp);
1041 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1042 += b_to_q((char *)buf, incc, &tp->t_rawq);
1043 buf += incc;
1044 tk_nin += incc;
1045 tk_rawcc += incc;
1046 tp->t_rawcc += incc;
1047 ttwakeup(tp);
1048 if (tp->t_state & TS_TTSTOP
1049 && (tp->t_iflag & IXANY
1050 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1051 tp->t_state &= ~TS_TTSTOP;
1052 tp->t_lflag &= ~FLUSHO;
1053 comstart(tp);
1054 }
1055 disable_intr();
1056 } while (buf < com->iptr);
1057 } else {
1058 do {
1059 enable_intr();
1060 line_status = buf[com->ierroff];
1061 recv_data = *buf++;
1062 if (line_status
1063 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1064 if (line_status & LSR_BI)
1065 recv_data |= TTY_BI;
1066 if (line_status & LSR_FE)
1067 recv_data |= TTY_FE;
1068 if (line_status & LSR_OE)
1069 recv_data |= TTY_OE;
1070 if (line_status & LSR_PE)
1071 recv_data |= TTY_PE;
1072 }
1073 (*linesw[tp->t_line].l_rint)(recv_data, tp);
1074 disable_intr();
1075 } while (buf < com->iptr);
1076 }
1077 com_events -= (com->iptr - com->ibuf);
1078 com->iptr = com->ibuf;
1079
1080 /*
1081 * There is now room for another low-level buffer full of input,
1082 * so enable RTS if it is now disabled and there is room in the
1083 * high-level buffer.
1084 */
1085 if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & com->mcr_rts) &&
1086 !(tp->t_state & TS_TBLOCK))
1087#if 0
1088 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1089#else
1090 cd_setreg(com, com->mcr_rts_reg,
1091 com->mcr_image |= com->mcr_rts);
1092#endif
1093}
1094
1095void
1096siointr(unit)
1097 int unit;
1098{
1099 int baseu;
1100 int cy_align;
1101 cy_addr cy_iobase;
1102 int cyu;
1103 cy_addr iobase;
1104 u_char status;
1105
1106 COM_LOCK(); /* XXX could this be placed down lower in the loop? */
1107
1108 baseu = unit * CY_MAX_PORTS;
1109 cy_align = com_addr(baseu)->cy_align;
1110 cy_iobase = com_addr(baseu)->cy_iobase;
1111
1112 /* check each CD1400 in turn */
1113 for (cyu = 0; cyu < cy_nr_cd1400s[unit]; ++cyu) {
1114 iobase = (cy_addr) (cy_iobase
1115 + (cy_chip_offset[cyu] << cy_align));
1116 /* poll to see if it has any work */
1117 status = cd_inb(iobase, CD1400_SVRR, cy_align);
1118 if (status == 0)
1119 continue;
1120#ifdef CyDebug
1121 ++cy_svrr_probes;
1122#endif
1123 /* service requests as appropriate, giving priority to RX */
1124 if (status & CD1400_SVRR_RXRDY) {
1125 struct com_s *com;
1126 u_int count;
1127 u_char *ioptr;
1128 u_char line_status;
1129 u_char recv_data;
1130 u_char serv_type;
1131#ifdef PollMode
1132 u_char save_rir;
1133#endif
1134
1135#ifdef PollMode
1136 save_rir = cd_inb(iobase, CD1400_RIR, cy_align);
1137
1138 /* enter rx service */
1139 cd_outb(iobase, CD1400_CAR, cy_align, save_rir);
1140 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1141 = save_rir & CD1400_CAR_CHAN;
1142
1143 serv_type = cd_inb(iobase, CD1400_RIVR, cy_align);
1144 com = com_addr(baseu
1145 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1146 & CD1400_xIVR_CHAN));
1147#else
1148 /* ack receive service */
1149 serv_type = cy_inb(iobase, CY8_SVCACKR, cy_align);
1150
1151 com = com_addr(baseu +
1152 + ((serv_type >> CD1400_xIVR_CHAN_SHIFT)
1153 & CD1400_xIVR_CHAN));
1154#endif
1155
1156 if (serv_type & CD1400_RIVR_EXCEPTION) {
1157 ++com->recv_exception;
1158 line_status = cd_inb(iobase, CD1400_RDSR, cy_align);
1159 /* break/unnattached error bits or real input? */
1160 recv_data = cd_inb(iobase, CD1400_RDSR, cy_align);
1161#ifndef SOFT_HOTCHAR
1162 if (line_status & CD1400_RDSR_SPECIAL
1163 && com->hotchar != 0)
1164 setsofttty();
1165#endif
1166#if 1 /* XXX "intelligent" PFO error handling would break O error handling */
1167 if (line_status & (LSR_PE|LSR_FE|LSR_BI)) {
1168 /*
1169 Don't store PE if IGNPAR and BI if IGNBRK,
1170 this hack allows "raw" tty optimization
1171 works even if IGN* is set.
1172 */
1173 if ( com->tp == NULL
1174 || !(com->tp->t_state & TS_ISOPEN)
1175 || ((line_status & (LSR_PE|LSR_FE))
1176 && (com->tp->t_iflag & IGNPAR))
1177 || ((line_status & LSR_BI)
1178 && (com->tp->t_iflag & IGNBRK)))
1179 goto cont;
1180 if ( (line_status & (LSR_PE|LSR_FE))
1181 && (com->tp->t_state & TS_CAN_BYPASS_L_RINT)
1182 && ((line_status & LSR_FE)
1183 || ((line_status & LSR_PE)
1184 && (com->tp->t_iflag & INPCK))))
1185 recv_data = 0;
1186 }
1187#endif /* 1 */
1188 ++com->bytes_in;
1189#ifdef SOFT_HOTCHAR
1190 if (com->hotchar != 0 && recv_data == com->hotchar)
1191 setsofttty();
1192#endif
1193 ioptr = com->iptr;
1194 if (ioptr >= com->ibufend)
1195 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1196 else {
1197 if (com->do_timestamp)
1198 microtime(&com->timestamp);
1199 ++com_events;
1200 ioptr[0] = recv_data;
1201 ioptr[com->ierroff] = line_status;
1202 com->iptr = ++ioptr;
1203 if (ioptr == com->ihighwater
1204 && com->state & CS_RTS_IFLOW)
1205#if 0
1206 outb(com->modem_ctl_port,
1207 com->mcr_image &= ~MCR_RTS);
1208#else
1209 cd_outb(iobase, com->mcr_rts_reg,
1210 cy_align,
1211 com->mcr_image &=
1212 ~com->mcr_rts);
1213#endif
1214 if (line_status & LSR_OE)
1215 CE_RECORD(com, CE_OVERRUN);
1216 }
1217 goto cont;
1218 } else {
1219 int ifree;
1220
1221 count = cd_inb(iobase, CD1400_RDCR, cy_align);
1222 if (!count)
1223 goto cont;
1224 com->bytes_in += count;
1225 ioptr = com->iptr;
1226 ifree = com->ibufend - ioptr;
1227 if (count > ifree) {
1228 count -= ifree;
1229 com_events += ifree;
1230 if (ifree != 0) {
1231 if (com->do_timestamp)
1232 microtime(&com->timestamp);
1233 do {
1234 recv_data = cd_inb(iobase,
1235 CD1400_RDSR,
1236 cy_align);
1237#ifdef SOFT_HOTCHAR
1238 if (com->hotchar != 0
1239 && recv_data
1240 == com->hotchar)
1241 setsofttty();
1242#endif
1243 ioptr[0] = recv_data;
1244 ioptr[com->ierroff] = 0;
1245 ++ioptr;
1246 } while (--ifree != 0);
1247 }
1248 com->delta_error_counts
1249 [CE_INTERRUPT_BUF_OVERFLOW] += count;
1250 do {
1251 recv_data = cd_inb(iobase, CD1400_RDSR,
1252 cy_align);
1253#ifdef SOFT_HOTCHAR
1254 if (com->hotchar != 0
1255 && recv_data == com->hotchar)
1256 setsofttty();
1257#endif
1258 } while (--count != 0);
1259 } else {
1260 if (com->do_timestamp)
1261 microtime(&com->timestamp);
1262 if (ioptr <= com->ihighwater
1263 && ioptr + count > com->ihighwater
1264 && com->state & CS_RTS_IFLOW)
1265#if 0
1266 outb(com->modem_ctl_port,
1267 com->mcr_image &= ~MCR_RTS);
1268#else
1269 cd_outb(iobase, com->mcr_rts_reg,
1270 cy_align,
1271 com->mcr_image
1272 &= ~com->mcr_rts);
1273#endif
1274 com_events += count;
1275 do {
1276 recv_data = cd_inb(iobase, CD1400_RDSR,
1277 cy_align);
1278#ifdef SOFT_HOTCHAR
1279 if (com->hotchar != 0
1280 && recv_data == com->hotchar)
1281 setsofttty();
1282#endif
1283 ioptr[0] = recv_data;
1284 ioptr[com->ierroff] = 0;
1285 ++ioptr;
1286 } while (--count != 0);
1287 }
1288 com->iptr = ioptr;
1289 }
1290cont:
1291
1292 /* terminate service context */
1293#ifdef PollMode
1294 cd_outb(iobase, CD1400_RIR, cy_align,
1295 save_rir
1296 & ~(CD1400_RIR_RDIREQ | CD1400_RIR_RBUSY));
1297#else
1298 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1299#endif
1300 }
1301 if (status & CD1400_SVRR_MDMCH) {
1302 struct com_s *com;
1303 u_char modem_status;
1304#ifdef PollMode
1305 u_char save_mir;
1306#else
1307 u_char vector;
1308#endif
1309
1310#ifdef PollMode
1311 save_mir = cd_inb(iobase, CD1400_MIR, cy_align);
1312
1313 /* enter modem service */
1314 cd_outb(iobase, CD1400_CAR, cy_align, save_mir);
1315 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1316 = save_mir & CD1400_CAR_CHAN;
1317
1318 com = com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS
1319 + (save_mir & CD1400_MIR_CHAN));
1320#else
1321 /* ack modem service */
1322 vector = cy_inb(iobase, CY8_SVCACKM, cy_align);
1323
1324 com = com_addr(baseu
1325 + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1326 & CD1400_xIVR_CHAN));
1327#endif
1328 ++com->mdm;
1329 modem_status = cd_inb(iobase, CD1400_MSVR2, cy_align);
1330 if (modem_status != com->last_modem_status) {
1331 if (com->do_dcd_timestamp
1332 && !(com->last_modem_status & MSR_DCD)
1333 && modem_status & MSR_DCD)
1334 microtime(&com->dcd_timestamp);
1335
1336 /*
1337 * Schedule high level to handle DCD changes. Note
1338 * that we don't use the delta bits anywhere. Some
1339 * UARTs mess them up, and it's easy to remember the
1340 * previous bits and calculate the delta.
1341 */
1342 com->last_modem_status = modem_status;
1343 if (!(com->state & CS_CHECKMSR)) {
1344 com_events += LOTS_OF_EVENTS;
1345 com->state |= CS_CHECKMSR;
1346 setsofttty();
1347 }
1348
1349#ifdef SOFT_CTS_OFLOW
1350 /* handle CTS change immediately for crisp flow ctl */
1351 if (com->state & CS_CTS_OFLOW) {
1352 if (modem_status & MSR_CTS) {
1353 com->state |= CS_ODEVREADY;
1354 if (com->state >= (CS_BUSY | CS_TTGO
1355 | CS_ODEVREADY)
1356 && !(com->intr_enable
1357 & CD1400_SRER_TXRDY))
1358 cd_outb(iobase, CD1400_SRER,
1359 cy_align,
1360 com->intr_enable
1361 = com->intr_enable
1362 & ~CD1400_SRER_TXMPTY
1363 | CD1400_SRER_TXRDY);
1364 } else {
1365 com->state &= ~CS_ODEVREADY;
1366 if (com->intr_enable
1367 & CD1400_SRER_TXRDY)
1368 cd_outb(iobase, CD1400_SRER,
1369 cy_align,
1370 com->intr_enable
1371 = com->intr_enable
1372 & ~CD1400_SRER_TXRDY
1373 | CD1400_SRER_TXMPTY);
1374 }
1375 }
1376#endif
1377 }
1378
1379 /* terminate service context */
1380#ifdef PollMode
1381 cd_outb(iobase, CD1400_MIR, cy_align,
1382 save_mir
1383 & ~(CD1400_MIR_RDIREQ | CD1400_MIR_RBUSY));
1384#else
1385 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1386#endif
1387 }
1388 if (status & CD1400_SVRR_TXRDY) {
1389 struct com_s *com;
1390#ifdef PollMode
1391 u_char save_tir;
1392#else
1393 u_char vector;
1394#endif
1395
1396#ifdef PollMode
1397 save_tir = cd_inb(iobase, CD1400_TIR, cy_align);
1398
1399 /* enter tx service */
1400 cd_outb(iobase, CD1400_CAR, cy_align, save_tir);
1401 com_addr(baseu + cyu * CD1400_NO_OF_CHANNELS)->car
1402 = save_tir & CD1400_CAR_CHAN;
1403
1404 com = com_addr(baseu
1405 + cyu * CD1400_NO_OF_CHANNELS
1406 + (save_tir & CD1400_TIR_CHAN));
1407#else
1408 /* ack transmit service */
1409 vector = cy_inb(iobase, CY8_SVCACKT, cy_align);
1410
1411 com = com_addr(baseu
1412 + ((vector >> CD1400_xIVR_CHAN_SHIFT)
1413 & CD1400_xIVR_CHAN));
1414#endif
1415
1416 if (com->etc != ETC_NONE) {
1417 if (com->intr_enable & CD1400_SRER_TXRDY) {
1418 /*
1419 * Here due to sloppy SRER_TXRDY
1420 * enabling. Ignore. Come back when
1421 * tx is empty.
1422 */
1423 cd_outb(iobase, CD1400_SRER, cy_align,
1424 com->intr_enable
1425 = (com->intr_enable
1426 & ~CD1400_SRER_TXRDY)
1427 | CD1400_SRER_TXMPTY);
1428 goto terminate_tx_service;
1429 }
1430 switch (com->etc) {
1431 case CD1400_ETC_SENDBREAK:
1432 case CD1400_ETC_STOPBREAK:
1433 /*
1434 * Start the command. Come back on
1435 * next tx empty interrupt, hopefully
1436 * after command has been executed.
1437 */
1438 cd_outb(iobase, CD1400_COR2, cy_align,
1439 com->cor[1] |= CD1400_COR2_ETC);
1440 cd_outb(iobase, CD1400_TDR, cy_align,
1441 CD1400_ETC_CMD);
1442 cd_outb(iobase, CD1400_TDR, cy_align,
1443 com->etc);
1444 if (com->etc == CD1400_ETC_SENDBREAK)
1445 com->etc = ETC_BREAK_STARTING;
1446 else
1447 com->etc = ETC_BREAK_ENDING;
1448 goto terminate_tx_service;
1449 case ETC_BREAK_STARTING:
1450 /*
1451 * BREAK is now on. Continue with
1452 * SRER_TXMPTY processing, hopefully
1453 * don't come back.
1454 */
1455 com->etc = ETC_BREAK_STARTED;
1456 break;
1457 case ETC_BREAK_STARTED:
1458 /*
1459 * Came back due to sloppy SRER_TXMPTY
1460 * enabling. Hope again.
1461 */
1462 break;
1463 case ETC_BREAK_ENDING:
1464 /*
1465 * BREAK is now off. Continue with
1466 * SRER_TXMPTY processing and don't
1467 * come back. The SWI handler will
1468 * restart tx interrupts if necessary.
1469 */
1470 cd_outb(iobase, CD1400_COR2, cy_align,
1471 com->cor[1]
1472 &= ~CD1400_COR2_ETC);
1473 com->etc = ETC_BREAK_ENDED;
1474 if (!(com->state & CS_ODONE)) {
1475 com_events += LOTS_OF_EVENTS;
1476 com->state |= CS_ODONE;
1477 setsofttty();
1478 }
1479 break;
1480 case ETC_BREAK_ENDED:
1481 /*
1482 * Shouldn't get here. Hope again.
1483 */
1484 break;
1485 }
1486 }
1487 if (com->intr_enable & CD1400_SRER_TXMPTY) {
1488 if (!(com->extra_state & CSE_ODONE)) {
1489 com_events += LOTS_OF_EVENTS;
1490 com->extra_state |= CSE_ODONE;
1491 setsofttty();
1492 }
1493 cd_outb(iobase, CD1400_SRER, cy_align,
1494 com->intr_enable
1495 &= ~CD1400_SRER_TXMPTY);
1496 goto terminate_tx_service;
1497 }
1498 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1499 u_char *ioptr;
1500 u_int ocount;
1501
1502 ioptr = com->obufq.l_head;
1503 ocount = com->obufq.l_tail - ioptr;
1504 if (ocount > CD1400_TX_FIFO_SIZE)
1505 ocount = CD1400_TX_FIFO_SIZE;
1506 com->bytes_out += ocount;
1507 do
1508 cd_outb(iobase, CD1400_TDR, cy_align,
1509 *ioptr++);
1510 while (--ocount != 0);
1511 com->obufq.l_head = ioptr;
1512 if (ioptr >= com->obufq.l_tail) {
1513 struct lbq *qp;
1514
1515 qp = com->obufq.l_next;
1516 qp->l_queued = FALSE;
1517 qp = qp->l_next;
1518 if (qp != NULL) {
1519 com->obufq.l_head = qp->l_head;
1520 com->obufq.l_tail = qp->l_tail;
1521 com->obufq.l_next = qp;
1522 } else {
1523 /* output just completed */
1524 com->state &= ~CS_BUSY;
1525
1526 /*
1527 * The setting of CSE_ODONE may be
1528 * stale here. We currently only
1529 * use it when CS_BUSY is set, and
1530 * fixing it when we clear CS_BUSY
1531 * is easiest.
1532 */
1533 if (com->extra_state & CSE_ODONE) {
1534 com_events -= LOTS_OF_EVENTS;
1535 com->extra_state &= ~CSE_ODONE;
1536 }
1537
1538 cd_outb(iobase, CD1400_SRER, cy_align,
1539 com->intr_enable
1540 = (com->intr_enable
1541 & ~CD1400_SRER_TXRDY)
1542 | CD1400_SRER_TXMPTY);
1543 }
1544 if (!(com->state & CS_ODONE)) {
1545 com_events += LOTS_OF_EVENTS;
1546 com->state |= CS_ODONE;
1547
1548 /* handle at high level ASAP */
1549 setsofttty();
1550 }
1551 }
1552 }
1553
1554 /* terminate service context */
1555terminate_tx_service:
1556#ifdef PollMode
1557 cd_outb(iobase, CD1400_TIR, cy_align,
1558 save_tir
1559 & ~(CD1400_TIR_RDIREQ | CD1400_TIR_RBUSY));
1560#else
1561 cd_outb(iobase, CD1400_EOSRR, cy_align, 0);
1562#endif
1563 }
1564 }
1565
1566 /* ensure an edge for the next interrupt */
1567 cy_outb(cy_iobase, CY_CLEAR_INTR, cy_align, 0);
1568
1569 schedsofttty();
1570
1571 COM_UNLOCK();
1572}
1573
1574#if 0
1575static void
1576siointr1(com)
1577 struct com_s *com;
1578{
1579}
1580#endif
1581
1582static int
1583sioioctl(dev, cmd, data, flag, p)
1584 dev_t dev;
1585 u_long cmd;
1586 caddr_t data;
1587 int flag;
1588 struct proc *p;
1589{
1590 struct com_s *com;
1591 int error;
1592 int mynor;
1593 int s;
1594 struct tty *tp;
1595#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1596 int oldcmd;
1597 struct termios term;
1598#endif
1599
1600 mynor = minor(dev);
1601 com = com_addr(MINOR_TO_UNIT(mynor));
1602 if (mynor & CONTROL_MASK) {
1603 struct termios *ct;
1604
1605 switch (mynor & CONTROL_MASK) {
1606 case CONTROL_INIT_STATE:
1607 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1608 break;
1609 case CONTROL_LOCK_STATE:
1610 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1611 break;
1612 default:
1613 return (ENODEV); /* /dev/nodev */
1614 }
1615 switch (cmd) {
1616 case TIOCSETA:
1617 error = suser(p);
1618 if (error != 0)
1619 return (error);
1620 *ct = *(struct termios *)data;
1621 return (0);
1622 case TIOCGETA:
1623 *(struct termios *)data = *ct;
1624 return (0);
1625 case TIOCGETD:
1626 *(int *)data = TTYDISC;
1627 return (0);
1628 case TIOCGWINSZ:
1629 bzero(data, sizeof(struct winsize));
1630 return (0);
1631 default:
1632 return (ENOTTY);
1633 }
1634 }
1635 tp = com->tp;
1636#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1637 term = tp->t_termios;
1638 oldcmd = cmd;
1639 error = ttsetcompat(tp, &cmd, data, &term);
1640 if (error != 0)
1641 return (error);
1642 if (cmd != oldcmd)
1643 data = (caddr_t)&term;
1644#endif
1645 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1646 int cc;
1647 struct termios *dt = (struct termios *)data;
1648 struct termios *lt = mynor & CALLOUT_MASK
1649 ? &com->lt_out : &com->lt_in;
1650
1651 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1652 | (dt->c_iflag & ~lt->c_iflag);
1653 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1654 | (dt->c_oflag & ~lt->c_oflag);
1655 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1656 | (dt->c_cflag & ~lt->c_cflag);
1657 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1658 | (dt->c_lflag & ~lt->c_lflag);
1659 for (cc = 0; cc < NCCS; ++cc)
1660 if (lt->c_cc[cc] != 0)
1661 dt->c_cc[cc] = tp->t_cc[cc];
1662 if (lt->c_ispeed != 0)
1663 dt->c_ispeed = tp->t_ispeed;
1664 if (lt->c_ospeed != 0)
1665 dt->c_ospeed = tp->t_ospeed;
1666 }
1667 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1668 if (error != ENOIOCTL)
1669 return (error);
1670 s = spltty();
1671 error = ttioctl(tp, cmd, data, flag);
1672 disc_optim(tp, &tp->t_termios, com);
1673 if (error != ENOIOCTL) {
1674 splx(s);
1675 return (error);
1676 }
1677 switch (cmd) {
1678 case TIOCSBRK:
1679#if 0
1680 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1681#else
1682 cd_etc(com, CD1400_ETC_SENDBREAK);
1683#endif
1684 break;
1685 case TIOCCBRK:
1686#if 0
1687 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1688#else
1689 cd_etc(com, CD1400_ETC_STOPBREAK);
1690#endif
1691 break;
1692 case TIOCSDTR:
1693 (void)commctl(com, TIOCM_DTR, DMBIS);
1694 break;
1695 case TIOCCDTR:
1696 (void)commctl(com, TIOCM_DTR, DMBIC);
1697 break;
1698 /*
1699 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The
1700 * changes get undone on the next call to comparam().
1701 */
1702 case TIOCMSET:
1703 (void)commctl(com, *(int *)data, DMSET);
1704 break;
1705 case TIOCMBIS:
1706 (void)commctl(com, *(int *)data, DMBIS);
1707 break;
1708 case TIOCMBIC:
1709 (void)commctl(com, *(int *)data, DMBIC);
1710 break;
1711 case TIOCMGET:
1712 *(int *)data = commctl(com, 0, DMGET);
1713 break;
1714 case TIOCMSDTRWAIT:
1715 /* must be root since the wait applies to following logins */
1716 error = suser(p);
1717 if (error != 0) {
1718 splx(s);
1719 return (error);
1720 }
1721 com->dtr_wait = *(int *)data * hz / 100;
1722 break;
1723 case TIOCMGDTRWAIT:
1724 *(int *)data = com->dtr_wait * 100 / hz;
1725 break;
1726 case TIOCTIMESTAMP:
1727 com->do_timestamp = TRUE;
1728 *(struct timeval *)data = com->timestamp;
1729 break;
1730 case TIOCDCDTIMESTAMP:
1731 com->do_dcd_timestamp = TRUE;
1732 *(struct timeval *)data = com->dcd_timestamp;
1733 break;
1734 default:
1735 splx(s);
1736 return (ENOTTY);
1737 }
1738 splx(s);
1739 return (0);
1740}
1741
1742static void
1743siopoll()
1744{
1745 int unit;
1746
1747#ifdef CyDebug
1748 ++cy_timeouts;
1749#endif
1750 if (com_events == 0)
1751 return;
1752repeat:
1753 for (unit = 0; unit < NSIO; ++unit) {
1754 struct com_s *com;
1755 int incc;
1756 struct tty *tp;
1757
1758 com = com_addr(unit);
1759 if (com == NULL)
1760 continue;
1761 tp = com->tp;
1762 if (tp == NULL) {
1763 /*
1764 * XXX forget any events related to closed devices
1765 * (actually never opened devices) so that we don't
1766 * loop.
1767 */
1768 disable_intr();
1769 incc = com->iptr - com->ibuf;
1770 com->iptr = com->ibuf;
1771 if (com->state & CS_CHECKMSR) {
1772 incc += LOTS_OF_EVENTS;
1773 com->state &= ~CS_CHECKMSR;
1774 }
1775 com_events -= incc;
1776 enable_intr();
1777 if (incc != 0)
1778 log(LOG_DEBUG,
1779 "sio%d: %d events for device with no tp\n",
1780 unit, incc);
1781 continue;
1782 }
1783 if (com->iptr != com->ibuf) {
1784 disable_intr();
1785 sioinput(com);
1786 enable_intr();
1787 }
1788 if (com->state & CS_CHECKMSR) {
1789 u_char delta_modem_status;
1790
1791 disable_intr();
1792 delta_modem_status = com->last_modem_status
1793 ^ com->prev_modem_status;
1794 com->prev_modem_status = com->last_modem_status;
1795 com_events -= LOTS_OF_EVENTS;
1796 com->state &= ~CS_CHECKMSR;
1797 enable_intr();
1798 if (delta_modem_status & MSR_DCD)
1799 (*linesw[tp->t_line].l_modem)
1800 (tp, com->prev_modem_status & MSR_DCD);
1801 }
1802 if (com->extra_state & CSE_ODONE) {
1803 disable_intr();
1804 com_events -= LOTS_OF_EVENTS;
1805 com->extra_state &= ~CSE_ODONE;
1806 enable_intr();
1807 if (!(com->state & CS_BUSY)) {
1808 tp->t_state &= ~TS_BUSY;
1809 ttwwakeup(com->tp);
1810 }
1811 if (com->etc != ETC_NONE) {
1812 if (com->etc == ETC_BREAK_ENDED)
1813 com->etc = ETC_NONE;
1814 wakeup(&com->etc);
1815 }
1816 }
1817 if (com->state & CS_ODONE) {
1818 disable_intr();
1819 com_events -= LOTS_OF_EVENTS;
1820 com->state &= ~CS_ODONE;
1821 enable_intr();
1822 (*linesw[tp->t_line].l_start)(tp);
1823 }
1824 if (com_events == 0)
1825 break;
1826 }
1827 if (com_events >= LOTS_OF_EVENTS)
1828 goto repeat;
1829}
1830
1831static int
1832comparam(tp, t)
1833 struct tty *tp;
1834 struct termios *t;
1835{
1836 int bits;
1837 int cflag;
1838 struct com_s *com;
1839 u_char cor_change;
1840 u_long cy_clock;
1841 int idivisor;
1842 int iflag;
1843 int iprescaler;
1844 int itimeout;
1845 int odivisor;
1846 int oprescaler;
1847 u_char opt;
1848 int s;
1849 int unit;
1850
1851 /* do historical conversions */
1852 if (t->c_ispeed == 0)
1853 t->c_ispeed = t->c_ospeed;
1854
1855 unit = DEV_TO_UNIT(tp->t_dev);
1856 com = com_addr(unit);
1857
1858 /* check requested parameters */
1859 cy_clock = CY_CLOCK(com->gfrcr_image);
1860 idivisor = comspeed(t->c_ispeed, cy_clock, &iprescaler);
1861 if (idivisor < 0)
1862 return (EINVAL);
1863 odivisor = comspeed(t->c_ospeed, cy_clock, &oprescaler);
1864 if (odivisor < 0)
1865 return (EINVAL);
1866
1867 /* parameters are OK, convert them to the com struct and the device */
1868 s = spltty();
1869 if (odivisor == 0)
1870 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
1871 else
1872 (void)commctl(com, TIOCM_DTR, DMBIS);
1873
1874 /*
1875 * This returns with interrupts disabled so that we can complete
1876 * the speed change atomically.
1877 */
1878 (void) siosetwater(com, t->c_ispeed);
1879
1880 /* XXX we don't actually change the speed atomically. */
1881 enable_intr();
1882
1883 if (idivisor != 0) {
1884 cd_setreg(com, CD1400_RBPR, idivisor);
1885 cd_setreg(com, CD1400_RCOR, iprescaler);
1886 }
1887 if (odivisor != 0) {
1888 cd_setreg(com, CD1400_TBPR, odivisor);
1889 cd_setreg(com, CD1400_TCOR, oprescaler);
1890 }
1891
1892 /*
1893 * channel control
1894 * receiver enable
1895 * transmitter enable (always set)
1896 */
1897 cflag = t->c_cflag;
1898 opt = CD1400_CCR_CMDCHANCTL | CD1400_CCR_XMTEN
1899 | (cflag & CREAD ? CD1400_CCR_RCVEN : CD1400_CCR_RCVDIS);
1900 if (opt != com->channel_control) {
1901 com->channel_control = opt;
1902 cd1400_channel_cmd(com, opt);
1903 }
1904
1905#ifdef Smarts
1906 /* set special chars */
1907 /* XXX if one is _POSIX_VDISABLE, can't use some others */
1908 if (t->c_cc[VSTOP] != _POSIX_VDISABLE)
1909 cd_setreg(com, CD1400_SCHR1, t->c_cc[VSTOP]);
1910 if (t->c_cc[VSTART] != _POSIX_VDISABLE)
1911 cd_setreg(com, CD1400_SCHR2, t->c_cc[VSTART]);
1912 if (t->c_cc[VINTR] != _POSIX_VDISABLE)
1913 cd_setreg(com, CD1400_SCHR3, t->c_cc[VINTR]);
1914 if (t->c_cc[VSUSP] != _POSIX_VDISABLE)
1915 cd_setreg(com, CD1400_SCHR4, t->c_cc[VSUSP]);
1916#endif
1917
1918 /*
1919 * set channel option register 1 -
1920 * parity mode
1921 * stop bits
1922 * char length
1923 */
1924 opt = 0;
1925 /* parity */
1926 if (cflag & PARENB) {
1927 if (cflag & PARODD)
1928 opt |= CD1400_COR1_PARODD;
1929 opt |= CD1400_COR1_PARNORMAL;
1930 }
1931 iflag = t->c_iflag;
1932 if (!(iflag & INPCK))
1933 opt |= CD1400_COR1_NOINPCK;
1934 bits = 1 + 1;
1935 /* stop bits */
1936 if (cflag & CSTOPB) {
1937 ++bits;
1938 opt |= CD1400_COR1_STOP2;
1939 }
1940 /* char length */
1941 switch (cflag & CSIZE) {
1942 case CS5:
1943 bits += 5;
1944 opt |= CD1400_COR1_CS5;
1945 break;
1946 case CS6:
1947 bits += 6;
1948 opt |= CD1400_COR1_CS6;
1949 break;
1950 case CS7:
1951 bits += 7;
1952 opt |= CD1400_COR1_CS7;
1953 break;
1954 default:
1955 bits += 8;
1956 opt |= CD1400_COR1_CS8;
1957 break;
1958 }
1959 cor_change = 0;
1960 if (opt != com->cor[0]) {
1961 cor_change |= CD1400_CCR_COR1;
1962 cd_setreg(com, CD1400_COR1, com->cor[0] = opt);
1963 }
1964
1965 /*
1966 * Set receive time-out period, normally to max(one char time, 5 ms).
1967 */
1968 if (t->c_ispeed == 0)
1969 itimeout = cd_getreg(com, CD1400_RTPR);
1970 else {
1971 itimeout = (1000 * bits + t->c_ispeed - 1) / t->c_ispeed;
1972#ifdef SOFT_HOTCHAR
1973#define MIN_RTP 1
1974#else
1975#define MIN_RTP 5
1976#endif
1977 if (itimeout < MIN_RTP)
1978 itimeout = MIN_RTP;
1979 }
1980 if (!(t->c_lflag & ICANON) && t->c_cc[VMIN] != 0 && t->c_cc[VTIME] != 0
1981 && t->c_cc[VTIME] * 10 > itimeout)
1982 itimeout = t->c_cc[VTIME] * 10;
1983 if (itimeout > 255)
1984 itimeout = 255;
1985 cd_setreg(com, CD1400_RTPR, itimeout);
1986
1987 /*
1988 * set channel option register 2 -
1989 * flow control
1990 */
1991 opt = 0;
1992#ifdef Smarts
1993 if (iflag & IXANY)
1994 opt |= CD1400_COR2_IXANY;
1995 if (iflag & IXOFF)
1996 opt |= CD1400_COR2_IXOFF;
1997#endif
1998#ifndef SOFT_CTS_OFLOW
1999 if (cflag & CCTS_OFLOW)
2000 opt |= CD1400_COR2_CCTS_OFLOW;
2001#endif
2002 disable_intr();
2003 if (opt != com->cor[1]) {
2004 cor_change |= CD1400_CCR_COR2;
2005 cd_setreg(com, CD1400_COR2, com->cor[1] = opt);
2006 }
2007 enable_intr();
2008
2009 /*
2010 * set channel option register 3 -
2011 * receiver FIFO interrupt threshold
2012 * flow control
2013 */
2014 opt = RxFifoThreshold;
2015#ifdef Smarts
2016 if (t->c_lflag & ICANON)
2017 opt |= CD1400_COR3_SCD34; /* detect INTR & SUSP chars */
2018 if (iflag & IXOFF)
2019 /* detect and transparently handle START and STOP chars */
2020 opt |= CD1400_COR3_FCT | CD1400_COR3_SCD12;
2021#endif
2022 if (opt != com->cor[2]) {
2023 cor_change |= CD1400_CCR_COR3;
2024 cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
2025 }
2026
2027 /* notify the CD1400 if COR1-3 have changed */
2028 if (cor_change)
2029 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | cor_change);
2030
2031 /*
2032 * set channel option register 4 -
2033 * CR/NL processing
2034 * break processing
2035 * received exception processing
2036 */
2037 opt = 0;
2038 if (iflag & IGNCR)
2039 opt |= CD1400_COR4_IGNCR;
2040#ifdef Smarts
2041 /*
2042 * we need a new ttyinput() for this, as we don't want to
2043 * have ICRNL && INLCR being done in both layers, or to have
2044 * synchronisation problems
2045 */
2046 if (iflag & ICRNL)
2047 opt |= CD1400_COR4_ICRNL;
2048 if (iflag & INLCR)
2049 opt |= CD1400_COR4_INLCR;
2050#endif
2051 if (iflag & IGNBRK)
2052 opt |= CD1400_COR4_IGNBRK | CD1400_COR4_NOBRKINT;
2053 /*
2054 * The `-ignbrk -brkint parmrk' case is not handled by the hardware,
2055 * so only tell the hardware about -brkint if -parmrk.
2056 */
2057 if (!(iflag & (BRKINT | PARMRK)))
2058 opt |= CD1400_COR4_NOBRKINT;
2059#if 0
2060 /* XXX using this "intelligence" breaks reporting of overruns. */
2061 if (iflag & IGNPAR)
2062 opt |= CD1400_COR4_PFO_DISCARD;
2063 else {
2064 if (iflag & PARMRK)
2065 opt |= CD1400_COR4_PFO_ESC;
2066 else
2067 opt |= CD1400_COR4_PFO_NUL;
2068 }
2069#else
2070 opt |= CD1400_COR4_PFO_EXCEPTION;
2071#endif
2072 cd_setreg(com, CD1400_COR4, opt);
2073
2074 /*
2075 * set channel option register 5 -
2076 */
2077 opt = 0;
2078 if (iflag & ISTRIP)
2079 opt |= CD1400_COR5_ISTRIP;
2080 if (t->c_iflag & IEXTEN)
2081 /* enable LNEXT (e.g. ctrl-v quoting) handling */
2082 opt |= CD1400_COR5_LNEXT;
2083#ifdef Smarts
2084 if (t->c_oflag & ONLCR)
2085 opt |= CD1400_COR5_ONLCR;
2086 if (t->c_oflag & OCRNL)
2087 opt |= CD1400_COR5_OCRNL;
2088#endif
2089 cd_setreg(com, CD1400_COR5, opt);
2090
2091 /*
2092 * We always generate modem status change interrupts for CD changes.
2093 * Among other things, this is necessary to track TS_CARR_ON for
2094 * pstat to print even when the driver doesn't care. CD changes
2095 * should be rare so interrupts for them are not worth extra code to
2096 * avoid. We avoid interrupts for other modem status changes (except
2097 * for CTS changes when SOFT_CTS_OFLOW is configured) since this is
2098 * simplest and best.
2099 */
2100
2101 /*
2102 * set modem change option register 1
2103 * generate modem interrupts on which 1 -> 0 input transitions
2104 * also controls auto-DTR output flow-control, which we don't use
2105 */
2106 opt = CD1400_MCOR1_CDzd;
2107#ifdef SOFT_CTS_OFLOW
2108 if (cflag & CCTS_OFLOW)
2109 opt |= CD1400_MCOR1_CTSzd;
2110#endif
2111 cd_setreg(com, CD1400_MCOR1, opt);
2112
2113 /*
2114 * set modem change option register 2
2115 * generate modem interrupts on specific 0 -> 1 input transitions
2116 */
2117 opt = CD1400_MCOR2_CDod;
2118#ifdef SOFT_CTS_OFLOW
2119 if (cflag & CCTS_OFLOW)
2120 opt |= CD1400_MCOR2_CTSod;
2121#endif
2122 cd_setreg(com, CD1400_MCOR2, opt);
2123
2124 /*
2125 * XXX should have done this long ago, but there is too much state
2126 * to change all atomically.
2127 */
2128 disable_intr();
2129
2130 com->state &= ~CS_TTGO;
2131 if (!(tp->t_state & TS_TTSTOP))
2132 com->state |= CS_TTGO;
2133 if (cflag & CRTS_IFLOW) {
2134 com->state |= CS_RTS_IFLOW;
2135 /*
2136 * If CS_RTS_IFLOW just changed from off to on, the change
2137 * needs to be propagated to MCR_RTS. This isn't urgent,
2138 * so do it later by calling comstart() instead of repeating
2139 * a lot of code from comstart() here.
2140 */
2141 } else if (com->state & CS_RTS_IFLOW) {
2142 com->state &= ~CS_RTS_IFLOW;
2143 /*
2144 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS
2145 * on here, since comstart() won't do it later.
2146 */
2147#if 0
2148 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2149#else
2150 cd_setreg(com, com->mcr_rts_reg,
2151 com->mcr_image |= com->mcr_rts);
2152#endif
2153 }
2154
2155 /*
2156 * Set up state to handle output flow control.
2157 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2158 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2159 */
2160 com->state |= CS_ODEVREADY;
2161#ifdef SOFT_CTS_OFLOW
2162 com->state &= ~CS_CTS_OFLOW;
2163 if (cflag & CCTS_OFLOW) {
2164 com->state |= CS_CTS_OFLOW;
2165 if (!(com->last_modem_status & MSR_CTS))
2166 com->state &= ~CS_ODEVREADY;
2167 }
2168#endif
2169 /* XXX shouldn't call functions while intrs are disabled. */
2170 disc_optim(tp, t, com);
2171#if 0
2172 /*
2173 * Recover from fiddling with CS_TTGO. We used to call siointr1()
2174 * unconditionally, but that defeated the careful discarding of
2175 * stale input in sioopen().
2176 */
2177 if (com->state >= (CS_BUSY | CS_TTGO))
2178 siointr1(com);
2179#endif
2180 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
2181 if (!(com->intr_enable & CD1400_SRER_TXRDY))
2182 cd_setreg(com, CD1400_SRER,
2183 com->intr_enable
2184 = (com->intr_enable & ~CD1400_SRER_TXMPTY)
2185 | CD1400_SRER_TXRDY);
2186 } else {
2187 if (com->intr_enable & CD1400_SRER_TXRDY)
2188 cd_setreg(com, CD1400_SRER,
2189 com->intr_enable
2190 = (com->intr_enable & ~CD1400_SRER_TXRDY)
2191 | CD1400_SRER_TXMPTY);
2192 }
2193
2194 enable_intr();
2195 splx(s);
2196 comstart(tp);
2197 if (com->ibufold != NULL) {
2198 free(com->ibufold, M_DEVBUF);
2199 com->ibufold = NULL;
2200 }
2201 return (0);
2202}
2203
2204static int
2205siosetwater(com, speed)
2206 struct com_s *com;
2207 speed_t speed;
2208{
2209 int cp4ticks;
2210 u_char *ibuf;
2211 int ibufsize;
2212 struct tty *tp;
2213
2214 /*
2215 * Make the buffer size large enough to handle a softtty interrupt
2216 * latency of about 2 ticks without loss of throughput or data
2217 * (about 3 ticks if input flow control is not used or not honoured,
2218 * but a bit less for CS5-CS7 modes).
2219 */
2220 cp4ticks = speed / 10 / hz * 4;
2221 for (ibufsize = 128; ibufsize < cp4ticks;)
2222 ibufsize <<= 1;
2223 if (ibufsize == com->ibufsize) {
2224 disable_intr();
2225 return (0);
2226 }
2227
2228 /*
2229 * Allocate input buffer. The extra factor of 2 in the size is
2230 * to allow for an error byte for each input byte.
2231 */
2232 ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
2233 if (ibuf == NULL) {
2234 disable_intr();
2235 return (ENOMEM);
2236 }
2237
2238 /* Initialize non-critical variables. */
2239 com->ibufold = com->ibuf;
2240 com->ibufsize = ibufsize;
2241 tp = com->tp;
2242 if (tp != NULL) {
2243 tp->t_ififosize = 2 * ibufsize;
2244 tp->t_ispeedwat = (speed_t)-1;
2245 tp->t_ospeedwat = (speed_t)-1;
2246 }
2247
2248 /*
2249 * Read current input buffer, if any. Continue with interrupts
2250 * disabled.
2251 */
2252 disable_intr();
2253 if (com->iptr != com->ibuf)
2254 sioinput(com);
2255
2256 /*-
2257 * Initialize critical variables, including input buffer watermarks.
2258 * The external device is asked to stop sending when the buffer
2259 * exactly reaches high water, or when the high level requests it.
2260 * The high level is notified immediately (rather than at a later
2261 * clock tick) when this watermark is reached.
2262 * The buffer size is chosen so the watermark should almost never
2263 * be reached.
2264 * The low watermark is invisibly 0 since the buffer is always
2265 * emptied all at once.
2266 */
2267 com->iptr = com->ibuf = ibuf;
2268 com->ibufend = ibuf + ibufsize;
2269 com->ierroff = ibufsize;
2270 com->ihighwater = ibuf + 3 * ibufsize / 4;
2271 return (0);
2272}
2273
2274static void
2275comstart(tp)
2276 struct tty *tp;
2277{
2278 struct com_s *com;
2279 int s;
2280#ifdef CyDebug
2281 bool_t started;
2282#endif
2283 int unit;
2284
2285 unit = DEV_TO_UNIT(tp->t_dev);
2286 com = com_addr(unit);
2287 s = spltty();
2288
2289#ifdef CyDebug
2290 ++com->start_count;
2291 started = FALSE;
2292#endif
2293
2294 disable_intr();
2295 if (tp->t_state & TS_TTSTOP) {
2296 com->state &= ~CS_TTGO;
2297 if (com->intr_enable & CD1400_SRER_TXRDY)
2298 cd_setreg(com, CD1400_SRER,
2299 com->intr_enable
2300 = (com->intr_enable & ~CD1400_SRER_TXRDY)
2301 | CD1400_SRER_TXMPTY);
2302 } else {
2303 com->state |= CS_TTGO;
2304 if (com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)
2305 && !(com->intr_enable & CD1400_SRER_TXRDY))
2306 cd_setreg(com, CD1400_SRER,
2307 com->intr_enable
2308 = (com->intr_enable & ~CD1400_SRER_TXMPTY)
2309 | CD1400_SRER_TXRDY);
2310 }
2311 if (tp->t_state & TS_TBLOCK) {
2312 if (com->mcr_image & com->mcr_rts && com->state & CS_RTS_IFLOW)
2313#if 0
2314 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2315#else
2316 cd_setreg(com, com->mcr_rts_reg,
2317 com->mcr_image &= ~com->mcr_rts);
2318#endif
2319 } else {
2320 if (!(com->mcr_image & com->mcr_rts)
2321 && com->iptr < com->ihighwater
2322 && com->state & CS_RTS_IFLOW)
2323#if 0
2324 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2325#else
2326 cd_setreg(com, com->mcr_rts_reg,
2327 com->mcr_image |= com->mcr_rts);
2328#endif
2329 }
2330 enable_intr();
2331 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2332 ttwwakeup(tp);
2333 splx(s);
2334 return;
2335 }
2336 if (tp->t_outq.c_cc != 0) {
2337 struct lbq *qp;
2338 struct lbq *next;
2339
2340 if (!com->obufs[0].l_queued) {
2341#ifdef CyDebug
2342 started = TRUE;
2343#endif
2344 com->obufs[0].l_tail
2345 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2346 sizeof com->obuf1);
2347 com->obufs[0].l_next = NULL;
2348 com->obufs[0].l_queued = TRUE;
2349 disable_intr();
2350 if (com->state & CS_BUSY) {
2351 qp = com->obufq.l_next;
2352 while ((next = qp->l_next) != NULL)
2353 qp = next;
2354 qp->l_next = &com->obufs[0];
2355 } else {
2356 com->obufq.l_head = com->obufs[0].l_head;
2357 com->obufq.l_tail = com->obufs[0].l_tail;
2358 com->obufq.l_next = &com->obufs[0];
2359 com->state |= CS_BUSY;
2360 if (com->state >= (CS_BUSY | CS_TTGO
2361 | CS_ODEVREADY))
2362 cd_setreg(com, CD1400_SRER,
2363 com->intr_enable
2364 = (com->intr_enable
2365 & ~CD1400_SRER_TXMPTY)
2366 | CD1400_SRER_TXRDY);
2367 }
2368 enable_intr();
2369 }
2370 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2371#ifdef CyDebug
2372 started = TRUE;
2373#endif
2374 com->obufs[1].l_tail
2375 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2376 sizeof com->obuf2);
2377 com->obufs[1].l_next = NULL;
2378 com->obufs[1].l_queued = TRUE;
2379 disable_intr();
2380 if (com->state & CS_BUSY) {
2381 qp = com->obufq.l_next;
2382 while ((next = qp->l_next) != NULL)
2383 qp = next;
2384 qp->l_next = &com->obufs[1];
2385 } else {
2386 com->obufq.l_head = com->obufs[1].l_head;
2387 com->obufq.l_tail = com->obufs[1].l_tail;
2388 com->obufq.l_next = &com->obufs[1];
2389 com->state |= CS_BUSY;
2390 if (com->state >= (CS_BUSY | CS_TTGO
2391 | CS_ODEVREADY))
2392 cd_setreg(com, CD1400_SRER,
2393 com->intr_enable
2394 = (com->intr_enable
2395 & ~CD1400_SRER_TXMPTY)
2396 | CD1400_SRER_TXRDY);
2397 }
2398 enable_intr();
2399 }
2400 tp->t_state |= TS_BUSY;
2401 }
2402#ifdef CyDebug
2403 if (started)
2404 ++com->start_real;
2405#endif
2406#if 0
2407 disable_intr();
2408 if (com->state >= (CS_BUSY | CS_TTGO))
2409 siointr1(com); /* fake interrupt to start output */
2410 enable_intr();
2411#endif
2412 ttwwakeup(tp);
2413 splx(s);
2414}
2415
2416static void
2417siostop(tp, rw)
2417comstop(tp, rw)
2418 struct tty *tp;
2419 int rw;
2420{
2421 struct com_s *com;
2422 bool_t wakeup_etc;
2423
2424 com = com_addr(DEV_TO_UNIT(tp->t_dev));
2425 wakeup_etc = FALSE;
2426 disable_intr();
2427 if (rw & FWRITE) {
2428 com->obufs[0].l_queued = FALSE;
2429 com->obufs[1].l_queued = FALSE;
2430 if (com->extra_state & CSE_ODONE) {
2431 com_events -= LOTS_OF_EVENTS;
2432 com->extra_state &= ~CSE_ODONE;
2433 if (com->etc != ETC_NONE) {
2434 if (com->etc == ETC_BREAK_ENDED)
2435 com->etc = ETC_NONE;
2436 wakeup_etc = TRUE;
2437 }
2438 }
2439 com->tp->t_state &= ~TS_BUSY;
2440 if (com->state & CS_ODONE)
2441 com_events -= LOTS_OF_EVENTS;
2442 com->state &= ~(CS_ODONE | CS_BUSY);
2443 }
2444 if (rw & FREAD) {
2445 /* XXX no way to reset only input fifo. */
2446 com_events -= (com->iptr - com->ibuf);
2447 com->iptr = com->ibuf;
2448 }
2449 enable_intr();
2450 if (wakeup_etc)
2451 wakeup(&com->etc);
2452 if (rw & FWRITE && com->etc == ETC_NONE)
2453 cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
2454 comstart(tp);
2455}
2456
2418 struct tty *tp;
2419 int rw;
2420{
2421 struct com_s *com;
2422 bool_t wakeup_etc;
2423
2424 com = com_addr(DEV_TO_UNIT(tp->t_dev));
2425 wakeup_etc = FALSE;
2426 disable_intr();
2427 if (rw & FWRITE) {
2428 com->obufs[0].l_queued = FALSE;
2429 com->obufs[1].l_queued = FALSE;
2430 if (com->extra_state & CSE_ODONE) {
2431 com_events -= LOTS_OF_EVENTS;
2432 com->extra_state &= ~CSE_ODONE;
2433 if (com->etc != ETC_NONE) {
2434 if (com->etc == ETC_BREAK_ENDED)
2435 com->etc = ETC_NONE;
2436 wakeup_etc = TRUE;
2437 }
2438 }
2439 com->tp->t_state &= ~TS_BUSY;
2440 if (com->state & CS_ODONE)
2441 com_events -= LOTS_OF_EVENTS;
2442 com->state &= ~(CS_ODONE | CS_BUSY);
2443 }
2444 if (rw & FREAD) {
2445 /* XXX no way to reset only input fifo. */
2446 com_events -= (com->iptr - com->ibuf);
2447 com->iptr = com->ibuf;
2448 }
2449 enable_intr();
2450 if (wakeup_etc)
2451 wakeup(&com->etc);
2452 if (rw & FWRITE && com->etc == ETC_NONE)
2453 cd1400_channel_cmd(com, CD1400_CCR_CMDRESET | CD1400_CCR_FTF);
2454 comstart(tp);
2455}
2456
2457static struct tty *
2458siodevtotty(dev)
2459 dev_t dev;
2460{
2461 int mynor;
2462 int unit;
2463
2464 mynor = minor(dev);
2465 if (mynor & CONTROL_MASK)
2466 return (NULL);
2467 unit = MINOR_TO_UNIT(mynor);
2468 if ((u_int) unit >= NSIO)
2469 return (NULL);
2470 return (&sio_tty[unit]);
2471}
2472
2473static int
2474commctl(com, bits, how)
2475 struct com_s *com;
2476 int bits;
2477 int how;
2478{
2479 int mcr;
2480 int msr;
2481
2482 if (how == DMGET) {
2483 if (com->channel_control & CD1400_CCR_RCVEN)
2484 bits |= TIOCM_LE;
2485 mcr = com->mcr_image;
2486 if (mcr & com->mcr_dtr)
2487 bits |= TIOCM_DTR;
2488 if (mcr & com->mcr_rts)
2489 /* XXX wired on for Cyclom-8Ys */
2490 bits |= TIOCM_RTS;
2491
2492 /*
2493 * We must read the modem status from the hardware because
2494 * we don't generate modem status change interrupts for all
2495 * changes, so com->prev_modem_status is not guaranteed to
2496 * be up to date. This is safe, unlike for sio, because
2497 * reading the status register doesn't clear pending modem
2498 * status change interrupts.
2499 */
2500 msr = cd_getreg(com, CD1400_MSVR2);
2501
2502 if (msr & MSR_CTS)
2503 bits |= TIOCM_CTS;
2504 if (msr & MSR_DCD)
2505 bits |= TIOCM_CD;
2506 if (msr & MSR_DSR)
2507 bits |= TIOCM_DSR;
2508 if (msr & MSR_RI)
2509 /* XXX not connected except for Cyclom-16Y? */
2510 bits |= TIOCM_RI;
2511 return (bits);
2512 }
2513 mcr = 0;
2514 if (bits & TIOCM_DTR)
2515 mcr |= com->mcr_dtr;
2516 if (bits & TIOCM_RTS)
2517 mcr |= com->mcr_rts;
2518 disable_intr();
2519 switch (how) {
2520 case DMSET:
2521 com->mcr_image = mcr;
2522 cd_setreg(com, CD1400_MSVR1, mcr);
2523 cd_setreg(com, CD1400_MSVR2, mcr);
2524 break;
2525 case DMBIS:
2526 com->mcr_image = mcr = com->mcr_image | mcr;
2527 cd_setreg(com, CD1400_MSVR1, mcr);
2528 cd_setreg(com, CD1400_MSVR2, mcr);
2529 break;
2530 case DMBIC:
2531 com->mcr_image = mcr = com->mcr_image & ~mcr;
2532 cd_setreg(com, CD1400_MSVR1, mcr);
2533 cd_setreg(com, CD1400_MSVR2, mcr);
2534 break;
2535 }
2536 enable_intr();
2537 return (0);
2538}
2539
2540static void
2541siosettimeout()
2542{
2543 struct com_s *com;
2544 bool_t someopen;
2545 int unit;
2546
2547 /*
2548 * Set our timeout period to 1 second if no polled devices are open.
2549 * Otherwise set it to max(1/200, 1/hz).
2550 * Enable timeouts iff some device is open.
2551 */
2552 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2553 sio_timeout = hz;
2554 someopen = FALSE;
2555 for (unit = 0; unit < NSIO; ++unit) {
2556 com = com_addr(unit);
2557 if (com != NULL && com->tp != NULL
2558 && com->tp->t_state & TS_ISOPEN) {
2559 someopen = TRUE;
2560#if 0
2561 if (com->poll || com->poll_output) {
2562 sio_timeout = hz > 200 ? hz / 200 : 1;
2563 break;
2564 }
2565#endif
2566 }
2567 }
2568 if (someopen) {
2569 sio_timeouts_until_log = hz / sio_timeout;
2570 sio_timeout_handle = timeout(comwakeup, (void *)NULL,
2571 sio_timeout);
2572 } else {
2573 /* Flush error messages, if any. */
2574 sio_timeouts_until_log = 1;
2575 comwakeup((void *)NULL);
2576 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2577 }
2578}
2579
2580static void
2581comwakeup(chan)
2582 void *chan;
2583{
2584 struct com_s *com;
2585 int unit;
2586
2587 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
2588
2589#if 0
2590 /*
2591 * Recover from lost output interrupts.
2592 * Poll any lines that don't use interrupts.
2593 */
2594 for (unit = 0; unit < NSIO; ++unit) {
2595 com = com_addr(unit);
2596 if (com != NULL
2597 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2598 disable_intr();
2599 siointr1(com);
2600 enable_intr();
2601 }
2602 }
2603#endif
2604
2605 /*
2606 * Check for and log errors, but not too often.
2607 */
2608 if (--sio_timeouts_until_log > 0)
2609 return;
2610 sio_timeouts_until_log = hz / sio_timeout;
2611 for (unit = 0; unit < NSIO; ++unit) {
2612 int errnum;
2613
2614 com = com_addr(unit);
2615 if (com == NULL)
2616 continue;
2617 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2618 u_int delta;
2619 u_long total;
2620
2621 disable_intr();
2622 delta = com->delta_error_counts[errnum];
2623 com->delta_error_counts[errnum] = 0;
2624 enable_intr();
2625 if (delta == 0)
2626 continue;
2627 total = com->error_counts[errnum] += delta;
2628 log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
2629 unit, delta, error_desc[errnum],
2630 delta == 1 ? "" : "s", total);
2631 }
2632 }
2633}
2634
2635static void
2636disc_optim(tp, t, com)
2637 struct tty *tp;
2638 struct termios *t;
2639 struct com_s *com;
2640{
2641#ifndef SOFT_HOTCHAR
2642 u_char opt;
2643#endif
2644
2645 /*
2646 * XXX can skip a lot more cases if Smarts. Maybe
2647 * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we
2648 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2649 */
2650 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2651 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2652 && (!(t->c_iflag & PARMRK)
2653 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2654 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2655 && linesw[tp->t_line].l_rint == ttyinput)
2656 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2657 else
2658 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2659 com->hotchar = linesw[tp->t_line].l_hotchar;
2660#ifndef SOFT_HOTCHAR
2661 opt = com->cor[2] & ~CD1400_COR3_SCD34;
2662 if (com->hotchar != 0) {
2663 cd_setreg(com, CD1400_SCHR3, com->hotchar);
2664 cd_setreg(com, CD1400_SCHR4, com->hotchar);
2665 opt |= CD1400_COR3_SCD34;
2666 }
2667 if (opt != com->cor[2]) {
2668 cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
2669 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
2670 }
2671#endif
2672}
2673
2674#ifdef Smarts
2675/* standard line discipline input routine */
2676int
2677cyinput(c, tp)
2678 int c;
2679 struct tty *tp;
2680{
2681 /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
2682 * bits, as they are done by the CD1400. Hardly worth the effort,
2683 * given that high-throughput sessions are raw anyhow.
2684 */
2685}
2686#endif /* Smarts */
2687
2688static int
2689comspeed(speed, cy_clock, prescaler_io)
2690 speed_t speed;
2691 u_long cy_clock;
2692 int *prescaler_io;
2693{
2694 int actual;
2695 int error;
2696 int divider;
2697 int prescaler;
2698 int prescaler_unit;
2699
2700 if (speed == 0)
2701 return (0);
2702 if (speed < 0 || speed > 150000)
2703 return (-1);
2704
2705 /* determine which prescaler to use */
2706 for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
2707 prescaler_unit--, prescaler >>= 2) {
2708 if (cy_clock / prescaler / speed > 63)
2709 break;
2710 }
2711
2712 divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */
2713 if (divider > 255)
2714 divider = 255;
2715 actual = cy_clock/prescaler/divider;
2716
2717 /* 10 times error in percent: */
2718 error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2;
2719
2720 /* 3.0% max error tolerance */
2721 if (error < -30 || error > 30)
2722 return (-1);
2723
2724#if 0
2725 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
2726 printf("divider = %d (%x)\n", divider, divider);
2727 printf("actual = %d\n", actual);
2728 printf("error = %d\n", error);
2729#endif
2730
2731 *prescaler_io = prescaler_unit;
2732 return (divider);
2733}
2734
2735static void
2736cd1400_channel_cmd(com, cmd)
2737 struct com_s *com;
2738 int cmd;
2739{
2740 cd1400_channel_cmd_wait(com);
2741 cd_setreg(com, CD1400_CCR, cmd);
2742 cd1400_channel_cmd_wait(com);
2743}
2744
2745static void
2746cd1400_channel_cmd_wait(com)
2747 struct com_s *com;
2748{
2749 struct timeval start;
2750 struct timeval tv;
2751 long usec;
2752
2753 if (cd_getreg(com, CD1400_CCR) == 0)
2754 return;
2755 microtime(&start);
2756 for (;;) {
2757 if (cd_getreg(com, CD1400_CCR) == 0)
2758 return;
2759 microtime(&tv);
2760 usec = 1000000 * (tv.tv_sec - start.tv_sec) +
2761 tv.tv_usec - start.tv_usec;
2762 if (usec >= 5000) {
2763 log(LOG_ERR,
2764 "cy%d: channel command timeout (%ld usec)\n",
2765 com->unit, usec);
2766 return;
2767 }
2768 }
2769}
2770
2771static void
2772cd_etc(com, etc)
2773 struct com_s *com;
2774 int etc;
2775{
2776 /*
2777 * We can't change the hardware's ETC state while there are any
2778 * characters in the tx fifo, since those characters would be
2779 * interpreted as commands! Unputting characters from the fifo
2780 * is difficult, so we wait up to 12 character times for the fifo
2781 * to drain. The command will be delayed for up to 2 character
2782 * times for the tx to become empty. Unputting characters from
2783 * the tx holding and shift registers is impossible, so we wait
2784 * for the tx to become empty so that the command is sure to be
2785 * executed soon after we issue it.
2786 */
2787 disable_intr();
2788 if (com->etc == etc) {
2789 enable_intr();
2790 goto wait;
2791 }
2792 if ((etc == CD1400_ETC_SENDBREAK
2793 && (com->etc == ETC_BREAK_STARTING
2794 || com->etc == ETC_BREAK_STARTED))
2795 || (etc == CD1400_ETC_STOPBREAK
2796 && (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED
2797 || com->etc == ETC_NONE))) {
2798 enable_intr();
2799 return;
2800 }
2801 com->etc = etc;
2802 cd_setreg(com, CD1400_SRER,
2803 com->intr_enable
2804 = (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY);
2805 enable_intr();
2806wait:
2807 while (com->etc == etc
2808 && tsleep(&com->etc, TTIPRI | PCATCH, "cyetc", 0) == 0)
2809 continue;
2810}
2811
2812static int
2813cd_getreg(com, reg)
2814 struct com_s *com;
2815 int reg;
2816{
2817 struct com_s *basecom;
2818 u_char car;
2819 int cy_align;
2820 u_long ef;
2821 cy_addr iobase;
2822 int val;
2823
2824 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
2825 car = com->unit & CD1400_CAR_CHAN;
2826 cy_align = com->cy_align;
2827 iobase = com->iobase;
2828 ef = read_eflags();
2829 if (ef & PSL_I)
2830 disable_intr();
2831 if (basecom->car != car)
2832 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
2833 val = cd_inb(iobase, reg, cy_align);
2834 if (ef & PSL_I)
2835 enable_intr();
2836 return (val);
2837}
2838
2839static void
2840cd_setreg(com, reg, val)
2841 struct com_s *com;
2842 int reg;
2843 int val;
2844{
2845 struct com_s *basecom;
2846 u_char car;
2847 int cy_align;
2848 u_long ef;
2849 cy_addr iobase;
2850
2851 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
2852 car = com->unit & CD1400_CAR_CHAN;
2853 cy_align = com->cy_align;
2854 iobase = com->iobase;
2855 ef = read_eflags();
2856 if (ef & PSL_I)
2857 disable_intr();
2858 if (basecom->car != car)
2859 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
2860 cd_outb(iobase, reg, cy_align, val);
2861 if (ef & PSL_I)
2862 enable_intr();
2863}
2864
2865#ifdef CyDebug
2866/* useful in ddb */
2867void
2868cystatus(unit)
2869 int unit;
2870{
2871 struct com_s *com;
2872 cy_addr iobase;
2873 u_int ocount;
2874 struct tty *tp;
2875
2876 com = com_addr(unit);
2877 printf("info for channel %d\n", unit);
2878 printf("------------------\n");
2879 printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
2880 printf("calls to upper layer:\t\t%d\n", cy_timeouts);
2881 if (com == NULL)
2882 return;
2883 iobase = com->iobase;
2884 printf("\n");
2885 printf("cd1400 base address:\\tt%p\n", iobase);
2886 printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
2887 printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
2888 com->cor[0], com->cor[1], com->cor[2]);
2889 printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
2890 cd_getreg(com, CD1400_SRER), com->intr_enable);
2891 printf("service request register:\t0x%02x\n",
2892 cd_inb(iobase, CD1400_SVRR, com->cy_align));
2893 printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
2894 cd_getreg(com, CD1400_MSVR2), com->prev_modem_status);
2895 printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
2896 cd_inb(iobase, CD1400_RIR, com->cy_align),
2897 cd_inb(iobase, CD1400_TIR, com->cy_align),
2898 cd_inb(iobase, CD1400_MIR, com->cy_align));
2899 printf("\n");
2900 printf("com state:\t\t\t0x%02x\n", com->state);
2901 printf("calls to comstart():\t\t%d (%d useful)\n",
2902 com->start_count, com->start_real);
2903 printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
2904 ocount = 0;
2905 if (com->obufs[0].l_queued)
2906 ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
2907 if (com->obufs[1].l_queued)
2908 ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
2909 printf("tx buffer chars:\t\t%u\n", ocount);
2910 printf("received chars:\t\t\t%d\n", com->bytes_in);
2911 printf("received exceptions:\t\t%d\n", com->recv_exception);
2912 printf("modem signal deltas:\t\t%d\n", com->mdm);
2913 printf("transmitted chars:\t\t%d\n", com->bytes_out);
2914 printf("\n");
2915 tp = com->tp;
2916 if (tp != NULL) {
2917 printf("tty state:\t\t\t0x%08x\n", tp->t_state);
2918 printf(
2919 "upper layer queue lengths:\t%d raw, %d canon, %d output\n",
2920 tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
2921 } else
2922 printf("tty state:\t\t\tclosed\n");
2923}
2924#endif /* CyDebug */
2457static int
2458commctl(com, bits, how)
2459 struct com_s *com;
2460 int bits;
2461 int how;
2462{
2463 int mcr;
2464 int msr;
2465
2466 if (how == DMGET) {
2467 if (com->channel_control & CD1400_CCR_RCVEN)
2468 bits |= TIOCM_LE;
2469 mcr = com->mcr_image;
2470 if (mcr & com->mcr_dtr)
2471 bits |= TIOCM_DTR;
2472 if (mcr & com->mcr_rts)
2473 /* XXX wired on for Cyclom-8Ys */
2474 bits |= TIOCM_RTS;
2475
2476 /*
2477 * We must read the modem status from the hardware because
2478 * we don't generate modem status change interrupts for all
2479 * changes, so com->prev_modem_status is not guaranteed to
2480 * be up to date. This is safe, unlike for sio, because
2481 * reading the status register doesn't clear pending modem
2482 * status change interrupts.
2483 */
2484 msr = cd_getreg(com, CD1400_MSVR2);
2485
2486 if (msr & MSR_CTS)
2487 bits |= TIOCM_CTS;
2488 if (msr & MSR_DCD)
2489 bits |= TIOCM_CD;
2490 if (msr & MSR_DSR)
2491 bits |= TIOCM_DSR;
2492 if (msr & MSR_RI)
2493 /* XXX not connected except for Cyclom-16Y? */
2494 bits |= TIOCM_RI;
2495 return (bits);
2496 }
2497 mcr = 0;
2498 if (bits & TIOCM_DTR)
2499 mcr |= com->mcr_dtr;
2500 if (bits & TIOCM_RTS)
2501 mcr |= com->mcr_rts;
2502 disable_intr();
2503 switch (how) {
2504 case DMSET:
2505 com->mcr_image = mcr;
2506 cd_setreg(com, CD1400_MSVR1, mcr);
2507 cd_setreg(com, CD1400_MSVR2, mcr);
2508 break;
2509 case DMBIS:
2510 com->mcr_image = mcr = com->mcr_image | mcr;
2511 cd_setreg(com, CD1400_MSVR1, mcr);
2512 cd_setreg(com, CD1400_MSVR2, mcr);
2513 break;
2514 case DMBIC:
2515 com->mcr_image = mcr = com->mcr_image & ~mcr;
2516 cd_setreg(com, CD1400_MSVR1, mcr);
2517 cd_setreg(com, CD1400_MSVR2, mcr);
2518 break;
2519 }
2520 enable_intr();
2521 return (0);
2522}
2523
2524static void
2525siosettimeout()
2526{
2527 struct com_s *com;
2528 bool_t someopen;
2529 int unit;
2530
2531 /*
2532 * Set our timeout period to 1 second if no polled devices are open.
2533 * Otherwise set it to max(1/200, 1/hz).
2534 * Enable timeouts iff some device is open.
2535 */
2536 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2537 sio_timeout = hz;
2538 someopen = FALSE;
2539 for (unit = 0; unit < NSIO; ++unit) {
2540 com = com_addr(unit);
2541 if (com != NULL && com->tp != NULL
2542 && com->tp->t_state & TS_ISOPEN) {
2543 someopen = TRUE;
2544#if 0
2545 if (com->poll || com->poll_output) {
2546 sio_timeout = hz > 200 ? hz / 200 : 1;
2547 break;
2548 }
2549#endif
2550 }
2551 }
2552 if (someopen) {
2553 sio_timeouts_until_log = hz / sio_timeout;
2554 sio_timeout_handle = timeout(comwakeup, (void *)NULL,
2555 sio_timeout);
2556 } else {
2557 /* Flush error messages, if any. */
2558 sio_timeouts_until_log = 1;
2559 comwakeup((void *)NULL);
2560 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2561 }
2562}
2563
2564static void
2565comwakeup(chan)
2566 void *chan;
2567{
2568 struct com_s *com;
2569 int unit;
2570
2571 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
2572
2573#if 0
2574 /*
2575 * Recover from lost output interrupts.
2576 * Poll any lines that don't use interrupts.
2577 */
2578 for (unit = 0; unit < NSIO; ++unit) {
2579 com = com_addr(unit);
2580 if (com != NULL
2581 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2582 disable_intr();
2583 siointr1(com);
2584 enable_intr();
2585 }
2586 }
2587#endif
2588
2589 /*
2590 * Check for and log errors, but not too often.
2591 */
2592 if (--sio_timeouts_until_log > 0)
2593 return;
2594 sio_timeouts_until_log = hz / sio_timeout;
2595 for (unit = 0; unit < NSIO; ++unit) {
2596 int errnum;
2597
2598 com = com_addr(unit);
2599 if (com == NULL)
2600 continue;
2601 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2602 u_int delta;
2603 u_long total;
2604
2605 disable_intr();
2606 delta = com->delta_error_counts[errnum];
2607 com->delta_error_counts[errnum] = 0;
2608 enable_intr();
2609 if (delta == 0)
2610 continue;
2611 total = com->error_counts[errnum] += delta;
2612 log(LOG_ERR, "cy%d: %u more %s%s (total %lu)\n",
2613 unit, delta, error_desc[errnum],
2614 delta == 1 ? "" : "s", total);
2615 }
2616 }
2617}
2618
2619static void
2620disc_optim(tp, t, com)
2621 struct tty *tp;
2622 struct termios *t;
2623 struct com_s *com;
2624{
2625#ifndef SOFT_HOTCHAR
2626 u_char opt;
2627#endif
2628
2629 /*
2630 * XXX can skip a lot more cases if Smarts. Maybe
2631 * (IGNCR | ISTRIP | IXON) in c_iflag. But perhaps we
2632 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
2633 */
2634 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2635 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2636 && (!(t->c_iflag & PARMRK)
2637 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2638 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2639 && linesw[tp->t_line].l_rint == ttyinput)
2640 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2641 else
2642 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2643 com->hotchar = linesw[tp->t_line].l_hotchar;
2644#ifndef SOFT_HOTCHAR
2645 opt = com->cor[2] & ~CD1400_COR3_SCD34;
2646 if (com->hotchar != 0) {
2647 cd_setreg(com, CD1400_SCHR3, com->hotchar);
2648 cd_setreg(com, CD1400_SCHR4, com->hotchar);
2649 opt |= CD1400_COR3_SCD34;
2650 }
2651 if (opt != com->cor[2]) {
2652 cd_setreg(com, CD1400_COR3, com->cor[2] = opt);
2653 cd1400_channel_cmd(com, CD1400_CCR_CMDCORCHG | CD1400_CCR_COR3);
2654 }
2655#endif
2656}
2657
2658#ifdef Smarts
2659/* standard line discipline input routine */
2660int
2661cyinput(c, tp)
2662 int c;
2663 struct tty *tp;
2664{
2665 /* XXX duplicate ttyinput(), but without the IXOFF/IXON/ISTRIP/IPARMRK
2666 * bits, as they are done by the CD1400. Hardly worth the effort,
2667 * given that high-throughput sessions are raw anyhow.
2668 */
2669}
2670#endif /* Smarts */
2671
2672static int
2673comspeed(speed, cy_clock, prescaler_io)
2674 speed_t speed;
2675 u_long cy_clock;
2676 int *prescaler_io;
2677{
2678 int actual;
2679 int error;
2680 int divider;
2681 int prescaler;
2682 int prescaler_unit;
2683
2684 if (speed == 0)
2685 return (0);
2686 if (speed < 0 || speed > 150000)
2687 return (-1);
2688
2689 /* determine which prescaler to use */
2690 for (prescaler_unit = 4, prescaler = 2048; prescaler_unit;
2691 prescaler_unit--, prescaler >>= 2) {
2692 if (cy_clock / prescaler / speed > 63)
2693 break;
2694 }
2695
2696 divider = (cy_clock / prescaler * 2 / speed + 1) / 2; /* round off */
2697 if (divider > 255)
2698 divider = 255;
2699 actual = cy_clock/prescaler/divider;
2700
2701 /* 10 times error in percent: */
2702 error = ((actual - (long)speed) * 2000 / (long)speed + 1) / 2;
2703
2704 /* 3.0% max error tolerance */
2705 if (error < -30 || error > 30)
2706 return (-1);
2707
2708#if 0
2709 printf("prescaler = %d (%d)\n", prescaler, prescaler_unit);
2710 printf("divider = %d (%x)\n", divider, divider);
2711 printf("actual = %d\n", actual);
2712 printf("error = %d\n", error);
2713#endif
2714
2715 *prescaler_io = prescaler_unit;
2716 return (divider);
2717}
2718
2719static void
2720cd1400_channel_cmd(com, cmd)
2721 struct com_s *com;
2722 int cmd;
2723{
2724 cd1400_channel_cmd_wait(com);
2725 cd_setreg(com, CD1400_CCR, cmd);
2726 cd1400_channel_cmd_wait(com);
2727}
2728
2729static void
2730cd1400_channel_cmd_wait(com)
2731 struct com_s *com;
2732{
2733 struct timeval start;
2734 struct timeval tv;
2735 long usec;
2736
2737 if (cd_getreg(com, CD1400_CCR) == 0)
2738 return;
2739 microtime(&start);
2740 for (;;) {
2741 if (cd_getreg(com, CD1400_CCR) == 0)
2742 return;
2743 microtime(&tv);
2744 usec = 1000000 * (tv.tv_sec - start.tv_sec) +
2745 tv.tv_usec - start.tv_usec;
2746 if (usec >= 5000) {
2747 log(LOG_ERR,
2748 "cy%d: channel command timeout (%ld usec)\n",
2749 com->unit, usec);
2750 return;
2751 }
2752 }
2753}
2754
2755static void
2756cd_etc(com, etc)
2757 struct com_s *com;
2758 int etc;
2759{
2760 /*
2761 * We can't change the hardware's ETC state while there are any
2762 * characters in the tx fifo, since those characters would be
2763 * interpreted as commands! Unputting characters from the fifo
2764 * is difficult, so we wait up to 12 character times for the fifo
2765 * to drain. The command will be delayed for up to 2 character
2766 * times for the tx to become empty. Unputting characters from
2767 * the tx holding and shift registers is impossible, so we wait
2768 * for the tx to become empty so that the command is sure to be
2769 * executed soon after we issue it.
2770 */
2771 disable_intr();
2772 if (com->etc == etc) {
2773 enable_intr();
2774 goto wait;
2775 }
2776 if ((etc == CD1400_ETC_SENDBREAK
2777 && (com->etc == ETC_BREAK_STARTING
2778 || com->etc == ETC_BREAK_STARTED))
2779 || (etc == CD1400_ETC_STOPBREAK
2780 && (com->etc == ETC_BREAK_ENDING || com->etc == ETC_BREAK_ENDED
2781 || com->etc == ETC_NONE))) {
2782 enable_intr();
2783 return;
2784 }
2785 com->etc = etc;
2786 cd_setreg(com, CD1400_SRER,
2787 com->intr_enable
2788 = (com->intr_enable & ~CD1400_SRER_TXRDY) | CD1400_SRER_TXMPTY);
2789 enable_intr();
2790wait:
2791 while (com->etc == etc
2792 && tsleep(&com->etc, TTIPRI | PCATCH, "cyetc", 0) == 0)
2793 continue;
2794}
2795
2796static int
2797cd_getreg(com, reg)
2798 struct com_s *com;
2799 int reg;
2800{
2801 struct com_s *basecom;
2802 u_char car;
2803 int cy_align;
2804 u_long ef;
2805 cy_addr iobase;
2806 int val;
2807
2808 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
2809 car = com->unit & CD1400_CAR_CHAN;
2810 cy_align = com->cy_align;
2811 iobase = com->iobase;
2812 ef = read_eflags();
2813 if (ef & PSL_I)
2814 disable_intr();
2815 if (basecom->car != car)
2816 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
2817 val = cd_inb(iobase, reg, cy_align);
2818 if (ef & PSL_I)
2819 enable_intr();
2820 return (val);
2821}
2822
2823static void
2824cd_setreg(com, reg, val)
2825 struct com_s *com;
2826 int reg;
2827 int val;
2828{
2829 struct com_s *basecom;
2830 u_char car;
2831 int cy_align;
2832 u_long ef;
2833 cy_addr iobase;
2834
2835 basecom = com_addr(com->unit & ~(CD1400_NO_OF_CHANNELS - 1));
2836 car = com->unit & CD1400_CAR_CHAN;
2837 cy_align = com->cy_align;
2838 iobase = com->iobase;
2839 ef = read_eflags();
2840 if (ef & PSL_I)
2841 disable_intr();
2842 if (basecom->car != car)
2843 cd_outb(iobase, CD1400_CAR, cy_align, basecom->car = car);
2844 cd_outb(iobase, reg, cy_align, val);
2845 if (ef & PSL_I)
2846 enable_intr();
2847}
2848
2849#ifdef CyDebug
2850/* useful in ddb */
2851void
2852cystatus(unit)
2853 int unit;
2854{
2855 struct com_s *com;
2856 cy_addr iobase;
2857 u_int ocount;
2858 struct tty *tp;
2859
2860 com = com_addr(unit);
2861 printf("info for channel %d\n", unit);
2862 printf("------------------\n");
2863 printf("total cyclom service probes:\t%d\n", cy_svrr_probes);
2864 printf("calls to upper layer:\t\t%d\n", cy_timeouts);
2865 if (com == NULL)
2866 return;
2867 iobase = com->iobase;
2868 printf("\n");
2869 printf("cd1400 base address:\\tt%p\n", iobase);
2870 printf("saved channel_control:\t\t0x%02x\n", com->channel_control);
2871 printf("saved cor1-3:\t\t\t0x%02x 0x%02x 0x%02x\n",
2872 com->cor[0], com->cor[1], com->cor[2]);
2873 printf("service request enable reg:\t0x%02x (0x%02x cached)\n",
2874 cd_getreg(com, CD1400_SRER), com->intr_enable);
2875 printf("service request register:\t0x%02x\n",
2876 cd_inb(iobase, CD1400_SVRR, com->cy_align));
2877 printf("modem status:\t\t\t0x%02x (0x%02x cached)\n",
2878 cd_getreg(com, CD1400_MSVR2), com->prev_modem_status);
2879 printf("rx/tx/mdm interrupt registers:\t0x%02x 0x%02x 0x%02x\n",
2880 cd_inb(iobase, CD1400_RIR, com->cy_align),
2881 cd_inb(iobase, CD1400_TIR, com->cy_align),
2882 cd_inb(iobase, CD1400_MIR, com->cy_align));
2883 printf("\n");
2884 printf("com state:\t\t\t0x%02x\n", com->state);
2885 printf("calls to comstart():\t\t%d (%d useful)\n",
2886 com->start_count, com->start_real);
2887 printf("rx buffer chars free:\t\t%d\n", com->iptr - com->ibuf);
2888 ocount = 0;
2889 if (com->obufs[0].l_queued)
2890 ocount += com->obufs[0].l_tail - com->obufs[0].l_head;
2891 if (com->obufs[1].l_queued)
2892 ocount += com->obufs[1].l_tail - com->obufs[1].l_head;
2893 printf("tx buffer chars:\t\t%u\n", ocount);
2894 printf("received chars:\t\t\t%d\n", com->bytes_in);
2895 printf("received exceptions:\t\t%d\n", com->recv_exception);
2896 printf("modem signal deltas:\t\t%d\n", com->mdm);
2897 printf("transmitted chars:\t\t%d\n", com->bytes_out);
2898 printf("\n");
2899 tp = com->tp;
2900 if (tp != NULL) {
2901 printf("tty state:\t\t\t0x%08x\n", tp->t_state);
2902 printf(
2903 "upper layer queue lengths:\t%d raw, %d canon, %d output\n",
2904 tp->t_rawq.c_cc, tp->t_canq.c_cc, tp->t_outq.c_cc);
2905 } else
2906 printf("tty state:\t\t\tclosed\n");
2907}
2908#endif /* CyDebug */