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