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