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