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