This isn't 386BSD 0.1 any more now. Added CSRG's copyright, and changed
[unix-history] / sys / i386 / isa / sio.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
96029811
RG
33 * From:
34 * @(#)com.c 7.5 (Berkeley) 5/16/91
15637ed4
RG
35 *
36 * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt
37 * com port driver.
38 * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR
39 * code, add multiport support.
40 * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting
41 * into the patch kit. Added in sioselect
42 * from com.c. Added port 4 support.
43 */
3b0e8c9e 44static char rcsid[] = "$Header: /a/cvs/386BSD/src/sys/i386/isa/sio.c,v 1.6 1993/08/28 03:02:49 rgrimes Exp $";
15637ed4
RG
45
46#include "sio.h"
47#if NSIO > 0
48/*
49 * COM driver, based on HP dca driver.
50 * Mostly rewritten to use pseudo-DMA.
51 * Works for National Semiconductor NS8250-NS16550AF UARTs.
52 */
53#include "param.h"
54#include "systm.h"
55#include "ioctl.h"
56#include "tty.h"
57#include "proc.h"
58#include "user.h"
59#include "conf.h"
60#include "file.h"
61#include "uio.h"
62#include "kernel.h"
63#include "syslog.h"
64
65#include "i386/isa/isa.h"
66#include "i386/isa/isa_device.h"
67#include "i386/isa/comreg.h"
68#include "i386/isa/ic/ns16550.h"
69
70#undef CRTS_IFLOW
71#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */
72#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
73#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
74#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
75#define RS_IBUFSIZE 256
76#define TS_RTSBLOCK TS_TBLOCK /* XXX */
77#define TTY_BI TTY_FE /* XXX */
78#define TTY_OE TTY_PE /* XXX */
79#ifndef COM_BIDIR
80#define UNIT(x) (minor(x)) /* XXX */
81#else /* COM_BIDIR */
82#define COM_UNITMASK 0x7f
83#define COM_CALLOUTMASK 0x80
84
85#define UNIT(x) (minor(x) & COM_UNITMASK)
86#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
87#endif /* COM_BIDIR */
88
89#ifdef COM_MULTIPORT
90/* checks in flags for multiport and which is multiport "master chip"
91 * for a given card
92 */
93#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
94#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
95#endif /* COM_MULTIPORT */
96
97#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
98#define schedsoftcom() (ipending |= 1 << 4) /* XXX */
99
100/*
101 * Input buffer watermarks.
102 * The external device is asked to stop sending when the buffer exactly reaches
103 * high water, or when the high level requests it.
104 * The high level is notified immediately (rather than at a later clock tick)
105 * when this watermark is reached.
106 * The buffer size is chosen so the watermark should almost never be reached.
107 * The low watermark is invisibly 0 since the buffer is always emptied all at
108 * once.
109 */
110#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
111
112/*
113 * com state bits.
114 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
115 * than the other bits so that they can be tested as a group without masking
116 * off the low bits.
117 *
118 * The following com and tty flags correspond closely:
119 * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
120 * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
121 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
122 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
123 * TS_FLUSH is not used.
124 * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
125 */
126#define CS_BUSY 0x80 /* output in progress */
127#define CS_TTGO 0x40 /* output not stopped by XOFF */
128#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
129#define CS_CHECKMSR 1 /* check of MSR scheduled */
130#define CS_CTS_OFLOW 2 /* use CTS output flow control */
131#define CS_ODONE 4 /* output completed */
132#define CS_RTS_IFLOW 8 /* use RTS input flow control */
133
134static char *error_desc[] = {
135#define CE_OVERRUN 0
136 "silo overflow",
137#define CE_INTERRUPT_BUF_OVERFLOW 1
138 "interrupt-level buffer overflow",
139#define CE_TTY_BUF_OVERFLOW 2
140 "tty-level buffer overflow",
141};
142
143#define CE_NTYPES 3
144#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
145
146/* types. XXX - should be elsewhere */
147typedef u_int Port_t; /* hardware port */
148typedef int Bool_t; /* promoted boolean */
149typedef u_char bool_t; /* boolean */
150
151/* com device structure */
152struct com_s {
153 u_char state; /* miscellaneous flag bits */
154 u_char cfcr_image; /* copy of value written to CFCR */
155 bool_t hasfifo; /* nonzero for 16550 UARTs */
156 u_char mcr_image; /* copy of value written to MCR */
157 bool_t softDCD; /* nonzero for faked carrier detect */
158#ifdef COM_BIDIR
159 bool_t bidir; /* is this unit bidirectional? */
160 bool_t active; /* is the port active _at all_? */
161 bool_t active_in; /* is the incoming port in use? */
162 bool_t active_out; /* is the outgoing port in use? */
163#endif /* COM_BIDIR */
164#ifdef COM_MULTIPORT
165 bool_t multiport; /* is this unit part of a multiport device? */
166#endif /* COM_MULTIPORT */
167
168 /*
169 * The high level of the driver never reads status registers directly
170 * because there would be too many side effects to handle conveniently.
171 * Instead, it reads copies of the registers stored here by the
172 * interrupt handler.
173 */
174 u_char last_modem_status; /* last MSR read by intr handler */
175 u_char prev_modem_status; /* last MSR handled by high level */
176
177 u_char *ibuf; /* start of input buffer */
178 u_char *ibufend; /* end of input buffer */
179 u_char *ihighwater; /* threshold in input buffer */
180 u_char *iptr; /* next free spot in input buffer */
181
182 u_char *obufend; /* end of output buffer */
183 int ocount; /* original count for current output */
184 u_char *optr; /* next char to output */
185
186 Port_t data_port; /* i/o ports */
187 Port_t int_id_port;
188 Port_t iobase;
189 Port_t modem_ctl_port;
190 Port_t line_status_port;
191 Port_t modem_status_port;
192
193 struct tty *tp; /* cross reference */
194
195 u_long bytes_in; /* statistics */
196 u_long bytes_out;
197 u_int delta_error_counts[CE_NTYPES];
198 u_int error_counts[CE_NTYPES];
199
200 /*
201 * Ping-pong input buffers. The extra factor of 2 in the sizes is
202 * to allow for an error byte for each input byte.
203 */
204#define CE_INPUT_OFFSET RS_IBUFSIZE
205 u_char ibuf1[2 * RS_IBUFSIZE];
206 u_char ibuf2[2 * RS_IBUFSIZE];
207};
208
209
210/*
211 * These functions in the com module ought to be declared (with a prototype)
212 * in a com-driver system header. The void ones may need to be int to match
213 * ancient devswitch declarations, but they don't actually return anything.
214 */
215#define Dev_t int /* promoted dev_t */
216struct consdev;
217
218int sioclose __P((Dev_t dev, int fflag, int devtype,
219 struct proc *p));
220void siointr __P((int unit));
221#ifdef COM_MULTIPORT
222bool_t comintr1 __P((struct com_s *com));
223#endif /* COM_MULTIPORT */
224int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
225 int fflag, struct proc *p));
226int siocngetc __P((Dev_t dev));
227void siocninit __P((struct consdev *cp));
228void siocnprobe __P((struct consdev *cp));
229void siocnputc __P((Dev_t dev, int c));
230int sioopen __P((Dev_t dev, int oflags, int devtype,
231 struct proc *p));
232/*
233 * sioopen gets compared to the d_open entry in struct cdevsw. d_open and
234 * other functions are declared in <sys/conf.h> with short types like dev_t
235 * in the prototype. Such declarations are broken because they vary with
236 * __P (significantly in theory - the compiler is allowed to push a short
237 * arg if it has seen the prototype; insignificantly in practice - gcc
238 * doesn't push short args and it would be slower on 386's to do so).
239 *
240 * Also, most of the device switch functions are still declared old-style
241 * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler
242 * and faster if dev_t's were always promoted (to ints or whatever) as
243 * early as possible.
244 *
245 * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type
246 * when comparing it to the d_open entry just to avoid compiler warnings.
247 */
248typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
249 struct proc *p));
250int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
251void siostop __P((struct tty *tp, int rw));
252int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
253void softsio0 __P((void));
254void softsio1 __P((void));
255void softsio2 __P((void));
256void softsio3 __P((void));
257void softsio4 __P((void));
258void softsio5 __P((void));
259void softsio6 __P((void));
260void softsio7 __P((void));
261void softsio8 __P((void));
262
263static int sioattach __P((struct isa_device *dev));
264static void comflush __P((struct com_s *com));
265static void comhardclose __P((struct com_s *com));
266static void cominit __P((int unit, int rate));
267static int commctl __P((struct com_s *com, int bits, int how));
268static int comparam __P((struct tty *tp, struct termios *t));
269static int sioprobe __P((struct isa_device *dev));
270static void compoll __P((void));
271static int comstart __P((struct tty *tp));
272static void comwakeup __P((void));
273
274/* table and macro for fast conversion from a unit number to its com struct */
275static struct com_s *p_com_addr[NSIO];
276#define com_addr(unit) (p_com_addr[unit])
277
278static struct com_s com_structs[NSIO];
279
280struct isa_driver siodriver = {
281 sioprobe, sioattach, "sio"
282};
283
284#ifdef COMCONSOLE
285static int comconsole = COMCONSOLE;
286#else
287static int comconsole = -1;
288#endif
289static bool_t comconsinit;
290static speed_t comdefaultrate = TTYDEF_SPEED;
291static u_int com_events; /* input chars + weighted output completions */
292static int commajor;
293struct tty sio_tty[NSIO];
294extern struct tty *constty;
295extern u_int ipending; /* XXX */
296extern int tk_nin; /* XXX */
297extern int tk_rawcc; /* XXX */
298
299#ifdef KGDB
300#include "machine/remote-sl.h"
301
302extern int kgdb_dev;
303extern int kgdb_rate;
304extern int kgdb_debug_init;
305#endif
306
307static struct speedtab comspeedtab[] = {
308 0, 0,
309 50, COMBRD(50),
310 75, COMBRD(75),
311 110, COMBRD(110),
312 134, COMBRD(134),
313 150, COMBRD(150),
314 200, COMBRD(200),
315 300, COMBRD(300),
316 600, COMBRD(600),
317 1200, COMBRD(1200),
318 1800, COMBRD(1800),
319 2400, COMBRD(2400),
320 4800, COMBRD(4800),
321 9600, COMBRD(9600),
322 19200, COMBRD(19200),
323 38400, COMBRD(38400),
324 57600, COMBRD(57600),
325 115200, COMBRD(115200),
326 -1, -1
327};
328
329/* XXX - configure this list */
330static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
331
332static int
333sioprobe(dev)
334 struct isa_device *dev;
335{
336 static bool_t already_init;
337 Port_t *com_ptr;
338 Port_t iobase;
339 int result;
340
341 if (!already_init) {
342 /*
343 * Turn off MCR_IENABLE for all likely serial ports. An unused
344 * port with its MCR_IENABLE gate open will inhibit interrupts
345 * from any used port that shares the interrupt vector.
346 */
347 for (com_ptr = likely_com_ports;
348 com_ptr < &likely_com_ports[sizeof likely_com_ports
349 / sizeof likely_com_ports[0]];
350 ++com_ptr)
351 outb(*com_ptr + com_mcr, 0);
352 already_init = TRUE;
353 }
354 iobase = dev->id_iobase;
7530c2f0 355 result = IO_COMSIZE;
15637ed4
RG
356
357 /*
358 * We don't want to get actual interrupts, just masked ones.
359 * Interrupts from this line should already be masked in the ICU,
360 * but mask them in the processor as well in case there are some
361 * (misconfigured) shared interrupts.
362 */
363 disable_intr();
364
365 /*
366 * Enable output interrupts (only) and check the following:
367 * o the CFCR, IER and MCR in UART hold the values written to them
368 * (the values happen to be all distinct - this is good for
369 * avoiding false positive tests from bus echoes).
370 * o an output interrupt is generated and its vector is correct.
371 * o the interrupt goes away when the IIR in the UART is read.
372 */
373 outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
374 outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
375 outb(iobase + com_ier, 0); /* ensure edge on next intr */
376 outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
377 if ( inb(iobase + com_cfcr) != CFCR_8BITS
378 || inb(iobase + com_ier) != IER_ETXRDY
379 || inb(iobase + com_mcr) != MCR_IENABLE
15637ed4
RG
380 || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
381 || isa_irq_pending(dev)
382 || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
383 result = 0;
384
385 /*
386 * Turn off all device interrupts and check that they go off properly.
387 * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
388 * the ICU input. Closing the gate would give a floating ICU input
389 * (unless there is another device driving at) and spurious interrupts.
390 * (On the system that this was first tested on, the input floats high
391 * and gives a (masked) interrupt as soon as the gate is closed.)
392 */
393 outb(iobase + com_ier, 0);
394 outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
395 if ( inb(iobase + com_ier) != 0
396 || isa_irq_pending(dev)
397 || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
398 result = 0;
399
400 enable_intr();
401
402 return (result);
403}
404
405static int /* XXX - should be void */
406sioattach(isdp)
407 struct isa_device *isdp;
408{
409 struct com_s *com;
410 static bool_t comwakeup_started = FALSE;
411 Port_t iobase;
412 int s;
413 u_char scr;
414 u_char scr1;
415 u_char scr2;
416 int unit;
417
418 iobase = isdp->id_iobase;
419 unit = isdp->id_unit;
420 if (unit == comconsole)
421 DELAY(1000); /* XXX */
422 s = spltty();
423
424 /*
425 * sioprobe() has initialized the device registers as follows:
426 * o cfcr = CFCR_8BITS.
427 * It is most important that CFCR_DLAB is off, so that the
428 * data port is not hidden when we enable interrupts.
429 * o ier = 0.
430 * Interrupts are only enabled when the line is open.
431 * o mcr = MCR_IENABLE.
432 * Keeping MCR_DTR and MCR_RTS off might stop the external
433 * device from sending before we are ready.
434 */
435
436 com = &com_structs[unit];
437 com->cfcr_image = CFCR_8BITS;
438 com->mcr_image = MCR_IENABLE;
439#if 0
440 com->softDCD = TRUE;
441#endif
442 com->iptr = com->ibuf = com->ibuf1;
443 com->ibufend = com->ibuf1 + RS_IBUFSIZE;
444 com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
445 com->iobase = iobase;
446 com->data_port = iobase + com_data;
447 com->int_id_port = iobase + com_iir;
448 com->modem_ctl_port = iobase + com_mcr;
449 com->line_status_port = iobase + com_lsr;
450 com->modem_status_port = iobase + com_msr;
451 com->tp = &sio_tty[unit];
452#ifdef COM_BIDIR
453 /*
454 * if bidirectional ports possible, clear the bidir port info;
455 */
456 com->bidir = FALSE;
457 com->active = FALSE;
458 com->active_in = com->active_out = FALSE;
459#endif /* COM_BIDIR */
460
461 /* attempt to determine UART type */
462 scr = inb(iobase + com_scr);
463 outb(iobase + com_scr, 0xa5);
464 scr1 = inb(iobase + com_scr);
465 outb(iobase + com_scr, 0x5a);
466 scr2 = inb(iobase + com_scr);
467 outb(iobase + com_scr, scr);
b7c9de13 468 printf("sio%d: type", unit);
15637ed4
RG
469 if (scr1 != 0xa5 || scr2 != 0x5a)
470 printf(" <8250>");
471 else {
472 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
473 DELAY(100);
474 switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
475 case FIFO_TRIGGER_1:
476 printf(" <16450>");
477 break;
478 case FIFO_TRIGGER_4:
479 printf(" <16450?>");
480 break;
481 case FIFO_TRIGGER_8:
482 printf(" <16550?>");
483 break;
484 case FIFO_TRIGGER_14:
485 com->hasfifo = TRUE;
486 printf(" <16550A>");
487 break;
488 }
489 outb(iobase + com_fifo, 0);
490 }
491#ifdef COM_MULTIPORT
492 if (COM_ISMULTIPORT(isdp)) {
493 struct isa_device *masterdev;
494
495 com->multiport = TRUE;
496 printf(" (multiport)");
497
498 /* set the master's common-interrupt-enable reg.,
499 * as appropriate. YYY See your manual
500 */
501 /* enable only common interrupt for port */
502 outb(iobase + com_mcr, 0);
503
504 masterdev = find_isadev(isa_devtab_tty, &siodriver,
505 COM_MPMASTER(isdp));
506 outb(masterdev->id_iobase+com_scr, 0x80);
507 }
508 else
509 com->multiport = FALSE;
510#endif /* COM_MULTIPORT */
3b0e8c9e 511 printf("\n");
15637ed4
RG
512
513#ifdef KGDB
514 if (kgdb_dev == makedev(commajor, unit)) {
515 if (comconsole == unit)
516 kgdb_dev = -1; /* can't debug over console port */
517 else {
518 cominit(unit, kgdb_rate);
519 if (kgdb_debug_init) {
520 /*
521 * Print prefix of device name,
522 * let kgdb_connect print the rest.
523 */
524 printf("com%d: ", unit);
525 kgdb_connect(1);
526 }
527 else
528 printf("com%d: kgdb enabled\n", unit);
529 }
530 }
531#endif
532
533 /*
534 * Need to reset baud rate, etc. of next print so reset comconsinit.
535 * Also make sure console is always "hardwired"
536 */
537 if (unit == comconsole) {
538 comconsinit = FALSE;
539 com->softDCD = TRUE;
540 }
541
542 com_addr(unit) = com;
543
544 splx(s);
545
546 if (!comwakeup_started) {
547 comwakeup();
548 comwakeup_started = TRUE;
549 }
550
551 return (1);
552}
553
554/* ARGSUSED */
555int
556sioopen(dev, flag, mode, p)
557 dev_t dev;
558 int flag;
559 int mode;
560 struct proc *p;
561{
562 struct com_s *com;
563 int error = 0;
564 Port_t iobase;
565 int s;
566 struct tty *tp;
567 int unit = UNIT(dev);
568#ifdef COM_BIDIR
569 bool_t callout = CALLOUT(dev);
570#endif /* COM_BIDIR */
571 if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
572 return (ENXIO);
573#ifdef COM_BIDIR
574 /* if it's a callout device, and bidir not possible on that dev, die */
575 if (callout && !(com->bidir))
576 return (ENXIO);
577#endif /* COM_BIDIR */
578
579 tp = com->tp;
580 s = spltty();
581
582#ifdef COM_BIDIR
583
584bidir_open_top:
585 /* if it's bidirectional, we've gotta deal with it... */
586 if (com->bidir) {
587 if (callout) {
588 if (com->active_in) {
589 /* it's busy. die */
590 splx(s);
591 return (EBUSY);
592 } else {
593 /* it's ours. lock it down, and set it up */
594 com->active_out = TRUE;
595 com->softDCD = TRUE;
596 }
597 } else {
598 if (com->active_out) {
599 /* it's busy, outgoing. wait, if possible */
600 if (flag & O_NONBLOCK) {
601 /* can't wait; bail */
602 splx(s);
603 return (EBUSY);
604 } else {
605 /* wait for it... */
606 error = tsleep(&com->active_out,
607 TTIPRI|PCATCH,
608 "comoth",
609 0);
610 /* if there was an error, take off. */
611 if (error != 0) {
612 splx(s);
613 return (error);
614 }
615 /* else take it from the top */
616 goto bidir_open_top;
617 }
618 } else if (com->last_modem_status & MSR_DCD) {
619 /* there's a carrier on the line; we win */
620 com->active_in = TRUE;
621 com->softDCD = FALSE;
622 } else {
623 /* there is no carrier on the line */
624 if (flag & O_NONBLOCK) {
625 /* can't wait; let it open */
626 com->active_in = TRUE;
627 com->softDCD = FALSE;
628 } else {
629 /* put DTR & RTS up */
630 /* NOTE: cgd'sdriver used the ier register
631 * to enable/disable interrupts. This one
632 * uses both ier and IENABLE in the mcr.
633 */
634 (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
635 outb(com->iobase + com_ier, IER_EMSC);
636 /* wait for it... */
637 error = tsleep(&com->active_in,
638 TTIPRI|PCATCH,
639 "comdcd",
640 0);
641
642 /* if not active, turn DTR & RTS off */
643 if (!com->active)
644 (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
645
646 /* if there was an error, take off. */
647 if (error != 0) {
648 splx(s);
649 return (error);
650 }
651 /* else take it from the top */
652 goto bidir_open_top;
653 }
654 }
655 }
656 }
657
658 com->active = TRUE;
659#endif /* COM_BIDIR */
660
661 tp->t_oproc = comstart;
662 tp->t_param = comparam;
663 tp->t_dev = dev;
664 if (!(tp->t_state & TS_ISOPEN)) {
665 tp->t_state |= TS_WOPEN;
666 ttychars(tp);
667 if (tp->t_ispeed == 0) {
668 /*
669 * We no longer use the flags from <sys/ttydefaults.h>
670 * since those are only relevant for logins. It's
671 * important to have echo off initially so that the
672 * line doesn't start blathering before the echo flag
89ebea80 673 * can be turned off.
15637ed4
RG
674 */
675 tp->t_iflag = 0;
676 tp->t_oflag = 0;
89ebea80 677 tp->t_cflag = CREAD | CS8 | HUPCL;
15637ed4
RG
678 tp->t_lflag = 0;
679 tp->t_ispeed = tp->t_ospeed = comdefaultrate;
680 }
681 (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
682 error = comparam(tp, &tp->t_termios);
683 if (error != 0)
684 goto out;
685 ttsetwater(tp);
686 iobase = com->iobase;
687 disable_intr();
688 if (com->hasfifo)
689 /* (re)enable and drain FIFO */
690 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14
691 | FIFO_RCV_RST | FIFO_XMT_RST);
692 (void) inb(com->line_status_port);
693 (void) inb(com->data_port);
694 com->last_modem_status =
695 com->prev_modem_status = inb(com->modem_status_port);
696 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
697 | IER_EMSC);
698 enable_intr();
699 if (com->softDCD || com->prev_modem_status & MSR_DCD)
700 tp->t_state |= TS_CARR_ON;
701 }
702 else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
703 splx(s);
704 return (EBUSY);
705 }
706 while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
707#ifdef COM_BIDIR
708 /* We went through a lot of trouble to open it,
709 * but it's certain we have a carrier now, so
710 * don't spend any time on it now.
711 */
712 && !(com->bidir)
713#endif /* COM_BIDIR */
714 && !(tp->t_state & TS_CARR_ON)) {
715 tp->t_state |= TS_WOPEN;
716 error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
717 ttopen, 0);
718 if (error != 0)
719 break;
720 }
721out:
722 splx(s);
723 if (error == 0)
724 error = (*linesw[tp->t_line].l_open)(dev, tp);
725
726#ifdef COM_BIDIR
727 /* wakeup sleepers */
728 wakeup((caddr_t) &com->active_in);
729#endif /* COM_BIDIR */
730
731 /*
732 * XXX - the next step was once not done, so interrupts, DTR and RTS
733 * remainded hot if the process was killed while it was sleeping
734 * waiting for carrier. Now there is the opposite problem. If several
735 * processes are sleeping waiting for carrier on the same line and one
736 * is killed, interrupts are turned off so the other processes will
737 * never see the carrier rise.
738 */
739 if (error != 0 && !(tp->t_state & TS_ISOPEN))
740{
741 comhardclose(com);
742}
743 tp->t_state &= ~TS_WOPEN;
744
745 return (error);
746}
747
748/*ARGSUSED*/
749int
750sioclose(dev, flag, mode, p)
751 dev_t dev;
752 int flag;
753 int mode;
754 struct proc *p;
755{
756 struct com_s *com;
757 struct tty *tp;
758
759 com = com_addr(UNIT(dev));
760 tp = com->tp;
761 (*linesw[tp->t_line].l_close)(tp, flag);
762 comhardclose(com);
763 ttyclose(tp);
764 return (0);
765}
766
767void
768comhardclose(com)
769 struct com_s *com;
770{
771 Port_t iobase;
772 int s;
773 struct tty *tp;
774
775 s = spltty();
776 iobase = com->iobase;
777 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
778#ifdef KGDB
779 /* do not disable interrupts if debugging */
780 if (kgdb_dev != makedev(commajor, com - &com_structs[0]))
781#endif
782 outb(iobase + com_ier, 0);
783 tp = com->tp;
784 if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
785 || !(tp->t_state & TS_ISOPEN))
786 (void) commctl(com, 0, DMSET);
787#ifdef COM_BIDIR
788 com->active = com->active_in = com->active_out = FALSE;
789 com->softDCD = FALSE;
790
791 /* wakeup sleepers who are waiting for out to finish */
792 wakeup((caddr_t) &com->active_out);
793#endif /* COM_BIDIR */
794
795 splx(s);
796}
797
798int
799sioread(dev, uio, flag)
800 dev_t dev;
801 struct uio *uio;
802 int flag;
803{
804 struct tty *tp = com_addr(UNIT(dev))->tp;
805
806 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
807}
808
809int
810siowrite(dev, uio, flag)
811 dev_t dev;
812 struct uio *uio;
813 int flag;
814{
815 int unit = UNIT(dev);
816 struct tty *tp = com_addr(unit)->tp;
817
818 /*
819 * (XXX) We disallow virtual consoles if the physical console is
820 * a serial port. This is in case there is a display attached that
821 * is not the console. In that situation we don't need/want the X
822 * server taking over the console.
823 */
824 if (constty && unit == comconsole)
825 constty = NULL;
826 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
827}
828
829void
830siointr(unit)
831 int unit;
832{
833 struct com_s *com;
834#ifndef COM_MULTIPORT
835 u_char line_status;
836 u_char modem_status;
837 u_char *ioptr;
838 u_char recv_data;
839
840 com = com_addr(unit);
841#else /* COM_MULTIPORT */
842 int i;
843 bool_t donesomething;
844
845 do {
846 donesomething = FALSE;
847 for(i=0;i<NSIO;i++) {
848 com=com_addr(i);
849 if(com != NULL) {
850 /* XXX When siointr is called
851 * to start output, maybe
852 * it should be changed to a
853 * call to comintr1. Doesn't
854 * seem a good idea: interrupts
855 * are disabled all the time.
856 */
857enable_intr();
858disable_intr();
859 donesomething = comintr1(com);
860 }
861 }
862 } while (donesomething);
863 return;
864}
865
866bool_t
867comintr1(struct com_s *com)
868{
869 u_char line_status;
870 u_char modem_status;
871 u_char *ioptr;
872 u_char recv_data;
873 bool_t donesomething;
874
875 donesomething = FALSE;
876#endif /* COM_MULTIPORT */
877
878 while (TRUE) {
879 line_status = inb(com->line_status_port);
880
881 /* input event? (check first to help avoid overruns) */
882 while (line_status & LSR_RCV_MASK) {
883 /* break/unnattached error bits or real input? */
884#ifdef COM_MULTIPORT
885 donesomething = TRUE;
886#endif /* COM_MULTIPORT */
887 if (!(line_status & LSR_RXRDY))
888 recv_data = 0;
889 else
890 recv_data = inb(com->data_port);
891 ++com->bytes_in;
892#ifdef KGDB
893 /* trap into kgdb? (XXX - needs testing and optim) */
894 if (recv_data == FRAME_END
895 && !(com->tp->t_state & TS_ISOPEN)
896 && kgdb_dev == makedev(commajor, unit)) {
897 kgdb_connect(0);
898 continue;
899 }
900#endif /* KGDB */
901 ioptr = com->iptr;
902 if (ioptr >= com->ibufend)
903 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
904 else {
905 ++com_events;
906 ioptr[0] = recv_data;
907 ioptr[CE_INPUT_OFFSET] = line_status;
908 com->iptr = ++ioptr;
909 if (ioptr == com->ihighwater
910 && com->state & CS_RTS_IFLOW)
911 outb(com->modem_ctl_port,
912 com->mcr_image &= ~MCR_RTS);
913 }
914
915 /*
916 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
917 * jump from the top of the loop to here
918 */
919 line_status = inb(com->line_status_port) & 0x7F;
920 }
921
922 /* modem status change? (always check before doing output) */
923 modem_status = inb(com->modem_status_port);
924 if (modem_status != com->last_modem_status) {
925 /*
926 * Schedule high level to handle DCD changes. Note
927 * that we don't use the delta bits anywhere. Some
928 * UARTs mess them up, and it's easy to remember the
929 * previous bits and calculate the delta.
930 */
931#ifdef COM_MULTIPORT
932 donesomething = TRUE;
933#endif /* COM_MULTIPORT */
934 com->last_modem_status = modem_status;
935 if (!(com->state & CS_CHECKMSR)) {
936 com_events += LOTS_OF_EVENTS;
937 com->state |= CS_CHECKMSR;
938 schedsoftcom();
939 }
940
941 /* handle CTS change immediately for crisp flow ctl */
942 if (com->state & CS_CTS_OFLOW) {
943 if (modem_status & MSR_CTS)
944 com->state |= CS_ODEVREADY;
945 else
946 com->state &= ~CS_ODEVREADY;
947 }
948 }
949
950 /* output queued and everything ready? */
951 if (line_status & LSR_TXRDY
952 && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
953#ifdef COM_MULTIPORT
954 donesomething = TRUE;
955#endif /* COM_MULTIPORT */
956 ioptr = com->optr;
957 outb(com->data_port, *ioptr);
958 ++com->bytes_out;
959 com->optr = ++ioptr;
960 if (ioptr >= com->obufend) {
961 /* output just completed */
962 com_events += LOTS_OF_EVENTS;
963 com->state ^= (CS_ODONE | CS_BUSY);
964 schedsoftcom(); /* handle at high level ASAP */
965 }
966 }
967
968 /* finished? */
969 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
970#ifdef COM_MULTIPORT
971 return (donesomething);
972#else
973 return;
974#endif /* COM_MULTIPORT */
975 }
976}
977
978int
979sioioctl(dev, cmd, data, flag, p)
980 dev_t dev;
981 int cmd;
982 caddr_t data;
983 int flag;
984 struct proc *p;
985{
986 struct com_s *com;
987 int error;
988 Port_t iobase;
989 int s;
990 struct tty *tp;
991
992 com = com_addr(UNIT(dev));
993 tp = com->tp;
994 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
995 if (error >= 0)
996 return (error);
997 error = ttioctl(tp, cmd, data, flag);
998 if (error >= 0)
999 return (error);
1000
1001 iobase = com->iobase;
1002 s = spltty();
1003 switch (cmd) {
1004 case TIOCSBRK:
1005 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1006 break;
1007 case TIOCCBRK:
1008 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1009 break;
1010 case TIOCSDTR:
1011 (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS);
1012 break;
1013 case TIOCCDTR:
1014 (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
1015 break;
1016 case TIOCMSET:
1017 (void) commctl(com, *(int *)data, DMSET);
1018 break;
1019 case TIOCMBIS:
1020 (void) commctl(com, *(int *)data, DMBIS);
1021 break;
1022 case TIOCMBIC:
1023 (void) commctl(com, *(int *)data, DMBIC);
1024 break;
1025 case TIOCMGET:
1026 *(int *)data = commctl(com, 0, DMGET);
1027 break;
1028#ifdef COM_BIDIR
1029 case TIOCMSBIDIR:
1030 /* must be root to set bidir. capability */
1031 if (p->p_ucred->cr_uid != 0)
1032 return(EPERM);
1033
1034 /* if it's the console, can't do it */
1035 if (UNIT(dev) == comconsole)
1036 return(ENOTTY);
1037
1038 /* can't do the next, for obvious reasons...
1039 * but there are problems to be looked at...
1040 */
1041
1042 /* if the port is active, don't do it */
1043 /* if (com->active)
1044 return(EBUSY); */
1045
1046 com->bidir = *(int *)data;
1047 break;
1048 case TIOCMGBIDIR:
1049 *(int *)data = com->bidir;
1050 break;
1051#endif /* COM_BIDIR */
1052 default:
1053 splx(s);
1054 return (ENOTTY);
1055 }
1056 splx(s);
1057 return (0);
1058}
1059
1060/* cancel pending output */
1061static void
1062comflush(com)
1063 struct com_s *com;
1064{
1065 struct ringb *rbp;
1066
1067 disable_intr();
1068 if (com->state & CS_ODONE)
1069 com_events -= LOTS_OF_EVENTS;
1070 com->state &= ~(CS_ODONE | CS_BUSY);
1071 enable_intr();
1072 rbp = &com->tp->t_out;
1073 rbp->rb_hd += com->ocount;
1074 rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
1075 com->ocount = 0;
1076 com->tp->t_state &= ~TS_BUSY;
1077}
1078
1079static void
1080compoll()
1081{
1082 static bool_t awake = FALSE;
1083 struct com_s *com;
1084 int s;
1085 int unit;
1086
1087 if (com_events == 0)
1088 return;
1089 disable_intr();
1090 if (awake) {
1091 enable_intr();
1092 return;
1093 }
1094 awake = TRUE;
1095 enable_intr();
1096 s = spltty();
1097repeat:
1098 for (unit = 0; unit < NSIO; ++unit) {
1099 u_char *buf;
1100 u_char *ibuf;
1101 int incc;
1102 struct tty *tp;
1103
1104 com = com_addr(unit);
1105 if (com == NULL)
1106 continue;
1107 tp = com->tp;
1108
1109 /* switch the role of the low-level input buffers */
1110 if (com->iptr == (ibuf = com->ibuf))
1111 incc = 0;
1112 else {
1113 buf = ibuf;
1114 disable_intr();
1115 incc = com->iptr - buf;
1116 com_events -= incc;
1117 if (ibuf == com->ibuf1)
1118 ibuf = com->ibuf2;
1119 else
1120 ibuf = com->ibuf1;
1121 com->ibufend = ibuf + RS_IBUFSIZE;
1122 com->ihighwater = ibuf + RS_IHIGHWATER;
1123 com->iptr = ibuf;
1124
1125 /*
1126 * There is now room for another low-level buffer full
1127 * of input, so enable RTS if it is now disabled and
1128 * there is room in the high-level buffer.
1129 */
1130 if (!(com->mcr_image & MCR_RTS)
1131 && !(tp->t_state & TS_RTSBLOCK))
1132 outb(com->modem_ctl_port,
1133 com->mcr_image |= MCR_RTS);
1134 enable_intr();
1135 com->ibuf = ibuf;
1136 }
1137
1138 if (com->state & CS_CHECKMSR) {
1139 u_char delta_modem_status;
1140
1141 disable_intr();
1142 delta_modem_status = com->last_modem_status
1143 ^ com->prev_modem_status;
1144 com->prev_modem_status = com->last_modem_status;
1145 com_events -= LOTS_OF_EVENTS;
1146 com->state &= ~CS_CHECKMSR;
1147 enable_intr();
1148 if (delta_modem_status & MSR_DCD &&
1149 unit != comconsole) {
1150#ifdef COM_BIDIR
1151 if (com->prev_modem_status & MSR_DCD) {
1152 (*linesw[tp->t_line].l_modem)(tp, 1);
1153 com->softDCD = FALSE;
1154 wakeup((caddr_t) &com->active_in);
1155 }
1156#else
1157 if (com->prev_modem_status & MSR_DCD)
1158 (*linesw[tp->t_line].l_modem)(tp, 1);
1159#endif /* COM_BIDIR */
1160 else if ((*linesw[tp->t_line].l_modem)(tp, 0)
1161 == 0) {
1162 disable_intr();
1163 outb(com->modem_ctl_port,
1164 com->mcr_image
1165 &= ~(MCR_DTR | MCR_RTS));
1166 enable_intr();
1167 }
1168 }
1169 }
1170
1171 /* XXX */
1172 if (TRUE) {
1173 u_int delta;
1174 u_int delta_error_counts[CE_NTYPES];
1175 int errnum;
1176 u_long total;
1177
1178 disable_intr();
1179 bcopy(com->delta_error_counts, delta_error_counts,
1180 sizeof delta_error_counts);
1181 bzero(com->delta_error_counts,
1182 sizeof delta_error_counts);
1183 enable_intr();
1184 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
1185 delta = delta_error_counts[errnum];
1186 if (delta != 0) {
1187 total =
1188 com->error_counts[errnum] += delta;
1189 log(LOG_WARNING,
1190 "com%d: %u more %s%s (total %lu)\n",
1191 unit, delta, error_desc[errnum],
1192 delta == 1 ? "" : "s", total);
1193 }
1194 }
1195 }
1196 if (com->state & CS_ODONE) {
1197 comflush(com);
1198 /* XXX - why isn't the table used for t_line == 0? */
1199 if (tp->t_line != 0)
1200 (*linesw[tp->t_line].l_start)(tp);
1201 else
1202 comstart(tp);
1203 }
1204 if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
1205 continue;
1206 if (com->state & CS_RTS_IFLOW
1207 && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
1208 && !(tp->t_state & TS_RTSBLOCK)
1209 /*
1210 * XXX - need RTS flow control for all line disciplines.
1211 * Only have it in standard one now.
1212 */
1213 && linesw[tp->t_line].l_rint == ttyinput) {
1214 tp->t_state |= TS_RTSBLOCK;
1215 ttstart(tp);
1216 }
1217 /*
1218 * Avoid the grotesquely inefficient lineswitch routine
1219 * (ttyinput) in "raw" mode. It usually takes about 450
1220 * instructions (that's without canonical processing or echo!).
1221 * slinput is reasonably fast (usually 40 instructions plus
1222 * call overhead).
1223 */
1224 if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
1225 | IXOFF | IXON))
1226 && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
1227 | PENDIN))
1228 && !(tp->t_state & (TS_CNTTB | TS_LNCH))
1229 && linesw[tp->t_line].l_rint == ttyinput) {
1230 tk_nin += incc;
1231 tk_rawcc += incc;
1232 tp->t_rawcc += incc;
1233 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1234 += incc - rb_write(&tp->t_raw, (char *) buf,
1235 incc);
1236 ttwakeup(tp);
1237 if (tp->t_state & TS_TTSTOP
1238 && (tp->t_iflag & IXANY
1239 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1240 tp->t_state &= ~TS_TTSTOP;
1241 tp->t_lflag &= ~FLUSHO;
1242 ttstart(tp);
1243 }
1244 }
1245 else {
1246 do {
1247 u_char line_status;
1248 int recv_data;
1249
1250 line_status = (u_char) buf[CE_INPUT_OFFSET];
1251 recv_data = (u_char) *buf++;
1252 if (line_status
1253 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1254 if (line_status & LSR_BI)
1255 recv_data |= TTY_BI;
1256 if (line_status & LSR_FE)
1257 recv_data |= TTY_FE;
1258 if (line_status & LSR_OE)
1259 recv_data |= TTY_OE;
1260 if (line_status & LSR_PE)
1261 recv_data |= TTY_PE;
1262 }
1263 (*linesw[tp->t_line].l_rint)(recv_data, tp);
1264 } while (--incc > 0);
1265 }
1266 if (com_events == 0)
1267 break;
1268 }
1269 if (com_events >= LOTS_OF_EVENTS)
1270 goto repeat;
1271 splx(s);
1272 awake = FALSE;
1273}
1274
1275static int
1276comparam(tp, t)
1277 struct tty *tp;
1278 struct termios *t;
1279{
1280 u_int cfcr;
1281 int cflag;
1282 struct com_s *com;
1283 int divisor;
1284 int error;
1285 Port_t iobase;
1286 int s;
1287 int unit;
1288
1289 /* check requested parameters */
1290 divisor = ttspeedtab(t->c_ospeed, comspeedtab);
1291 if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed)
1292 return (EINVAL);
1293
1294 /* parameters are OK, convert them to the com struct and the device */
1295 unit = UNIT(tp->t_dev);
1296 com = com_addr(unit);
1297 iobase = com->iobase;
1298 s = spltty();
1299 if (divisor == 0) {
1300 (void) commctl(com, 0, DMSET); /* hang up line */
1301 splx(s);
1302 return (0);
1303 }
1304 cflag = t->c_cflag;
1305 switch (cflag & CSIZE) {
1306 case CS5:
1307 cfcr = CFCR_5BITS;
1308 break;
1309 case CS6:
1310 cfcr = CFCR_6BITS;
1311 break;
1312 case CS7:
1313 cfcr = CFCR_7BITS;
1314 break;
1315 default:
1316 cfcr = CFCR_8BITS;
1317 break;
1318 }
1319 if (cflag & PARENB) {
1320 cfcr |= CFCR_PENAB;
1321 if (!(cflag & PARODD))
1322 cfcr |= CFCR_PEVEN;
1323 }
1324 if (cflag & CSTOPB)
1325 cfcr |= CFCR_STOPB;
1326
1327 /*
1328 * Some UARTs lock up if the divisor latch registers are selected
1329 * while the UART is doing output (they refuse to transmit anything
1330 * more until given a hard reset). Fix this by stopping filling
1331 * the device buffers and waiting for them to drain. Reading the
1332 * line status port outside of siointr() might lose some receiver
1333 * error bits, but that is acceptable here.
1334 */
1335 disable_intr();
1336 com->state &= ~CS_TTGO;
1337 enable_intr();
1338 while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1339 != (LSR_TSRE | LSR_TXRDY)) {
1340 error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
1341 "comparam", 1);
1342 if (error != 0 && error != EAGAIN) {
1343 if (!(tp->t_state & TS_TTSTOP)) {
1344 disable_intr();
1345 com->state |= CS_TTGO;
1346 enable_intr();
1347 }
1348 splx(s);
1349 return (error);
1350 }
1351 }
1352
1353 disable_intr(); /* very important while com_data is hidden */
1354 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
1355 outb(iobase + com_dlbl, divisor & 0xFF);
1356 outb(iobase + com_dlbh, (u_int) divisor >> 8);
1357 outb(iobase + com_cfcr, com->cfcr_image = cfcr);
1358 if (!(tp->t_state & TS_TTSTOP))
1359 com->state |= CS_TTGO;
1360 if (cflag & CRTS_IFLOW)
1361 com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
1362 else
1363 com->state &= ~CS_RTS_IFLOW;
1364
1365 /*
1366 * Set up state to handle output flow control.
1367 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
1368 * Now has 16+ msec latency, while CTS flow has 50- usec latency.
1369 * Note that DCD flow control stupidly uses the same state flag
1370 * (TS_TTSTOP) as XON/XOFF flow control.
1371 */
1372 com->state &= ~CS_CTS_OFLOW;
1373 com->state |= CS_ODEVREADY;
1374 if (cflag & CCTS_OFLOW) {
1375 com->state |= CS_CTS_OFLOW;
1376 if (!(com->prev_modem_status & MSR_CTS))
1377 com->state &= ~CS_ODEVREADY;
1378 }
1379
1380 enable_intr();
1381 siointr(unit); /* recover from fiddling with CS_TTGO */
1382 splx(s);
1383 return (0);
1384}
1385
1386static int /* XXX - should be void */
1387comstart(tp)
1388 struct tty *tp;
1389{
1390 struct com_s *com;
1391 int s;
1392 int unit;
1393
1394 unit = UNIT(tp->t_dev);
1395 com = com_addr(unit);
1396 s = spltty();
1397 disable_intr();
1398 if (tp->t_state & TS_TTSTOP)
1399 com->state &= ~CS_TTGO;
1400 else
1401 com->state |= CS_TTGO;
1402 if (tp->t_state & TS_RTSBLOCK) {
1403 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
1404 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
1405 }
1406 else {
1407 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
1408 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1409 }
1410 enable_intr();
1411 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
1412 goto out;
1413 if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
1414 if (tp->t_state & TS_ASLEEP) {
1415 tp->t_state &= ~TS_ASLEEP;
1416 wakeup((caddr_t)&tp->t_out);
1417 }
1418 if (tp->t_wsel) {
1419 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
1420 tp->t_wsel = 0;
1421 tp->t_state &= ~TS_WCOLL;
1422 }
1423 }
1424 if (com->ocount != 0) {
1425 disable_intr();
1426 siointr(unit);
1427 enable_intr();
1428 }
1429 else if (RB_LEN(&tp->t_out) != 0) {
1430 tp->t_state |= TS_BUSY;
1431 com->ocount = RB_CONTIGGET(&tp->t_out);
1432 disable_intr();
1433 com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
1434 + com->ocount;
1435 com->state |= CS_BUSY;
1436 siointr(unit); /* fake interrupt to start output */
1437 enable_intr();
1438 }
1439out:
1440 splx(s);
1441 return (1);
1442}
1443
1444void
1445siostop(tp, rw)
1446 struct tty *tp;
1447 int rw;
1448{
1449 struct com_s *com;
1450
1451 com = com_addr(UNIT(tp->t_dev));
1452 if (rw & FWRITE)
1453 comflush(com);
1454 disable_intr();
1455 if (tp->t_state & TS_TTSTOP)
1456 com->state &= ~CS_TTGO;
1457 else
1458 com->state |= CS_TTGO;
1459 enable_intr();
1460}
1461
1462static int
1463commctl(com, bits, how)
1464 struct com_s *com;
1465 int bits;
1466 int how;
1467{
1468 disable_intr();
1469 switch (how) {
1470 case DMSET:
1471#ifdef COM_MULTIPORT
1472 /* YYY maybe your card doesn't want IENABLE to be reset? */
1473 if(com->multiport)
1474 outb(com->modem_ctl_port,
1475 com->mcr_image = bits);
1476 else
1477#endif /* COM_MULTIPORT */
1478 outb(com->modem_ctl_port,
1479 com->mcr_image = bits | MCR_IENABLE);
1480 break;
1481 case DMBIS:
1482 outb(com->modem_ctl_port, com->mcr_image |= bits);
1483 break;
1484 case DMBIC:
1485#ifdef COM_MULTIPORT
1486 /* YYY maybe your card doesn't want IENABLE to be reset? */
1487 if(com->multiport)
1488 outb(com->modem_ctl_port,
1489 com->mcr_image &= ~(bits));
1490 else
1491#endif /* COM_MULTIPORT */
1492 outb(com->modem_ctl_port,
1493 com->mcr_image &= ~(bits & ~MCR_IENABLE));
1494 break;
1495 case DMGET:
1496 bits = com->prev_modem_status;
1497 break;
1498 }
1499 enable_intr();
1500 return (bits);
1501}
1502
1503static void
1504comwakeup()
1505{
1506 struct com_s *com;
1507 int unit;
1508
1509 timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1);
1510 if (com_events != 0)
1511 /* schedule compoll() to run when the cpl allows */
1512 schedsoftcom();
1513
1514 /* recover from lost output interrupts */
1515 for (unit = 0; unit < NSIO; ++unit) {
1516 com = com_addr(unit);
1517 if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
1518 disable_intr();
1519 siointr(unit);
1520 enable_intr();
1521 }
1522 }
1523}
1524
1525void
1526softsio0() { compoll(); }
1527
1528void
1529softsio1() { compoll(); }
1530
1531void
1532softsio2() { compoll(); }
1533
1534void
1535softsio3() { compoll(); }
1536
1537void
1538softsio4() { compoll(); }
1539
1540void
1541softsio5() { compoll(); }
1542
1543void
1544softsio6() { compoll(); }
1545
1546void
1547softsio7() { compoll(); }
1548
1549void
1550softsio8() { compoll(); }
1551
1552/*
1553 * Following are all routines needed for COM to act as console
1554 * XXX - not tested in this version
1555 * XXX - check that the corresponding serial interrupts are never enabled
1556 */
1557#include "i386/i386/cons.h"
1558
1559void
1560siocnprobe(cp)
1561 struct consdev *cp;
1562{
1563 int unit;
1564
1565 /* locate the major number */
1566 for (commajor = 0; commajor < nchrdev; commajor++)
1567 if (cdevsw[commajor].d_open == (bogus_open_t) sioopen)
1568 break;
1569
1570 /* XXX: ick */
1571 unit = CONUNIT;
1572 com_addr(unit) = &com_structs[unit];
1573 com_addr(unit)->iobase = CONADDR;
1574
1575 /* make sure hardware exists? XXX */
1576
1577 /* initialize required fields */
1578 cp->cn_dev = makedev(commajor, unit);
1579 cp->cn_tp = &sio_tty[unit];
1580#ifdef COMCONSOLE
1581 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
1582#else
1583 cp->cn_pri = CN_NORMAL;
1584#endif
1585}
1586
1587void
1588siocninit(cp)
1589 struct consdev *cp;
1590{
1591 int unit;
1592
1593 unit = UNIT(cp->cn_dev);
1594 cominit(unit, comdefaultrate);
1595 comconsole = unit;
1596 comconsinit = TRUE;
1597}
1598
1599static void
1600cominit(unit, rate)
1601 int unit;
1602 int rate;
1603{
1604 Port_t iobase;
1605 int s;
1606
1607 iobase = com_addr(unit)->iobase;
1608 s = splhigh();
1609 outb(iobase + com_cfcr, CFCR_DLAB);
1610 rate = ttspeedtab(comdefaultrate, comspeedtab);
1611 outb(iobase + com_data, rate & 0xFF);
1612 outb(iobase + com_ier, rate >> 8);
1613 outb(iobase + com_cfcr, CFCR_8BITS);
1614
1615 /*
1616 * XXX - fishy to enable interrupts and then poll.
1617 * It shouldn't be necessary to ready the iir.
1618 */
1619 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
1620 outb(iobase + com_fifo,
1621 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
1622 (void) inb(iobase + com_iir);
1623 splx(s);
1624}
1625
1626int
1627siocngetc(dev)
1628 dev_t dev;
1629{
1630 int c;
1631 Port_t iobase;
1632 int s;
1633
1634 iobase = com_addr(UNIT(dev))->iobase;
1635 s = splhigh();
1636 while (!(inb(iobase + com_lsr) & LSR_RXRDY))
1637 ;
1638 c = inb(iobase + com_data);
1639 (void) inb(iobase + com_iir);
1640 splx(s);
1641 return (c);
1642}
1643
1644void
1645siocnputc(dev, c)
1646 dev_t dev;
1647 int c;
1648{
1649 Port_t iobase;
1650 int s;
1651 int timo;
1652
1653 iobase = com_addr(UNIT(dev))->iobase;
1654 s = splhigh();
1655#ifdef KGDB
1656 if (dev != kgdb_dev)
1657#endif
1658 if (!comconsinit) {
1659 (void) cominit(UNIT(dev), comdefaultrate);
1660 comconsinit = TRUE;
1661 }
1662 /* wait for any pending transmission to finish */
1663 timo = 50000;
1664 while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
1665 ;
1666 outb(iobase + com_data, c);
1667 /* wait for this transmission to complete */
1668 timo = 1500000;
1669 while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
1670 ;
1671 /* clear any interrupts generated by this transmission */
1672 (void) inb(iobase + com_iir);
1673 splx(s);
1674}
1675
1676/*
1677 * 10 Feb 93 Jordan K. Hubbard Added select code
1678 * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5
1679 */
1680
1681int
1682sioselect(dev, rw, p)
1683 dev_t dev;
1684 int rw;
1685 struct proc *p;
1686{
1687 register struct tty *tp = &sio_tty[UNIT(dev)];
1688 int nread;
1689 int s = spltty();
1690 struct proc *selp;
1691
1692 switch (rw) {
1693
1694 case FREAD:
1695 nread = ttnread(tp);
1696 if (nread > 0 ||
1697 ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
1698 goto win;
1699 if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
1700 tp->t_state |= TS_RCOLL;
1701 else
1702 tp->t_rsel = p->p_pid;
1703 break;
1704
1705 case FWRITE:
1706 if (RB_LEN(&tp->t_out) <= tp->t_lowat)
1707 goto win;
1708 if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
1709 tp->t_state |= TS_WCOLL;
1710 else
1711 tp->t_wsel = p->p_pid;
1712 break;
1713 }
1714 splx(s);
1715 return (0);
1716 win:
1717 splx(s);
1718 return (1);
1719}
1720
1721#endif /* NSIO > 0 */