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