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