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