FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/sio.c
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 *
33 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
34 * $FreeBSD$
35 */
36
37 #include "opt_comconsole.h"
38 #include "opt_compat.h"
39 #include "opt_ddb.h"
40 #include "opt_devfs.h"
41 #include "opt_sio.h"
42 #include "sio.h"
43 #include "pnp.h"
44
45 /*
46 * Serial driver, based on 386BSD-0.1 com driver.
47 * Mostly rewritten to use pseudo-DMA.
48 * Works for National Semiconductor NS8250-NS16550AF UARTs.
49 * COM driver, based on HP dca driver.
50 *
51 * Changes for PC-Card integration:
52 * - Added PC-Card driver table and handlers
53 */
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/reboot.h>
57 #include <sys/malloc.h>
58 #include <sys/tty.h>
59 #include <sys/proc.h>
60 #include <sys/conf.h>
61 #include <sys/dkstat.h>
62 #include <sys/fcntl.h>
63 #include <sys/interrupt.h>
64 #include <sys/kernel.h>
65 #include <sys/syslog.h>
66 #include <sys/sysctl.h>
67 #ifdef DEVFS
68 #include <sys/devfsext.h>
69 #endif
70 #include <sys/timepps.h>
71
72 #include <machine/clock.h>
73 #include <machine/ipl.h>
74 #ifndef SMP
75 #include <machine/lock.h>
76 #endif
77
78 #include <i386/isa/isa.h>
79 #include <i386/isa/isa_device.h>
80 #include <i386/isa/sioreg.h>
81 #include <i386/isa/intr_machdep.h>
82
83 #ifdef COM_ESP
84 #include <i386/isa/ic/esp.h>
85 #endif
86 #include <i386/isa/ic/ns16550.h>
87
88 #include "card.h"
89 #if NCARD > 0
90 #include <sys/module.h>
91 #include <pccard/cardinfo.h>
92 #include <pccard/slot.h>
93 #endif
94
95 #if NPNP > 0
96 #include <i386/isa/pnp.h>
97 #endif
98
99 #ifdef SMP
100 #define disable_intr() COM_DISABLE_INTR()
101 #define enable_intr() COM_ENABLE_INTR()
102 #endif /* SMP */
103
104 #ifndef EXTRA_SIO
105 #if NPNP > 0
106 #define EXTRA_SIO MAX_PNP_CARDS
107 #else
108 #define EXTRA_SIO 0
109 #endif
110 #endif
111
112 #define NSIOTOT (NSIO + EXTRA_SIO)
113
114 #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
115 #define RS_IBUFSIZE 256
116
117 #define CALLOUT_MASK 0x80
118 #define CONTROL_MASK 0x60
119 #define CONTROL_INIT_STATE 0x20
120 #define CONTROL_LOCK_STATE 0x40
121 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
122 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
123 #define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
124
125 #ifdef COM_MULTIPORT
126 /* checks in flags for multiport and which is multiport "master chip"
127 * for a given card
128 */
129 #define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
130 #define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
131 #define COM_NOTAST4(dev) ((dev)->id_flags & 0x04)
132 #endif /* COM_MULTIPORT */
133
134 #define COM_CONSOLE(dev) ((dev)->id_flags & 0x10)
135 #define COM_FORCECONSOLE(dev) ((dev)->id_flags & 0x20)
136 #define COM_LLCONSOLE(dev) ((dev)->id_flags & 0x40)
137 #define COM_LOSESOUTINTS(dev) ((dev)->id_flags & 0x08)
138 #define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
139 #define COM_ST16650A(dev) ((dev)->id_flags & 0x20000)
140 #define COM_C_NOPROBE (0x40000)
141 #define COM_NOPROBE(dev) ((dev)->id_flags & COM_C_NOPROBE)
142 #define COM_C_IIR_TXRDYBUG (0x80000)
143 #define COM_IIR_TXRDYBUG(dev) ((dev)->id_flags & COM_C_IIR_TXRDYBUG)
144 #define COM_FIFOSIZE(dev) (((dev)->id_flags & 0xff000000) >> 24)
145
146 #define com_scr 7 /* scratch register for 16450-16550 (R/W) */
147
148 /*
149 * Input buffer watermarks.
150 * The external device is asked to stop sending when the buffer exactly reaches
151 * high water, or when the high level requests it.
152 * The high level is notified immediately (rather than at a later clock tick)
153 * when this watermark is reached.
154 * The buffer size is chosen so the watermark should almost never be reached.
155 * The low watermark is invisibly 0 since the buffer is always emptied all at
156 * once.
157 */
158 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
159
160 /*
161 * com state bits.
162 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
163 * than the other bits so that they can be tested as a group without masking
164 * off the low bits.
165 *
166 * The following com and tty flags correspond closely:
167 * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and
168 * siostop())
169 * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart())
170 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
171 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
172 * TS_FLUSH is not used.
173 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
174 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
175 */
176 #define CS_BUSY 0x80 /* output in progress */
177 #define CS_TTGO 0x40 /* output not stopped by XOFF */
178 #define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
179 #define CS_CHECKMSR 1 /* check of MSR scheduled */
180 #define CS_CTS_OFLOW 2 /* use CTS output flow control */
181 #define CS_DTR_OFF 0x10 /* DTR held off */
182 #define CS_ODONE 4 /* output completed */
183 #define CS_RTS_IFLOW 8 /* use RTS input flow control */
184 #define CSE_BUSYCHECK 1 /* siobusycheck() scheduled */
185
186 static char const * const error_desc[] = {
187 #define CE_OVERRUN 0
188 "silo overflow",
189 #define CE_INTERRUPT_BUF_OVERFLOW 1
190 "interrupt-level buffer overflow",
191 #define CE_TTY_BUF_OVERFLOW 2
192 "tty-level buffer overflow",
193 };
194
195 #define CE_NTYPES 3
196 #define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
197
198 /* types. XXX - should be elsewhere */
199 typedef u_int Port_t; /* hardware port */
200 typedef u_char bool_t; /* boolean */
201
202 /* queue of linear buffers */
203 struct lbq {
204 u_char *l_head; /* next char to process */
205 u_char *l_tail; /* one past the last char to process */
206 struct lbq *l_next; /* next in queue */
207 bool_t l_queued; /* nonzero if queued */
208 };
209
210 /* com device structure */
211 struct com_s {
212 u_int id_flags; /* Copy isa device falgas */
213 u_char state; /* miscellaneous flag bits */
214 bool_t active_out; /* nonzero if the callout device is open */
215 u_char cfcr_image; /* copy of value written to CFCR */
216 #ifdef COM_ESP
217 bool_t esp; /* is this unit a hayes esp board? */
218 #endif
219 u_char extra_state; /* more flag bits, separate for order trick */
220 u_char fifo_image; /* copy of value written to FIFO */
221 bool_t hasfifo; /* nonzero for 16550 UARTs */
222 bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */
223 bool_t loses_outints; /* nonzero if device loses output interrupts */
224 u_char mcr_image; /* copy of value written to MCR */
225 #ifdef COM_MULTIPORT
226 bool_t multiport; /* is this unit part of a multiport device? */
227 #endif /* COM_MULTIPORT */
228 bool_t no_irq; /* nonzero if irq is not attached */
229 bool_t gone; /* hardware disappeared */
230 bool_t poll; /* nonzero if polling is required */
231 bool_t poll_output; /* nonzero if polling for output is required */
232 int unit; /* unit number */
233 int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
234 u_int tx_fifo_size;
235 u_int wopeners; /* # processes waiting for DCD in open() */
236
237 /*
238 * The high level of the driver never reads status registers directly
239 * because there would be too many side effects to handle conveniently.
240 * Instead, it reads copies of the registers stored here by the
241 * interrupt handler.
242 */
243 u_char last_modem_status; /* last MSR read by intr handler */
244 u_char prev_modem_status; /* last MSR handled by high level */
245
246 u_char hotchar; /* ldisc-specific char to be handled ASAP */
247 u_char *ibuf; /* start of input buffer */
248 u_char *ibufend; /* end of input buffer */
249 u_char *ihighwater; /* threshold in input buffer */
250 u_char *iptr; /* next free spot in input buffer */
251
252 struct lbq obufq; /* head of queue of output buffers */
253 struct lbq obufs[2]; /* output buffers */
254
255 Port_t data_port; /* i/o ports */
256 #ifdef COM_ESP
257 Port_t esp_port;
258 #endif
259 Port_t int_id_port;
260 Port_t iobase;
261 Port_t modem_ctl_port;
262 Port_t line_status_port;
263 Port_t modem_status_port;
264 Port_t intr_ctl_port; /* Ports of IIR register */
265
266 struct tty *tp; /* cross reference */
267
268 /* Initial state. */
269 struct termios it_in; /* should be in struct tty */
270 struct termios it_out;
271
272 /* Lock state. */
273 struct termios lt_in; /* should be in struct tty */
274 struct termios lt_out;
275
276 bool_t do_timestamp;
277 bool_t do_dcd_timestamp;
278 struct timeval timestamp;
279 struct timeval dcd_timestamp;
280 struct pps_state pps;
281
282 u_long bytes_in; /* statistics */
283 u_long bytes_out;
284 u_int delta_error_counts[CE_NTYPES];
285 u_long error_counts[CE_NTYPES];
286
287 /*
288 * Ping-pong input buffers. The extra factor of 2 in the sizes is
289 * to allow for an error byte for each input byte.
290 */
291 #define CE_INPUT_OFFSET RS_IBUFSIZE
292 u_char ibuf1[2 * RS_IBUFSIZE];
293 u_char ibuf2[2 * RS_IBUFSIZE];
294
295 /*
296 * Data area for output buffers. Someday we should build the output
297 * buffer queue without copying data.
298 */
299 u_char obuf1[256];
300 u_char obuf2[256];
301 #ifdef DEVFS
302 void *devfs_token_ttyd;
303 void *devfs_token_ttyl;
304 void *devfs_token_ttyi;
305 void *devfs_token_cuaa;
306 void *devfs_token_cual;
307 void *devfs_token_cuai;
308 #endif
309 };
310
311 #ifdef COM_ESP
312 static int espattach __P((struct isa_device *isdp, struct com_s *com,
313 Port_t esp_port));
314 #endif
315 static int sioattach __P((struct isa_device *dev));
316 static timeout_t siobusycheck;
317 static timeout_t siodtrwakeup;
318 static void comhardclose __P((struct com_s *com));
319 static ointhand2_t siointr;
320 static void siointr1 __P((struct com_s *com));
321 static int commctl __P((struct com_s *com, int bits, int how));
322 static int comparam __P((struct tty *tp, struct termios *t));
323 static swihand_t siopoll;
324 static int sioprobe __P((struct isa_device *dev));
325 static void siosettimeout __P((void));
326 static void comstart __P((struct tty *tp));
327 static timeout_t comwakeup;
328 static void disc_optim __P((struct tty *tp, struct termios *t,
329 struct com_s *com));
330
331
332 static char driver_name[] = "sio";
333
334 /* table and macro for fast conversion from a unit number to its com struct */
335 static struct com_s *p_com_addr[NSIOTOT];
336 #define com_addr(unit) (p_com_addr[unit])
337
338 struct isa_driver siodriver = {
339 sioprobe, sioattach, driver_name
340 };
341
342 static d_open_t sioopen;
343 static d_close_t sioclose;
344 static d_read_t sioread;
345 static d_write_t siowrite;
346 static d_ioctl_t sioioctl;
347 static d_stop_t siostop;
348 static d_devtotty_t siodevtotty;
349
350 #define CDEV_MAJOR 28
351 static struct cdevsw sio_cdevsw = {
352 sioopen, sioclose, sioread, siowrite,
353 sioioctl, siostop, noreset, siodevtotty,
354 ttpoll, nommap, NULL, driver_name,
355 NULL, -1, nodump, nopsize,
356 D_TTY,
357 };
358
359 static int comconsole = -1;
360 static volatile speed_t comdefaultrate = CONSPEED;
361 static u_int com_events; /* input chars + weighted output completions */
362 static Port_t siocniobase;
363 static bool_t sio_registered;
364 static int sio_timeout;
365 static int sio_timeouts_until_log;
366 static struct callout_handle sio_timeout_handle
367 = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
368 #if 0 /* XXX */
369 static struct tty *sio_tty[NSIOTOT];
370 #else
371 static struct tty sio_tty[NSIOTOT];
372 #endif
373 static const int nsio_tty = NSIOTOT;
374
375 static struct speedtab comspeedtab[] = {
376 { 0, 0 },
377 { 50, COMBRD(50) },
378 { 75, COMBRD(75) },
379 { 110, COMBRD(110) },
380 { 134, COMBRD(134) },
381 { 150, COMBRD(150) },
382 { 200, COMBRD(200) },
383 { 300, COMBRD(300) },
384 { 600, COMBRD(600) },
385 { 1200, COMBRD(1200) },
386 { 1800, COMBRD(1800) },
387 { 2400, COMBRD(2400) },
388 { 4800, COMBRD(4800) },
389 { 9600, COMBRD(9600) },
390 { 19200, COMBRD(19200) },
391 { 38400, COMBRD(38400) },
392 { 57600, COMBRD(57600) },
393 { 115200, COMBRD(115200) },
394 { -1, -1 }
395 };
396
397 #ifdef COM_ESP
398 /* XXX configure this properly. */
399 static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
400 static Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
401 #endif
402
403 /*
404 * handle sysctl read/write requests for console speed
405 *
406 * In addition to setting comdefaultrate for I/O through /dev/console,
407 * also set the initial and lock values for the /dev/ttyXX device
408 * if there is one associated with the console. Finally, if the /dev/tty
409 * device has already been open, change the speed on the open running port
410 * itself.
411 */
412
413 static int
414 sysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS
415 {
416 int error, s;
417 speed_t newspeed;
418 struct com_s *com;
419 struct tty *tp;
420
421 newspeed = comdefaultrate;
422
423 error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
424 if (error || !req->newptr)
425 return (error);
426
427 comdefaultrate = newspeed;
428
429 if (comconsole < 0) /* serial console not selected? */
430 return (0);
431
432 com = com_addr(comconsole);
433 if (!com)
434 return (ENXIO);
435
436 /*
437 * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
438 * (note, the lock rates really are boolean -- if non-zero, disallow
439 * speed changes)
440 */
441 com->it_in.c_ispeed = com->it_in.c_ospeed =
442 com->lt_in.c_ispeed = com->lt_in.c_ospeed =
443 com->it_out.c_ispeed = com->it_out.c_ospeed =
444 com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate;
445
446 /*
447 * if we're open, change the running rate too
448 */
449 tp = com->tp;
450 if (tp && (tp->t_state & TS_ISOPEN)) {
451 tp->t_termios.c_ispeed =
452 tp->t_termios.c_ospeed = comdefaultrate;
453 s = spltty();
454 error = comparam(tp, &tp->t_termios);
455 splx(s);
456 }
457 return error;
458 }
459
460 SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
461 0, 0, sysctl_machdep_comdefaultrate, "I", "");
462
463 #if NCARD > 0
464 /*
465 * PC-Card (PCMCIA) specific code.
466 */
467 static int sioinit __P((struct pccard_devinfo *));
468 static void siounload __P((struct pccard_devinfo *));
469 static int card_intr __P((struct pccard_devinfo *));
470
471 PCCARD_MODULE(sio, sioinit, siounload, card_intr, 0, tty_imask);
472
473 /*
474 * Initialize the device - called from Slot manager.
475 */
476 int
477 sioinit(struct pccard_devinfo *devi)
478 {
479
480 /* validate unit number. */
481 if (devi->isahd.id_unit >= (NSIOTOT))
482 return(ENODEV);
483 /* Make sure it isn't already probed. */
484 if (com_addr(devi->isahd.id_unit))
485 return(EBUSY);
486
487 /* It's already probed as serial by Upper */
488 devi->isahd.id_flags |= COM_C_NOPROBE;
489
490 /*
491 * Probe the device. If a value is returned, the
492 * device was found at the location.
493 */
494 if (sioprobe(&devi->isahd) == 0)
495 return(ENXIO);
496 if (sioattach(&devi->isahd) == 0)
497 return(ENXIO);
498
499 return(0);
500 }
501
502 /*
503 * siounload - unload the driver and clear the table.
504 * XXX TODO:
505 * This is usually called when the card is ejected, but
506 * can be caused by a modunload of a controller driver.
507 * The idea is to reset the driver's view of the device
508 * and ensure that any driver entry points such as
509 * read and write do not hang.
510 */
511 static void
512 siounload(struct pccard_devinfo *devi)
513 {
514 struct com_s *com;
515
516 if (!devi) {
517 printf("NULL devi in siounload\n");
518 return;
519 }
520 com = com_addr(devi->isahd.id_unit);
521 if (!com) {
522 printf("NULL com in siounload\n");
523 return;
524 }
525 if (!com->iobase) {
526 printf("sio%d already unloaded!\n",devi->isahd.id_unit);
527 return;
528 }
529 if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
530 com->gone = 1;
531 printf("sio%d: unload\n", devi->isahd.id_unit);
532 com->tp->t_gen++;
533 ttyclose(com->tp);
534 ttwakeup(com->tp);
535 ttwwakeup(com->tp);
536 } else {
537 com_addr(com->unit) = NULL;
538 bzero(com, sizeof *com);
539 free(com,M_TTYS);
540 printf("sio%d: unload,gone\n", devi->isahd.id_unit);
541 }
542 }
543
544 /*
545 * card_intr - Shared interrupt called from
546 * front end of PC-Card handler.
547 */
548 static int
549 card_intr(struct pccard_devinfo *devi)
550 {
551 struct com_s *com;
552
553 COM_LOCK();
554 com = com_addr(devi->isahd.id_unit);
555 if (com && !com->gone)
556 siointr1(com_addr(devi->isahd.id_unit));
557 COM_UNLOCK();
558 return(1);
559 }
560 #endif /* NCARD > 0 */
561
562 static int
563 sioprobe(dev)
564 struct isa_device *dev;
565 {
566 static bool_t already_init;
567 bool_t failures[10];
568 int fn;
569 struct isa_device *idev;
570 Port_t iobase;
571 intrmask_t irqmap[4];
572 intrmask_t irqs;
573 u_char mcr_image;
574 int result;
575 struct isa_device *xdev;
576
577 if (!already_init) {
578 /*
579 * Turn off MCR_IENABLE for all likely serial ports. An unused
580 * port with its MCR_IENABLE gate open will inhibit interrupts
581 * from any used port that shares the interrupt vector.
582 * XXX the gate enable is elsewhere for some multiports.
583 */
584 for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++)
585 if (xdev->id_driver == &siodriver && xdev->id_enabled)
586 outb(xdev->id_iobase + com_mcr, 0);
587 already_init = TRUE;
588 }
589
590 if (COM_LLCONSOLE(dev)) {
591 printf("sio%d: reserved for low-level i/o\n", dev->id_unit);
592 return (0);
593 }
594
595 /*
596 * If the device is on a multiport card and has an AST/4
597 * compatible interrupt control register, initialize this
598 * register and prepare to leave MCR_IENABLE clear in the mcr.
599 * Otherwise, prepare to set MCR_IENABLE in the mcr.
600 * Point idev to the device struct giving the correct id_irq.
601 * This is the struct for the master device if there is one.
602 */
603 idev = dev;
604 mcr_image = MCR_IENABLE;
605 #ifdef COM_MULTIPORT
606 if (COM_ISMULTIPORT(dev)) {
607 idev = find_isadev(isa_devtab_tty, &siodriver,
608 COM_MPMASTER(dev));
609 if (idev == NULL) {
610 printf("sio%d: master device %d not configured\n",
611 dev->id_unit, COM_MPMASTER(dev));
612 dev->id_irq = 0;
613 idev = dev;
614 }
615 if (!COM_NOTAST4(dev)) {
616 outb(idev->id_iobase + com_scr,
617 idev->id_irq ? 0x80 : 0);
618 mcr_image = 0;
619 }
620 }
621 #endif /* COM_MULTIPORT */
622 if (idev->id_irq == 0)
623 mcr_image = 0;
624
625 bzero(failures, sizeof failures);
626 iobase = dev->id_iobase;
627
628 /*
629 * We don't want to get actual interrupts, just masked ones.
630 * Interrupts from this line should already be masked in the ICU,
631 * but mask them in the processor as well in case there are some
632 * (misconfigured) shared interrupts.
633 */
634 disable_intr();
635 /* EXTRA DELAY? */
636
637 /*
638 * Initialize the speed and the word size and wait long enough to
639 * drain the maximum of 16 bytes of junk in device output queues.
640 * The speed is undefined after a master reset and must be set
641 * before relying on anything related to output. There may be
642 * junk after a (very fast) soft reboot and (apparently) after
643 * master reset.
644 * XXX what about the UART bug avoided by waiting in comparam()?
645 * We don't want to to wait long enough to drain at 2 bps.
646 */
647 if (iobase == siocniobase)
648 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
649 else {
650 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
651 outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff);
652 outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8);
653 outb(iobase + com_cfcr, CFCR_8BITS);
654 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
655 }
656
657 /*
658 * Enable the interrupt gate and disable device interupts. This
659 * should leave the device driving the interrupt line low and
660 * guarantee an edge trigger if an interrupt can be generated.
661 */
662 /* EXTRA DELAY? */
663 outb(iobase + com_mcr, mcr_image);
664 outb(iobase + com_ier, 0);
665 DELAY(1000); /* XXX */
666 irqmap[0] = isa_irq_pending();
667
668 /*
669 * Attempt to set loopback mode so that we can send a null byte
670 * without annoying any external device.
671 */
672 /* EXTRA DELAY? */
673 outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
674
675 /*
676 * Attempt to generate an output interrupt. On 8250's, setting
677 * IER_ETXRDY generates an interrupt independent of the current
678 * setting and independent of whether the THR is empty. On 16450's,
679 * setting IER_ETXRDY generates an interrupt independent of the
680 * current setting. On 16550A's, setting IER_ETXRDY only
681 * generates an interrupt when IER_ETXRDY is not already set.
682 */
683 outb(iobase + com_ier, IER_ETXRDY);
684
685 /*
686 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
687 * an interrupt. They'd better generate one for actually doing
688 * output. Loopback may be broken on the same incompatibles but
689 * it's unlikely to do more than allow the null byte out.
690 */
691 outb(iobase + com_data, 0);
692 DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
693
694 /*
695 * Turn off loopback mode so that the interrupt gate works again
696 * (MCR_IENABLE was hidden). This should leave the device driving
697 * an interrupt line high. It doesn't matter if the interrupt
698 * line oscillates while we are not looking at it, since interrupts
699 * are disabled.
700 */
701 /* EXTRA DELAY? */
702 outb(iobase + com_mcr, mcr_image);
703
704 /*
705 * It's a definitly Serial PCMCIA(16550A), but still be required
706 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
707 */
708 if ( COM_NOPROBE(dev) ) {
709 /* Reading IIR register twice */
710 for ( fn = 0; fn < 2; fn ++ ) {
711 DELAY(10000);
712 failures[6] = inb(iobase + com_iir);
713 }
714 /* Check IIR_TXRDY clear ? */
715 result = IO_COMSIZE;
716 if ( failures[6] & IIR_TXRDY ) {
717 /* Nop, Double check with clearing IER */
718 outb(iobase + com_ier, 0);
719 if ( inb(iobase + com_iir) & IIR_NOPEND ) {
720 /* Ok. we're familia this gang */
721 dev->id_flags |= COM_C_IIR_TXRDYBUG; /* Set IIR_TXRDYBUG */
722 } else {
723 /* Unknow, Just omit this chip.. XXX*/
724 result = 0;
725 }
726 } else {
727 /* OK. this is well-known guys */
728 dev->id_flags &= ~COM_C_IIR_TXRDYBUG; /*Clear IIR_TXRDYBUG*/
729 }
730 outb(iobase + com_cfcr, CFCR_8BITS);
731 enable_intr();
732 return (iobase == siocniobase ? IO_COMSIZE : result);
733 }
734
735 /*
736 * Check that
737 * o the CFCR, IER and MCR in UART hold the values written to them
738 * (the values happen to be all distinct - this is good for
739 * avoiding false positive tests from bus echoes).
740 * o an output interrupt is generated and its vector is correct.
741 * o the interrupt goes away when the IIR in the UART is read.
742 */
743 /* EXTRA DELAY? */
744 failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
745 failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
746 failures[2] = inb(iobase + com_mcr) - mcr_image;
747 DELAY(10000); /* Some internal modems need this time */
748 irqmap[1] = isa_irq_pending();
749 failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
750 DELAY(1000); /* XXX */
751 irqmap[2] = isa_irq_pending();
752 failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
753
754 /*
755 * Turn off all device interrupts and check that they go off properly.
756 * Leave MCR_IENABLE alone. For ports without a master port, it gates
757 * the OUT2 output of the UART to
758 * the ICU input. Closing the gate would give a floating ICU input
759 * (unless there is another device driving it) and spurious interrupts.
760 * (On the system that this was first tested on, the input floats high
761 * and gives a (masked) interrupt as soon as the gate is closed.)
762 */
763 outb(iobase + com_ier, 0);
764 outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */
765 failures[7] = inb(iobase + com_ier);
766 DELAY(1000); /* XXX */
767 irqmap[3] = isa_irq_pending();
768 failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
769
770 enable_intr();
771
772 irqs = irqmap[1] & ~irqmap[0];
773 if (idev->id_irq != 0 && (idev->id_irq & irqs) == 0)
774 printf(
775 "sio%d: configured irq %d not in bitmap of probed irqs %#x\n",
776 dev->id_unit, ffs(idev->id_irq) - 1, irqs);
777 if (bootverbose)
778 printf("sio%d: irq maps: %#x %#x %#x %#x\n",
779 dev->id_unit, irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
780
781 result = IO_COMSIZE;
782 for (fn = 0; fn < sizeof failures; ++fn)
783 if (failures[fn]) {
784 outb(iobase + com_mcr, 0);
785 result = 0;
786 if (bootverbose) {
787 printf("sio%d: probe failed test(s):",
788 dev->id_unit);
789 for (fn = 0; fn < sizeof failures; ++fn)
790 if (failures[fn])
791 printf(" %d", fn);
792 printf("\n");
793 }
794 break;
795 }
796 return (iobase == siocniobase ? IO_COMSIZE : result);
797 }
798
799 #ifdef COM_ESP
800 static int
801 espattach(isdp, com, esp_port)
802 struct isa_device *isdp;
803 struct com_s *com;
804 Port_t esp_port;
805 {
806 u_char dips;
807 u_char val;
808
809 /*
810 * Check the ESP-specific I/O port to see if we're an ESP
811 * card. If not, return failure immediately.
812 */
813 if ((inb(esp_port) & 0xf3) == 0) {
814 printf(" port 0x%x is not an ESP board?\n", esp_port);
815 return (0);
816 }
817
818 /*
819 * We've got something that claims to be a Hayes ESP card.
820 * Let's hope so.
821 */
822
823 /* Get the dip-switch configuration */
824 outb(esp_port + ESP_CMD1, ESP_GETDIPS);
825 dips = inb(esp_port + ESP_STATUS1);
826
827 /*
828 * Bits 0,1 of dips say which COM port we are.
829 */
830 if (com->iobase == likely_com_ports[dips & 0x03])
831 printf(" : ESP");
832 else {
833 printf(" esp_port has com %d\n", dips & 0x03);
834 return (0);
835 }
836
837 /*
838 * Check for ESP version 2.0 or later: bits 4,5,6 = 010.
839 */
840 outb(esp_port + ESP_CMD1, ESP_GETTEST);
841 val = inb(esp_port + ESP_STATUS1); /* clear reg 1 */
842 val = inb(esp_port + ESP_STATUS2);
843 if ((val & 0x70) < 0x20) {
844 printf("-old (%o)", val & 0x70);
845 return (0);
846 }
847
848 /*
849 * Check for ability to emulate 16550: bit 7 == 1
850 */
851 if ((dips & 0x80) == 0) {
852 printf(" slave");
853 return (0);
854 }
855
856 /*
857 * Okay, we seem to be a Hayes ESP card. Whee.
858 */
859 com->esp = TRUE;
860 com->esp_port = esp_port;
861 return (1);
862 }
863 #endif /* COM_ESP */
864
865 static int
866 sioattach(isdp)
867 struct isa_device *isdp;
868 {
869 struct com_s *com;
870 dev_t dev;
871 #ifdef COM_ESP
872 Port_t *espp;
873 #endif
874 #ifdef COM_MULTIPORT
875 struct isa_device *idev;
876 #endif
877 Port_t iobase;
878 int s;
879 int unit;
880
881 isdp->id_ointr = siointr;
882 isdp->id_ri_flags |= RI_FAST;
883 iobase = isdp->id_iobase;
884 unit = isdp->id_unit;
885 com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
886 if (com == NULL)
887 return (0);
888
889 /*
890 * sioprobe() has initialized the device registers as follows:
891 * o cfcr = CFCR_8BITS.
892 * It is most important that CFCR_DLAB is off, so that the
893 * data port is not hidden when we enable interrupts.
894 * o ier = 0.
895 * Interrupts are only enabled when the line is open.
896 * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
897 * interrupt control register or the config specifies no irq.
898 * Keeping MCR_DTR and MCR_RTS off might stop the external
899 * device from sending before we are ready.
900 */
901 bzero(com, sizeof *com);
902 com->unit = unit;
903 com->cfcr_image = CFCR_8BITS;
904 com->dtr_wait = 3 * hz;
905 com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
906 com->no_irq = isdp->id_irq == 0;
907 com->tx_fifo_size = 1;
908 com->iptr = com->ibuf = com->ibuf1;
909 com->ibufend = com->ibuf1 + RS_IBUFSIZE;
910 com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
911 com->obufs[0].l_head = com->obuf1;
912 com->obufs[1].l_head = com->obuf2;
913
914 com->iobase = iobase;
915 com->data_port = iobase + com_data;
916 com->int_id_port = iobase + com_iir;
917 com->modem_ctl_port = iobase + com_mcr;
918 com->mcr_image = inb(com->modem_ctl_port);
919 com->line_status_port = iobase + com_lsr;
920 com->modem_status_port = iobase + com_msr;
921 com->intr_ctl_port = iobase + com_ier;
922
923 /*
924 * We don't use all the flags from <sys/ttydefaults.h> since they
925 * are only relevant for logins. It's important to have echo off
926 * initially so that the line doesn't start blathering before the
927 * echo flag can be turned off.
928 */
929 com->it_in.c_iflag = 0;
930 com->it_in.c_oflag = 0;
931 com->it_in.c_cflag = TTYDEF_CFLAG;
932 com->it_in.c_lflag = 0;
933 if (unit == comconsole) {
934 com->it_in.c_iflag = TTYDEF_IFLAG;
935 com->it_in.c_oflag = TTYDEF_OFLAG;
936 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
937 com->it_in.c_lflag = TTYDEF_LFLAG;
938 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
939 com->lt_out.c_ispeed = com->lt_out.c_ospeed =
940 com->lt_in.c_ispeed = com->lt_in.c_ospeed =
941 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
942 } else
943 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
944 termioschars(&com->it_in);
945 com->it_out = com->it_in;
946
947 /* attempt to determine UART type */
948 printf("sio%d: type", unit);
949
950
951 #ifdef COM_MULTIPORT
952 if (!COM_ISMULTIPORT(isdp) && !COM_IIR_TXRDYBUG(isdp))
953 #else
954 if (!COM_IIR_TXRDYBUG(isdp))
955 #endif
956 {
957 u_char scr;
958 u_char scr1;
959 u_char scr2;
960
961 scr = inb(iobase + com_scr);
962 outb(iobase + com_scr, 0xa5);
963 scr1 = inb(iobase + com_scr);
964 outb(iobase + com_scr, 0x5a);
965 scr2 = inb(iobase + com_scr);
966 outb(iobase + com_scr, scr);
967 if (scr1 != 0xa5 || scr2 != 0x5a) {
968 printf(" 8250");
969 goto determined_type;
970 }
971 }
972 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
973 DELAY(100);
974 com->st16650a = 0;
975 switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
976 case FIFO_RX_LOW:
977 printf(" 16450");
978 break;
979 case FIFO_RX_MEDL:
980 printf(" 16450?");
981 break;
982 case FIFO_RX_MEDH:
983 printf(" 16550?");
984 break;
985 case FIFO_RX_HIGH:
986 if (COM_NOFIFO(isdp)) {
987 printf(" 16550A fifo disabled");
988 } else {
989 com->hasfifo = TRUE;
990 if (COM_ST16650A(isdp)) {
991 com->st16650a = 1;
992 com->tx_fifo_size = 32;
993 printf(" ST16650A");
994 } else {
995 com->tx_fifo_size = COM_FIFOSIZE(isdp);
996 printf(" 16550A");
997 }
998 }
999 #ifdef COM_ESP
1000 for (espp = likely_esp_ports; *espp != 0; espp++)
1001 if (espattach(isdp, com, *espp)) {
1002 com->tx_fifo_size = 1024;
1003 break;
1004 }
1005 #endif
1006 if (!com->st16650a) {
1007 if (!com->tx_fifo_size)
1008 com->tx_fifo_size = 16;
1009 else
1010 printf(" lookalike with %d bytes FIFO",
1011 com->tx_fifo_size);
1012 }
1013
1014 break;
1015 }
1016
1017 #ifdef COM_ESP
1018 if (com->esp) {
1019 /*
1020 * Set 16550 compatibility mode.
1021 * We don't use the ESP_MODE_SCALE bit to increase the
1022 * fifo trigger levels because we can't handle large
1023 * bursts of input.
1024 * XXX flow control should be set in comparam(), not here.
1025 */
1026 outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1027 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1028
1029 /* Set RTS/CTS flow control. */
1030 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1031 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1032 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1033
1034 /* Set flow-control levels. */
1035 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1036 outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1037 outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1038 outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1039 outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1040 }
1041 #endif /* COM_ESP */
1042 outb(iobase + com_fifo, 0);
1043 determined_type: ;
1044
1045 #ifdef COM_MULTIPORT
1046 if (COM_ISMULTIPORT(isdp)) {
1047 com->multiport = TRUE;
1048 printf(" (multiport");
1049 if (unit == COM_MPMASTER(isdp))
1050 printf(" master");
1051 printf(")");
1052 idev = find_isadev(isa_devtab_tty, &siodriver,
1053 COM_MPMASTER(isdp));
1054 com->no_irq = (idev == NULL || idev->id_irq == 0);
1055 }
1056 #endif /* COM_MULTIPORT */
1057 if (unit == comconsole)
1058 printf(", console");
1059 if ( COM_IIR_TXRDYBUG(isdp) )
1060 printf(" with a bogus IIR_TXRDY register");
1061 printf("\n");
1062
1063 s = spltty();
1064 com_addr(unit) = com;
1065 splx(s);
1066
1067 if (!sio_registered) {
1068 dev = makedev(CDEV_MAJOR, 0);
1069 cdevsw_add(&dev, &sio_cdevsw, NULL);
1070 register_swi(SWI_TTY, siopoll);
1071 sio_registered = TRUE;
1072 }
1073 #ifdef DEVFS
1074 com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
1075 unit, DV_CHR,
1076 UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit);
1077 com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
1078 unit | CONTROL_INIT_STATE, DV_CHR,
1079 UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit);
1080 com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
1081 unit | CONTROL_LOCK_STATE, DV_CHR,
1082 UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit);
1083 com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
1084 unit | CALLOUT_MASK, DV_CHR,
1085 UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit);
1086 com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
1087 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
1088 UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit);
1089 com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
1090 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
1091 UID_UUCP, GID_DIALER, 0660, "cuala%r", unit);
1092 #endif
1093 com->id_flags = isdp->id_flags; /* Heritate id_flags for later */
1094 com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
1095 pps_init(&com->pps);
1096 return (1);
1097 }
1098
1099 static int
1100 sioopen(dev, flag, mode, p)
1101 dev_t dev;
1102 int flag;
1103 int mode;
1104 struct proc *p;
1105 {
1106 struct com_s *com;
1107 int error;
1108 Port_t iobase;
1109 int mynor;
1110 int s;
1111 struct tty *tp;
1112 int unit;
1113
1114 mynor = minor(dev);
1115 unit = MINOR_TO_UNIT(mynor);
1116 if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL)
1117 return (ENXIO);
1118 if (com->gone)
1119 return (ENXIO);
1120 if (mynor & CONTROL_MASK)
1121 return (0);
1122 #if 0 /* XXX */
1123 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
1124 #else
1125 tp = com->tp = &sio_tty[unit];
1126 #endif
1127 s = spltty();
1128 /*
1129 * We jump to this label after all non-interrupted sleeps to pick
1130 * up any changes of the device state.
1131 */
1132 open_top:
1133 while (com->state & CS_DTR_OFF) {
1134 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
1135 if (com_addr(unit) == NULL)
1136 return (ENXIO);
1137 if (error != 0 || com->gone)
1138 goto out;
1139 }
1140 if (tp->t_state & TS_ISOPEN) {
1141 /*
1142 * The device is open, so everything has been initialized.
1143 * Handle conflicts.
1144 */
1145 if (mynor & CALLOUT_MASK) {
1146 if (!com->active_out) {
1147 error = EBUSY;
1148 goto out;
1149 }
1150 } else {
1151 if (com->active_out) {
1152 if (flag & O_NONBLOCK) {
1153 error = EBUSY;
1154 goto out;
1155 }
1156 error = tsleep(&com->active_out,
1157 TTIPRI | PCATCH, "siobi", 0);
1158 if (com_addr(unit) == NULL)
1159 return (ENXIO);
1160 if (error != 0 || com->gone)
1161 goto out;
1162 goto open_top;
1163 }
1164 }
1165 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
1166 error = EBUSY;
1167 goto out;
1168 }
1169 } else {
1170 /*
1171 * The device isn't open, so there are no conflicts.
1172 * Initialize it. Initialization is done twice in many
1173 * cases: to preempt sleeping callin opens if we are
1174 * callout, and to complete a callin open after DCD rises.
1175 */
1176 tp->t_oproc = comstart;
1177 tp->t_param = comparam;
1178 tp->t_dev = dev;
1179 tp->t_termios = mynor & CALLOUT_MASK
1180 ? com->it_out : com->it_in;
1181 tp->t_ififosize = 2 * RS_IBUFSIZE;
1182 tp->t_ispeedwat = (speed_t)-1;
1183 tp->t_ospeedwat = (speed_t)-1;
1184 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
1185 com->poll = com->no_irq;
1186 com->poll_output = com->loses_outints;
1187 ++com->wopeners;
1188 error = comparam(tp, &tp->t_termios);
1189 --com->wopeners;
1190 if (error != 0)
1191 goto out;
1192 /*
1193 * XXX we should goto open_top if comparam() slept.
1194 */
1195 iobase = com->iobase;
1196 if (com->hasfifo) {
1197 /*
1198 * (Re)enable and drain fifos.
1199 *
1200 * Certain SMC chips cause problems if the fifos
1201 * are enabled while input is ready. Turn off the
1202 * fifo if necessary to clear the input. We test
1203 * the input ready bit after enabling the fifos
1204 * since we've already enabled them in comparam()
1205 * and to handle races between enabling and fresh
1206 * input.
1207 */
1208 while (TRUE) {
1209 outb(iobase + com_fifo,
1210 FIFO_RCV_RST | FIFO_XMT_RST
1211 | com->fifo_image);
1212 /*
1213 * XXX the delays are for superstitious
1214 * historical reasons. It must be less than
1215 * the character time at the maximum
1216 * supported speed (87 usec at 115200 bps
1217 * 8N1). Otherwise we might loop endlessly
1218 * if data is streaming in. We used to use
1219 * delays of 100. That usually worked
1220 * because DELAY(100) used to usually delay
1221 * for about 85 usec instead of 100.
1222 */
1223 DELAY(50);
1224 if (!(inb(com->line_status_port) & LSR_RXRDY))
1225 break;
1226 outb(iobase + com_fifo, 0);
1227 DELAY(50);
1228 (void) inb(com->data_port);
1229 }
1230 }
1231
1232 disable_intr();
1233 (void) inb(com->line_status_port);
1234 (void) inb(com->data_port);
1235 com->prev_modem_status = com->last_modem_status
1236 = inb(com->modem_status_port);
1237 if (COM_IIR_TXRDYBUG(com)) {
1238 outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
1239 | IER_EMSC);
1240 } else {
1241 outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
1242 | IER_ERLS | IER_EMSC);
1243 }
1244 enable_intr();
1245 /*
1246 * Handle initial DCD. Callout devices get a fake initial
1247 * DCD (trapdoor DCD). If we are callout, then any sleeping
1248 * callin opens get woken up and resume sleeping on "siobi"
1249 * instead of "siodcd".
1250 */
1251 /*
1252 * XXX `mynor & CALLOUT_MASK' should be
1253 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
1254 * TRAPDOOR_CARRIER is the default initial state for callout
1255 * devices and SOFT_CARRIER is like CLOCAL except it hides
1256 * the true carrier.
1257 */
1258 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
1259 (*linesw[tp->t_line].l_modem)(tp, 1);
1260 }
1261 /*
1262 * Wait for DCD if necessary.
1263 */
1264 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1265 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1266 ++com->wopeners;
1267 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
1268 if (com_addr(unit) == NULL)
1269 return (ENXIO);
1270 --com->wopeners;
1271 if (error != 0 || com->gone)
1272 goto out;
1273 goto open_top;
1274 }
1275 error = (*linesw[tp->t_line].l_open)(dev, tp);
1276 disc_optim(tp, &tp->t_termios, com);
1277 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1278 com->active_out = TRUE;
1279 siosettimeout();
1280 out:
1281 splx(s);
1282 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
1283 comhardclose(com);
1284 return (error);
1285 }
1286
1287 static int
1288 sioclose(dev, flag, mode, p)
1289 dev_t dev;
1290 int flag;
1291 int mode;
1292 struct proc *p;
1293 {
1294 struct com_s *com;
1295 int mynor;
1296 int s;
1297 struct tty *tp;
1298
1299 mynor = minor(dev);
1300 if (mynor & CONTROL_MASK)
1301 return (0);
1302 com = com_addr(MINOR_TO_UNIT(mynor));
1303 tp = com->tp;
1304 s = spltty();
1305 (*linesw[tp->t_line].l_close)(tp, flag);
1306 disc_optim(tp, &tp->t_termios, com);
1307 siostop(tp, FREAD | FWRITE);
1308 comhardclose(com);
1309 ttyclose(tp);
1310 siosettimeout();
1311 splx(s);
1312 if (com->gone) {
1313 printf("sio%d: gone\n", com->unit);
1314 s = spltty();
1315 com_addr(com->unit) = 0;
1316 bzero(tp,sizeof *tp);
1317 bzero(com,sizeof *com);
1318 free(com,M_TTYS);
1319 splx(s);
1320 }
1321 return (0);
1322 }
1323
1324 static void
1325 comhardclose(com)
1326 struct com_s *com;
1327 {
1328 Port_t iobase;
1329 int s;
1330 struct tty *tp;
1331 int unit;
1332
1333 unit = com->unit;
1334 iobase = com->iobase;
1335 s = spltty();
1336 com->poll = FALSE;
1337 com->poll_output = FALSE;
1338 com->do_timestamp = FALSE;
1339 com->do_dcd_timestamp = FALSE;
1340 com->pps.ppsparam.mode = 0;
1341 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1342 {
1343 outb(iobase + com_ier, 0);
1344 tp = com->tp;
1345 if (tp->t_cflag & HUPCL
1346 /*
1347 * XXX we will miss any carrier drop between here and the
1348 * next open. Perhaps we should watch DCD even when the
1349 * port is closed; it is not sufficient to check it at
1350 * the next open because it might go up and down while
1351 * we're not watching.
1352 */
1353 || !com->active_out
1354 && !(com->prev_modem_status & MSR_DCD)
1355 && !(com->it_in.c_cflag & CLOCAL)
1356 || !(tp->t_state & TS_ISOPEN)) {
1357 (void)commctl(com, TIOCM_DTR, DMBIC);
1358 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
1359 timeout(siodtrwakeup, com, com->dtr_wait);
1360 com->state |= CS_DTR_OFF;
1361 }
1362 }
1363 }
1364 if (com->hasfifo) {
1365 /*
1366 * Disable fifos so that they are off after controlled
1367 * reboots. Some BIOSes fail to detect 16550s when the
1368 * fifos are enabled.
1369 */
1370 outb(iobase + com_fifo, 0);
1371 }
1372 com->active_out = FALSE;
1373 wakeup(&com->active_out);
1374 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
1375 splx(s);
1376 }
1377
1378 static int
1379 sioread(dev, uio, flag)
1380 dev_t dev;
1381 struct uio *uio;
1382 int flag;
1383 {
1384 int mynor;
1385 int unit;
1386 struct tty *tp;
1387
1388 mynor = minor(dev);
1389 if (mynor & CONTROL_MASK)
1390 return (ENODEV);
1391 unit = MINOR_TO_UNIT(mynor);
1392 if (com_addr(unit)->gone)
1393 return (ENODEV);
1394 tp = com_addr(unit)->tp;
1395 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1396 }
1397
1398 static int
1399 siowrite(dev, uio, flag)
1400 dev_t dev;
1401 struct uio *uio;
1402 int flag;
1403 {
1404 int mynor;
1405 struct tty *tp;
1406 int unit;
1407
1408 mynor = minor(dev);
1409 if (mynor & CONTROL_MASK)
1410 return (ENODEV);
1411
1412 unit = MINOR_TO_UNIT(mynor);
1413 if (com_addr(unit)->gone)
1414 return (ENODEV);
1415 tp = com_addr(unit)->tp;
1416 /*
1417 * (XXX) We disallow virtual consoles if the physical console is
1418 * a serial port. This is in case there is a display attached that
1419 * is not the console. In that situation we don't need/want the X
1420 * server taking over the console.
1421 */
1422 if (constty != NULL && unit == comconsole)
1423 constty = NULL;
1424 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
1425 }
1426
1427 static void
1428 siobusycheck(chan)
1429 void *chan;
1430 {
1431 struct com_s *com;
1432 int s;
1433
1434 com = (struct com_s *)chan;
1435
1436 /*
1437 * Clear TS_BUSY if low-level output is complete.
1438 * spl locking is sufficient because siointr1() does not set CS_BUSY.
1439 * If siointr1() clears CS_BUSY after we look at it, then we'll get
1440 * called again. Reading the line status port outside of siointr1()
1441 * is safe because CS_BUSY is clear so there are no output interrupts
1442 * to lose.
1443 */
1444 s = spltty();
1445 if (com->state & CS_BUSY)
1446 com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */
1447 else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1448 == (LSR_TSRE | LSR_TXRDY)) {
1449 com->tp->t_state &= ~TS_BUSY;
1450 ttwwakeup(com->tp);
1451 com->extra_state &= ~CSE_BUSYCHECK;
1452 } else
1453 timeout(siobusycheck, com, hz / 100);
1454 splx(s);
1455 }
1456
1457 static void
1458 siodtrwakeup(chan)
1459 void *chan;
1460 {
1461 struct com_s *com;
1462
1463 com = (struct com_s *)chan;
1464 com->state &= ~CS_DTR_OFF;
1465 wakeup(&com->dtr_wait);
1466 }
1467
1468 static void
1469 siointr(unit)
1470 int unit;
1471 {
1472 #ifndef COM_MULTIPORT
1473 COM_LOCK();
1474 siointr1(com_addr(unit));
1475 COM_UNLOCK();
1476 #else /* COM_MULTIPORT */
1477 struct com_s *com;
1478 bool_t possibly_more_intrs;
1479
1480 /*
1481 * Loop until there is no activity on any port. This is necessary
1482 * to get an interrupt edge more than to avoid another interrupt.
1483 * If the IRQ signal is just an OR of the IRQ signals from several
1484 * devices, then the edge from one may be lost because another is
1485 * on.
1486 */
1487 COM_LOCK();
1488 do {
1489 possibly_more_intrs = FALSE;
1490 for (unit = 0; unit < NSIOTOT; ++unit) {
1491 com = com_addr(unit);
1492 /*
1493 * XXX COM_LOCK();
1494 * would it work here, or be counter-productive?
1495 */
1496 if (com != NULL
1497 && !com->gone
1498 && (inb(com->int_id_port) & IIR_IMASK)
1499 != IIR_NOPEND) {
1500 siointr1(com);
1501 possibly_more_intrs = TRUE;
1502 }
1503 /* XXX COM_UNLOCK(); */
1504 }
1505 } while (possibly_more_intrs);
1506 COM_UNLOCK();
1507 #endif /* COM_MULTIPORT */
1508 }
1509
1510 static void
1511 siointr1(com)
1512 struct com_s *com;
1513 {
1514 u_char line_status;
1515 u_char modem_status;
1516 u_char *ioptr;
1517 u_char recv_data;
1518 u_char int_ctl;
1519 u_char int_ctl_new;
1520 struct timecounter *tc;
1521 u_int count;
1522
1523 if (COM_IIR_TXRDYBUG(com)) {
1524 int_ctl = inb(com->intr_ctl_port);
1525 int_ctl_new = int_ctl;
1526 } else {
1527 int_ctl = 0;
1528 int_ctl_new = 0;
1529 }
1530
1531 while (!com->gone) {
1532 if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) {
1533 modem_status = inb(com->modem_status_port);
1534 if ((modem_status ^ com->last_modem_status) & MSR_DCD) {
1535 tc = timecounter;
1536 count = tc->tc_get_timecount(tc);
1537 pps_event(&com->pps, tc, count,
1538 (modem_status & MSR_DCD) ?
1539 PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
1540 }
1541 }
1542 line_status = inb(com->line_status_port);
1543
1544 /* input event? (check first to help avoid overruns) */
1545 while (line_status & LSR_RCV_MASK) {
1546 /* break/unnattached error bits or real input? */
1547 if (!(line_status & LSR_RXRDY))
1548 recv_data = 0;
1549 else
1550 recv_data = inb(com->data_port);
1551 if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
1552 /*
1553 * Don't store BI if IGNBRK or FE/PE if IGNPAR.
1554 * Otherwise, push the work to a higher level
1555 * (to handle PARMRK) if we're bypassing.
1556 * Otherwise, convert BI/FE and PE+INPCK to 0.
1557 *
1558 * This makes bypassing work right in the
1559 * usual "raw" case (IGNBRK set, and IGNPAR
1560 * and INPCK clear).
1561 *
1562 * Note: BI together with FE/PE means just BI.
1563 */
1564 if (line_status & LSR_BI) {
1565 #if defined(DDB) && defined(BREAK_TO_DEBUGGER)
1566 if (com->unit == comconsole) {
1567 breakpoint();
1568 goto cont;
1569 }
1570 #endif
1571 if (com->tp == NULL
1572 || com->tp->t_iflag & IGNBRK)
1573 goto cont;
1574 } else {
1575 if (com->tp == NULL
1576 || com->tp->t_iflag & IGNPAR)
1577 goto cont;
1578 }
1579 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1580 && (line_status & (LSR_BI | LSR_FE)
1581 || com->tp->t_iflag & INPCK))
1582 recv_data = 0;
1583 }
1584 ++com->bytes_in;
1585 if (com->hotchar != 0 && recv_data == com->hotchar)
1586 setsofttty();
1587 ioptr = com->iptr;
1588 if (ioptr >= com->ibufend)
1589 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1590 else {
1591 if (com->do_timestamp)
1592 microtime(&com->timestamp);
1593 ++com_events;
1594 schedsofttty();
1595 #if 0 /* for testing input latency vs efficiency */
1596 if (com->iptr - com->ibuf == 8)
1597 setsofttty();
1598 #endif
1599 ioptr[0] = recv_data;
1600 ioptr[CE_INPUT_OFFSET] = line_status;
1601 com->iptr = ++ioptr;
1602 if (ioptr == com->ihighwater
1603 && com->state & CS_RTS_IFLOW)
1604 outb(com->modem_ctl_port,
1605 com->mcr_image &= ~MCR_RTS);
1606 if (line_status & LSR_OE)
1607 CE_RECORD(com, CE_OVERRUN);
1608 }
1609 cont:
1610 /*
1611 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1612 * jump from the top of the loop to here
1613 */
1614 line_status = inb(com->line_status_port) & 0x7F;
1615 }
1616
1617 /* modem status change? (always check before doing output) */
1618 modem_status = inb(com->modem_status_port);
1619 if (modem_status != com->last_modem_status) {
1620 if (com->do_dcd_timestamp
1621 && !(com->last_modem_status & MSR_DCD)
1622 && modem_status & MSR_DCD)
1623 microtime(&com->dcd_timestamp);
1624
1625 /*
1626 * Schedule high level to handle DCD changes. Note
1627 * that we don't use the delta bits anywhere. Some
1628 * UARTs mess them up, and it's easy to remember the
1629 * previous bits and calculate the delta.
1630 */
1631 com->last_modem_status = modem_status;
1632 if (!(com->state & CS_CHECKMSR)) {
1633 com_events += LOTS_OF_EVENTS;
1634 com->state |= CS_CHECKMSR;
1635 setsofttty();
1636 }
1637
1638 /* handle CTS change immediately for crisp flow ctl */
1639 if (com->state & CS_CTS_OFLOW) {
1640 if (modem_status & MSR_CTS)
1641 com->state |= CS_ODEVREADY;
1642 else
1643 com->state &= ~CS_ODEVREADY;
1644 }
1645 }
1646
1647 /* output queued and everything ready? */
1648 if (line_status & LSR_TXRDY
1649 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1650 ioptr = com->obufq.l_head;
1651 if (com->tx_fifo_size > 1) {
1652 u_int ocount;
1653
1654 ocount = com->obufq.l_tail - ioptr;
1655 if (ocount > com->tx_fifo_size)
1656 ocount = com->tx_fifo_size;
1657 com->bytes_out += ocount;
1658 do
1659 outb(com->data_port, *ioptr++);
1660 while (--ocount != 0);
1661 } else {
1662 outb(com->data_port, *ioptr++);
1663 ++com->bytes_out;
1664 }
1665 com->obufq.l_head = ioptr;
1666 if (COM_IIR_TXRDYBUG(com)) {
1667 int_ctl_new = int_ctl | IER_ETXRDY;
1668 }
1669 if (ioptr >= com->obufq.l_tail) {
1670 struct lbq *qp;
1671
1672 qp = com->obufq.l_next;
1673 qp->l_queued = FALSE;
1674 qp = qp->l_next;
1675 if (qp != NULL) {
1676 com->obufq.l_head = qp->l_head;
1677 com->obufq.l_tail = qp->l_tail;
1678 com->obufq.l_next = qp;
1679 } else {
1680 /* output just completed */
1681 if ( COM_IIR_TXRDYBUG(com) ) {
1682 int_ctl_new = int_ctl & ~IER_ETXRDY;
1683 }
1684 com->state &= ~CS_BUSY;
1685 }
1686 if (!(com->state & CS_ODONE)) {
1687 com_events += LOTS_OF_EVENTS;
1688 com->state |= CS_ODONE;
1689 setsofttty(); /* handle at high level ASAP */
1690 }
1691 }
1692 if ( COM_IIR_TXRDYBUG(com) && (int_ctl != int_ctl_new)) {
1693 outb(com->intr_ctl_port, int_ctl_new);
1694 }
1695 }
1696
1697 /* finished? */
1698 #ifndef COM_MULTIPORT
1699 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
1700 #endif /* COM_MULTIPORT */
1701 return;
1702 }
1703 }
1704
1705 static int
1706 sioioctl(dev, cmd, data, flag, p)
1707 dev_t dev;
1708 u_long cmd;
1709 caddr_t data;
1710 int flag;
1711 struct proc *p;
1712 {
1713 struct com_s *com;
1714 int error;
1715 Port_t iobase;
1716 int mynor;
1717 int s;
1718 struct tty *tp;
1719 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1720 int oldcmd;
1721 struct termios term;
1722 #endif
1723
1724 mynor = minor(dev);
1725 com = com_addr(MINOR_TO_UNIT(mynor));
1726 if (com->gone)
1727 return (ENODEV);
1728 iobase = com->iobase;
1729 if (mynor & CONTROL_MASK) {
1730 struct termios *ct;
1731
1732 switch (mynor & CONTROL_MASK) {
1733 case CONTROL_INIT_STATE:
1734 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1735 break;
1736 case CONTROL_LOCK_STATE:
1737 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1738 break;
1739 default:
1740 return (ENODEV); /* /dev/nodev */
1741 }
1742 switch (cmd) {
1743 case TIOCSETA:
1744 error = suser(p->p_ucred, &p->p_acflag);
1745 if (error != 0)
1746 return (error);
1747 *ct = *(struct termios *)data;
1748 return (0);
1749 case TIOCGETA:
1750 *(struct termios *)data = *ct;
1751 return (0);
1752 case TIOCGETD:
1753 *(int *)data = TTYDISC;
1754 return (0);
1755 case TIOCGWINSZ:
1756 bzero(data, sizeof(struct winsize));
1757 return (0);
1758 default:
1759 return (ENOTTY);
1760 }
1761 }
1762 tp = com->tp;
1763 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1764 term = tp->t_termios;
1765 oldcmd = cmd;
1766 error = ttsetcompat(tp, &cmd, data, &term);
1767 if (error != 0)
1768 return (error);
1769 if (cmd != oldcmd)
1770 data = (caddr_t)&term;
1771 #endif
1772 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1773 int cc;
1774 struct termios *dt = (struct termios *)data;
1775 struct termios *lt = mynor & CALLOUT_MASK
1776 ? &com->lt_out : &com->lt_in;
1777
1778 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1779 | (dt->c_iflag & ~lt->c_iflag);
1780 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1781 | (dt->c_oflag & ~lt->c_oflag);
1782 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1783 | (dt->c_cflag & ~lt->c_cflag);
1784 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1785 | (dt->c_lflag & ~lt->c_lflag);
1786 for (cc = 0; cc < NCCS; ++cc)
1787 if (lt->c_cc[cc] != 0)
1788 dt->c_cc[cc] = tp->t_cc[cc];
1789 if (lt->c_ispeed != 0)
1790 dt->c_ispeed = tp->t_ispeed;
1791 if (lt->c_ospeed != 0)
1792 dt->c_ospeed = tp->t_ospeed;
1793 }
1794 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1795 if (error != ENOIOCTL)
1796 return (error);
1797 s = spltty();
1798 error = ttioctl(tp, cmd, data, flag);
1799 disc_optim(tp, &tp->t_termios, com);
1800 if (error != ENOIOCTL) {
1801 splx(s);
1802 return (error);
1803 }
1804 switch (cmd) {
1805 case TIOCSBRK:
1806 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1807 break;
1808 case TIOCCBRK:
1809 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1810 break;
1811 case TIOCSDTR:
1812 (void)commctl(com, TIOCM_DTR, DMBIS);
1813 break;
1814 case TIOCCDTR:
1815 (void)commctl(com, TIOCM_DTR, DMBIC);
1816 break;
1817 /*
1818 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The
1819 * changes get undone on the next call to comparam().
1820 */
1821 case TIOCMSET:
1822 (void)commctl(com, *(int *)data, DMSET);
1823 break;
1824 case TIOCMBIS:
1825 (void)commctl(com, *(int *)data, DMBIS);
1826 break;
1827 case TIOCMBIC:
1828 (void)commctl(com, *(int *)data, DMBIC);
1829 break;
1830 case TIOCMGET:
1831 *(int *)data = commctl(com, 0, DMGET);
1832 break;
1833 case TIOCMSDTRWAIT:
1834 /* must be root since the wait applies to following logins */
1835 error = suser(p->p_ucred, &p->p_acflag);
1836 if (error != 0) {
1837 splx(s);
1838 return (error);
1839 }
1840 com->dtr_wait = *(int *)data * hz / 100;
1841 break;
1842 case TIOCMGDTRWAIT:
1843 *(int *)data = com->dtr_wait * 100 / hz;
1844 break;
1845 case TIOCTIMESTAMP:
1846 com->do_timestamp = TRUE;
1847 *(struct timeval *)data = com->timestamp;
1848 break;
1849 case TIOCDCDTIMESTAMP:
1850 com->do_dcd_timestamp = TRUE;
1851 *(struct timeval *)data = com->dcd_timestamp;
1852 break;
1853 default:
1854 splx(s);
1855 error = pps_ioctl(cmd, data, &com->pps);
1856 if (error == ENODEV)
1857 error = ENOTTY;
1858 return (error);
1859 }
1860 splx(s);
1861 return (0);
1862 }
1863
1864 static void
1865 siopoll()
1866 {
1867 int unit;
1868
1869 if (com_events == 0)
1870 return;
1871 repeat:
1872 for (unit = 0; unit < NSIOTOT; ++unit) {
1873 u_char *buf;
1874 struct com_s *com;
1875 u_char *ibuf;
1876 int incc;
1877 struct tty *tp;
1878
1879 com = com_addr(unit);
1880 if (com == NULL)
1881 continue;
1882 tp = com->tp;
1883 if (tp == NULL || com->gone) {
1884 /*
1885 * Discard any events related to never-opened or
1886 * going-away devices.
1887 */
1888 disable_intr();
1889 incc = com->iptr - com->ibuf;
1890 com->iptr = com->ibuf;
1891 if (com->state & CS_CHECKMSR) {
1892 incc += LOTS_OF_EVENTS;
1893 com->state &= ~CS_CHECKMSR;
1894 }
1895 com_events -= incc;
1896 enable_intr();
1897 continue;
1898 }
1899
1900 /* switch the role of the low-level input buffers */
1901 if (com->iptr == (ibuf = com->ibuf)) {
1902 buf = NULL; /* not used, but compiler can't tell */
1903 incc = 0;
1904 } else {
1905 buf = ibuf;
1906 disable_intr();
1907 incc = com->iptr - buf;
1908 com_events -= incc;
1909 if (ibuf == com->ibuf1)
1910 ibuf = com->ibuf2;
1911 else
1912 ibuf = com->ibuf1;
1913 com->ibufend = ibuf + RS_IBUFSIZE;
1914 com->ihighwater = ibuf + RS_IHIGHWATER;
1915 com->iptr = ibuf;
1916
1917 /*
1918 * There is now room for another low-level buffer full
1919 * of input, so enable RTS if it is now disabled and
1920 * there is room in the high-level buffer.
1921 */
1922 if ((com->state & CS_RTS_IFLOW)
1923 && !(com->mcr_image & MCR_RTS)
1924 && !(tp->t_state & TS_TBLOCK))
1925 outb(com->modem_ctl_port,
1926 com->mcr_image |= MCR_RTS);
1927 enable_intr();
1928 com->ibuf = ibuf;
1929 }
1930
1931 if (com->state & CS_CHECKMSR) {
1932 u_char delta_modem_status;
1933
1934 disable_intr();
1935 delta_modem_status = com->last_modem_status
1936 ^ com->prev_modem_status;
1937 com->prev_modem_status = com->last_modem_status;
1938 com_events -= LOTS_OF_EVENTS;
1939 com->state &= ~CS_CHECKMSR;
1940 enable_intr();
1941 if (delta_modem_status & MSR_DCD)
1942 (*linesw[tp->t_line].l_modem)
1943 (tp, com->prev_modem_status & MSR_DCD);
1944 }
1945 if (com->state & CS_ODONE) {
1946 disable_intr();
1947 com_events -= LOTS_OF_EVENTS;
1948 com->state &= ~CS_ODONE;
1949 enable_intr();
1950 if (!(com->state & CS_BUSY)
1951 && !(com->extra_state & CSE_BUSYCHECK)) {
1952 timeout(siobusycheck, com, hz / 100);
1953 com->extra_state |= CSE_BUSYCHECK;
1954 }
1955 (*linesw[tp->t_line].l_start)(tp);
1956 }
1957 if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
1958 !(tp->t_cflag & CREAD))
1959 continue;
1960 /*
1961 * Avoid the grotesquely inefficient lineswitch routine
1962 * (ttyinput) in "raw" mode. It usually takes about 450
1963 * instructions (that's without canonical processing or echo!).
1964 * slinput is reasonably fast (usually 40 instructions plus
1965 * call overhead).
1966 */
1967 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1968 if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
1969 && (com->state & CS_RTS_IFLOW
1970 || tp->t_iflag & IXOFF)
1971 && !(tp->t_state & TS_TBLOCK))
1972 ttyblock(tp);
1973 tk_nin += incc;
1974 tk_rawcc += incc;
1975 tp->t_rawcc += incc;
1976 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1977 += b_to_q((char *)buf, incc, &tp->t_rawq);
1978 ttwakeup(tp);
1979 if (tp->t_state & TS_TTSTOP
1980 && (tp->t_iflag & IXANY
1981 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1982 tp->t_state &= ~TS_TTSTOP;
1983 tp->t_lflag &= ~FLUSHO;
1984 comstart(tp);
1985 }
1986 } else {
1987 do {
1988 u_char line_status;
1989 int recv_data;
1990
1991 line_status = (u_char) buf[CE_INPUT_OFFSET];
1992 recv_data = (u_char) *buf++;
1993 if (line_status
1994 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1995 if (line_status & LSR_BI)
1996 recv_data |= TTY_BI;
1997 if (line_status & LSR_FE)
1998 recv_data |= TTY_FE;
1999 if (line_status & LSR_OE)
2000 recv_data |= TTY_OE;
2001 if (line_status & LSR_PE)
2002 recv_data |= TTY_PE;
2003 }
2004 (*linesw[tp->t_line].l_rint)(recv_data, tp);
2005 } while (--incc > 0);
2006 }
2007 if (com_events == 0)
2008 break;
2009 }
2010 if (com_events >= LOTS_OF_EVENTS)
2011 goto repeat;
2012 }
2013
2014 static int
2015 comparam(tp, t)
2016 struct tty *tp;
2017 struct termios *t;
2018 {
2019 u_int cfcr;
2020 int cflag;
2021 struct com_s *com;
2022 int divisor;
2023 u_char dlbh;
2024 u_char dlbl;
2025 Port_t iobase;
2026 int s;
2027 int unit;
2028
2029 /* do historical conversions */
2030 if (t->c_ispeed == 0)
2031 t->c_ispeed = t->c_ospeed;
2032
2033 /* check requested parameters */
2034 divisor = ttspeedtab(t->c_ospeed, comspeedtab);
2035 if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
2036 return (EINVAL);
2037
2038 /* parameters are OK, convert them to the com struct and the device */
2039 unit = DEV_TO_UNIT(tp->t_dev);
2040 com = com_addr(unit);
2041 iobase = com->iobase;
2042 s = spltty();
2043 if (divisor == 0)
2044 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
2045 else
2046 (void)commctl(com, TIOCM_DTR, DMBIS);
2047 cflag = t->c_cflag;
2048 switch (cflag & CSIZE) {
2049 case CS5:
2050 cfcr = CFCR_5BITS;
2051 break;
2052 case CS6:
2053 cfcr = CFCR_6BITS;
2054 break;
2055 case CS7:
2056 cfcr = CFCR_7BITS;
2057 break;
2058 default:
2059 cfcr = CFCR_8BITS;
2060 break;
2061 }
2062 if (cflag & PARENB) {
2063 cfcr |= CFCR_PENAB;
2064 if (!(cflag & PARODD))
2065 cfcr |= CFCR_PEVEN;
2066 }
2067 if (cflag & CSTOPB)
2068 cfcr |= CFCR_STOPB;
2069
2070 if (com->hasfifo && divisor != 0) {
2071 /*
2072 * Use a fifo trigger level low enough so that the input
2073 * latency from the fifo is less than about 16 msec and
2074 * the total latency is less than about 30 msec. These
2075 * latencies are reasonable for humans. Serial comms
2076 * protocols shouldn't expect anything better since modem
2077 * latencies are larger.
2078 */
2079 com->fifo_image = t->c_ospeed <= 4800
2080 ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
2081 #ifdef COM_ESP
2082 /*
2083 * The Hayes ESP card needs the fifo DMA mode bit set
2084 * in compatibility mode. If not, it will interrupt
2085 * for each character received.
2086 */
2087 if (com->esp)
2088 com->fifo_image |= FIFO_DMA_MODE;
2089 #endif
2090 outb(iobase + com_fifo, com->fifo_image);
2091 }
2092
2093 disable_intr(); /* very important while com_data is hidden */
2094
2095 if (divisor != 0) {
2096 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
2097 /*
2098 * Only set the divisor registers if they would change,
2099 * since on some 16550 incompatibles (UMC8669F), setting
2100 * them while input is arriving them loses sync until
2101 * data stops arriving.
2102 */
2103 dlbl = divisor & 0xFF;
2104 if (inb(iobase + com_dlbl) != dlbl)
2105 outb(iobase + com_dlbl, dlbl);
2106 dlbh = (u_int) divisor >> 8;
2107 if (inb(iobase + com_dlbh) != dlbh)
2108 outb(iobase + com_dlbh, dlbh);
2109 }
2110
2111
2112 outb(iobase + com_cfcr, com->cfcr_image = cfcr);
2113
2114 if (!(tp->t_state & TS_TTSTOP))
2115 com->state |= CS_TTGO;
2116
2117 if (cflag & CRTS_IFLOW) {
2118 if (com->st16650a) {
2119 outb(iobase + com_cfcr, 0xbf);
2120 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40);
2121 }
2122 com->state |= CS_RTS_IFLOW;
2123 /*
2124 * If CS_RTS_IFLOW just changed from off to on, the change
2125 * needs to be propagated to MCR_RTS. This isn't urgent,
2126 * so do it later by calling comstart() instead of repeating
2127 * a lot of code from comstart() here.
2128 */
2129 } else if (com->state & CS_RTS_IFLOW) {
2130 com->state &= ~CS_RTS_IFLOW;
2131 /*
2132 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS
2133 * on here, since comstart() won't do it later.
2134 */
2135 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2136 if (com->st16650a) {
2137 outb(iobase + com_cfcr, 0xbf);
2138 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40);
2139 }
2140 }
2141
2142
2143 /*
2144 * Set up state to handle output flow control.
2145 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2146 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2147 */
2148 com->state |= CS_ODEVREADY;
2149 com->state &= ~CS_CTS_OFLOW;
2150 if (cflag & CCTS_OFLOW) {
2151 com->state |= CS_CTS_OFLOW;
2152 if (!(com->last_modem_status & MSR_CTS))
2153 com->state &= ~CS_ODEVREADY;
2154 if (com->st16650a) {
2155 outb(iobase + com_cfcr, 0xbf);
2156 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80);
2157 }
2158 } else {
2159 if (com->st16650a) {
2160 outb(iobase + com_cfcr, 0xbf);
2161 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80);
2162 }
2163 }
2164
2165
2166 outb(iobase + com_cfcr, com->cfcr_image);
2167
2168
2169 /* XXX shouldn't call functions while intrs are disabled. */
2170 disc_optim(tp, t, com);
2171 /*
2172 * Recover from fiddling with CS_TTGO. We used to call siointr1()
2173 * unconditionally, but that defeated the careful discarding of
2174 * stale input in sioopen().
2175 */
2176 if (com->state >= (CS_BUSY | CS_TTGO))
2177 siointr1(com);
2178
2179 enable_intr();
2180 splx(s);
2181 comstart(tp);
2182 return (0);
2183 }
2184
2185 static void
2186 comstart(tp)
2187 struct tty *tp;
2188 {
2189 struct com_s *com;
2190 int s;
2191 int unit;
2192
2193 unit = DEV_TO_UNIT(tp->t_dev);
2194 com = com_addr(unit);
2195 s = spltty();
2196 disable_intr();
2197 if (tp->t_state & TS_TTSTOP)
2198 com->state &= ~CS_TTGO;
2199 else
2200 com->state |= CS_TTGO;
2201 if (tp->t_state & TS_TBLOCK) {
2202 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2203 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2204 } else {
2205 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2206 && com->state & CS_RTS_IFLOW)
2207 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2208 }
2209 enable_intr();
2210 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2211 ttwwakeup(tp);
2212 splx(s);
2213 return;
2214 }
2215 if (tp->t_outq.c_cc != 0) {
2216 struct lbq *qp;
2217 struct lbq *next;
2218
2219 if (!com->obufs[0].l_queued) {
2220 com->obufs[0].l_tail
2221 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2222 sizeof com->obuf1);
2223 com->obufs[0].l_next = NULL;
2224 com->obufs[0].l_queued = TRUE;
2225 disable_intr();
2226 if (com->state & CS_BUSY) {
2227 qp = com->obufq.l_next;
2228 while ((next = qp->l_next) != NULL)
2229 qp = next;
2230 qp->l_next = &com->obufs[0];
2231 } else {
2232 com->obufq.l_head = com->obufs[0].l_head;
2233 com->obufq.l_tail = com->obufs[0].l_tail;
2234 com->obufq.l_next = &com->obufs[0];
2235 com->state |= CS_BUSY;
2236 }
2237 enable_intr();
2238 }
2239 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2240 com->obufs[1].l_tail
2241 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2242 sizeof com->obuf2);
2243 com->obufs[1].l_next = NULL;
2244 com->obufs[1].l_queued = TRUE;
2245 disable_intr();
2246 if (com->state & CS_BUSY) {
2247 qp = com->obufq.l_next;
2248 while ((next = qp->l_next) != NULL)
2249 qp = next;
2250 qp->l_next = &com->obufs[1];
2251 } else {
2252 com->obufq.l_head = com->obufs[1].l_head;
2253 com->obufq.l_tail = com->obufs[1].l_tail;
2254 com->obufq.l_next = &com->obufs[1];
2255 com->state |= CS_BUSY;
2256 }
2257 enable_intr();
2258 }
2259 tp->t_state |= TS_BUSY;
2260 }
2261 disable_intr();
2262 if (com->state >= (CS_BUSY | CS_TTGO))
2263 siointr1(com); /* fake interrupt to start output */
2264 enable_intr();
2265 ttwwakeup(tp);
2266 splx(s);
2267 }
2268
2269 static void
2270 siostop(tp, rw)
2271 struct tty *tp;
2272 int rw;
2273 {
2274 struct com_s *com;
2275
2276 com = com_addr(DEV_TO_UNIT(tp->t_dev));
2277 if (com->gone)
2278 return;
2279 disable_intr();
2280 if (rw & FWRITE) {
2281 if (com->hasfifo)
2282 #ifdef COM_ESP
2283 /* XXX avoid h/w bug. */
2284 if (!com->esp)
2285 #endif
2286 outb(com->iobase + com_fifo,
2287 FIFO_XMT_RST | com->fifo_image);
2288 com->obufs[0].l_queued = FALSE;
2289 com->obufs[1].l_queued = FALSE;
2290 if (com->state & CS_ODONE)
2291 com_events -= LOTS_OF_EVENTS;
2292 com->state &= ~(CS_ODONE | CS_BUSY);
2293 com->tp->t_state &= ~TS_BUSY;
2294 }
2295 if (rw & FREAD) {
2296 if (com->hasfifo)
2297 #ifdef COM_ESP
2298 /* XXX avoid h/w bug. */
2299 if (!com->esp)
2300 #endif
2301 outb(com->iobase + com_fifo,
2302 FIFO_RCV_RST | com->fifo_image);
2303 com_events -= (com->iptr - com->ibuf);
2304 com->iptr = com->ibuf;
2305 }
2306 enable_intr();
2307 comstart(tp);
2308 }
2309
2310 static struct tty *
2311 siodevtotty(dev)
2312 dev_t dev;
2313 {
2314 int mynor;
2315 int unit;
2316
2317 mynor = minor(dev);
2318 if (mynor & CONTROL_MASK)
2319 return (NULL);
2320 unit = MINOR_TO_UNIT(mynor);
2321 if ((u_int) unit >= NSIOTOT)
2322 return (NULL);
2323 return (&sio_tty[unit]);
2324 }
2325
2326 static int
2327 commctl(com, bits, how)
2328 struct com_s *com;
2329 int bits;
2330 int how;
2331 {
2332 int mcr;
2333 int msr;
2334
2335 if (how == DMGET) {
2336 bits = TIOCM_LE; /* XXX - always enabled while open */
2337 mcr = com->mcr_image;
2338 if (mcr & MCR_DTR)
2339 bits |= TIOCM_DTR;
2340 if (mcr & MCR_RTS)
2341 bits |= TIOCM_RTS;
2342 msr = com->prev_modem_status;
2343 if (msr & MSR_CTS)
2344 bits |= TIOCM_CTS;
2345 if (msr & MSR_DCD)
2346 bits |= TIOCM_CD;
2347 if (msr & MSR_DSR)
2348 bits |= TIOCM_DSR;
2349 /*
2350 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
2351 * more volatile by reading the modem status a lot. Perhaps
2352 * we should latch both bits until the status is read here.
2353 */
2354 if (msr & (MSR_RI | MSR_TERI))
2355 bits |= TIOCM_RI;
2356 return (bits);
2357 }
2358 mcr = 0;
2359 if (bits & TIOCM_DTR)
2360 mcr |= MCR_DTR;
2361 if (bits & TIOCM_RTS)
2362 mcr |= MCR_RTS;
2363 if (com->gone)
2364 return(0);
2365 disable_intr();
2366 switch (how) {
2367 case DMSET:
2368 outb(com->modem_ctl_port,
2369 com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
2370 break;
2371 case DMBIS:
2372 outb(com->modem_ctl_port, com->mcr_image |= mcr);
2373 break;
2374 case DMBIC:
2375 outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
2376 break;
2377 }
2378 enable_intr();
2379 return (0);
2380 }
2381
2382 static void
2383 siosettimeout()
2384 {
2385 struct com_s *com;
2386 bool_t someopen;
2387 int unit;
2388
2389 /*
2390 * Set our timeout period to 1 second if no polled devices are open.
2391 * Otherwise set it to max(1/200, 1/hz).
2392 * Enable timeouts iff some device is open.
2393 */
2394 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2395 sio_timeout = hz;
2396 someopen = FALSE;
2397 for (unit = 0; unit < NSIOTOT; ++unit) {
2398 com = com_addr(unit);
2399 if (com != NULL && com->tp != NULL
2400 && com->tp->t_state & TS_ISOPEN && !com->gone) {
2401 someopen = TRUE;
2402 if (com->poll || com->poll_output) {
2403 sio_timeout = hz > 200 ? hz / 200 : 1;
2404 break;
2405 }
2406 }
2407 }
2408 if (someopen) {
2409 sio_timeouts_until_log = hz / sio_timeout;
2410 sio_timeout_handle = timeout(comwakeup, (void *)NULL,
2411 sio_timeout);
2412 } else {
2413 /* Flush error messages, if any. */
2414 sio_timeouts_until_log = 1;
2415 comwakeup((void *)NULL);
2416 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2417 }
2418 }
2419
2420 static void
2421 comwakeup(chan)
2422 void *chan;
2423 {
2424 struct com_s *com;
2425 int unit;
2426
2427 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
2428
2429 /*
2430 * Recover from lost output interrupts.
2431 * Poll any lines that don't use interrupts.
2432 */
2433 for (unit = 0; unit < NSIOTOT; ++unit) {
2434 com = com_addr(unit);
2435 if (com != NULL && !com->gone
2436 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2437 disable_intr();
2438 siointr1(com);
2439 enable_intr();
2440 }
2441 }
2442
2443 /*
2444 * Check for and log errors, but not too often.
2445 */
2446 if (--sio_timeouts_until_log > 0)
2447 return;
2448 sio_timeouts_until_log = hz / sio_timeout;
2449 for (unit = 0; unit < NSIOTOT; ++unit) {
2450 int errnum;
2451
2452 com = com_addr(unit);
2453 if (com == NULL)
2454 continue;
2455 if (com->gone)
2456 continue;
2457 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2458 u_int delta;
2459 u_long total;
2460
2461 disable_intr();
2462 delta = com->delta_error_counts[errnum];
2463 com->delta_error_counts[errnum] = 0;
2464 enable_intr();
2465 if (delta == 0)
2466 continue;
2467 total = com->error_counts[errnum] += delta;
2468 log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
2469 unit, delta, error_desc[errnum],
2470 delta == 1 ? "" : "s", total);
2471 }
2472 }
2473 }
2474
2475 static void
2476 disc_optim(tp, t, com)
2477 struct tty *tp;
2478 struct termios *t;
2479 struct com_s *com;
2480 {
2481 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2482 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2483 && (!(t->c_iflag & PARMRK)
2484 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2485 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2486 && linesw[tp->t_line].l_rint == ttyinput)
2487 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2488 else
2489 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2490 com->hotchar = linesw[tp->t_line].l_hotchar;
2491 }
2492
2493 /*
2494 * Following are all routines needed for SIO to act as console
2495 */
2496 #include <machine/cons.h>
2497
2498 struct siocnstate {
2499 u_char dlbl;
2500 u_char dlbh;
2501 u_char ier;
2502 u_char cfcr;
2503 u_char mcr;
2504 };
2505
2506 static speed_t siocngetspeed __P((Port_t, struct speedtab *));
2507 static void siocnclose __P((struct siocnstate *sp));
2508 static void siocnopen __P((struct siocnstate *sp));
2509 static void siocntxwait __P((void));
2510
2511 /*
2512 * XXX: sciocnget() and sciocnputc() are not declared static, as they are
2513 * referred to from i386/i386/i386-gdbstub.c.
2514 */
2515 static cn_probe_t siocnprobe;
2516 static cn_init_t siocninit;
2517 static cn_checkc_t siocncheckc;
2518 cn_getc_t siocngetc;
2519 cn_putc_t siocnputc;
2520
2521 CONS_DRIVER(sio, siocnprobe, siocninit, siocngetc, siocncheckc, siocnputc);
2522
2523 static void
2524 siocntxwait()
2525 {
2526 int timo;
2527
2528 /*
2529 * Wait for any pending transmission to finish. Required to avoid
2530 * the UART lockup bug when the speed is changed, and for normal
2531 * transmits.
2532 */
2533 timo = 100000;
2534 while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
2535 != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
2536 ;
2537 }
2538
2539 /*
2540 * Read the serial port specified and try to figure out what speed
2541 * it's currently running at. We're assuming the serial port has
2542 * been initialized and is basicly idle. This routine is only intended
2543 * to be run at system startup.
2544 *
2545 * If the value read from the serial port doesn't make sense, return 0.
2546 */
2547
2548 static speed_t
2549 siocngetspeed(iobase, table)
2550 Port_t iobase;
2551 struct speedtab *table;
2552 {
2553 int code;
2554 u_char dlbh;
2555 u_char dlbl;
2556 u_char cfcr;
2557
2558 cfcr = inb(iobase + com_cfcr);
2559 outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
2560
2561 dlbl = inb(iobase + com_dlbl);
2562 dlbh = inb(iobase + com_dlbh);
2563
2564 outb(iobase + com_cfcr, cfcr);
2565
2566 code = dlbh << 8 | dlbl;
2567
2568 for ( ; table->sp_speed != -1; table++)
2569 if (table->sp_code == code)
2570 return (table->sp_speed);
2571
2572 return 0; /* didn't match anything sane */
2573 }
2574
2575 static void
2576 siocnopen(sp)
2577 struct siocnstate *sp;
2578 {
2579 int divisor;
2580 u_char dlbh;
2581 u_char dlbl;
2582 Port_t iobase;
2583
2584 /*
2585 * Save all the device control registers except the fifo register
2586 * and set our default ones (cs8 -parenb speed=comdefaultrate).
2587 * We can't save the fifo register since it is read-only.
2588 */
2589 iobase = siocniobase;
2590 sp->ier = inb(iobase + com_ier);
2591 outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
2592 siocntxwait();
2593 sp->cfcr = inb(iobase + com_cfcr);
2594 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2595 sp->dlbl = inb(iobase + com_dlbl);
2596 sp->dlbh = inb(iobase + com_dlbh);
2597 /*
2598 * Only set the divisor registers if they would change, since on
2599 * some 16550 incompatibles (Startech), setting them clears the
2600 * data input register. This also reduces the effects of the
2601 * UMC8669F bug.
2602 */
2603 divisor = ttspeedtab(comdefaultrate, comspeedtab);
2604 dlbl = divisor & 0xFF;
2605 if (sp->dlbl != dlbl)
2606 outb(iobase + com_dlbl, dlbl);
2607 dlbh = (u_int) divisor >> 8;
2608 if (sp->dlbh != dlbh)
2609 outb(iobase + com_dlbh, dlbh);
2610 outb(iobase + com_cfcr, CFCR_8BITS);
2611 sp->mcr = inb(iobase + com_mcr);
2612 /*
2613 * We don't want interrupts, but must be careful not to "disable"
2614 * them by clearing the MCR_IENABLE bit, since that might cause
2615 * an interrupt by floating the IRQ line.
2616 */
2617 outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
2618 }
2619
2620 static void
2621 siocnclose(sp)
2622 struct siocnstate *sp;
2623 {
2624 Port_t iobase;
2625
2626 /*
2627 * Restore the device control registers.
2628 */
2629 siocntxwait();
2630 iobase = siocniobase;
2631 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2632 if (sp->dlbl != inb(iobase + com_dlbl))
2633 outb(iobase + com_dlbl, sp->dlbl);
2634 if (sp->dlbh != inb(iobase + com_dlbh))
2635 outb(iobase + com_dlbh, sp->dlbh);
2636 outb(iobase + com_cfcr, sp->cfcr);
2637 /*
2638 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
2639 */
2640 outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
2641 outb(iobase + com_ier, sp->ier);
2642 }
2643
2644 static void
2645 siocnprobe(cp)
2646 struct consdev *cp;
2647 {
2648 speed_t boot_speed;
2649 u_char cfcr;
2650 struct isa_device *dvp;
2651 int s;
2652 struct siocnstate sp;
2653
2654 /*
2655 * Find our first enabled console, if any. If it is a high-level
2656 * console device, then initialize it and return successfully.
2657 * If it is a low-level console device, then initialize it and
2658 * return unsuccessfully. It must be initialized in both cases
2659 * for early use by console drivers and debuggers. Initializing
2660 * the hardware is not necessary in all cases, since the i/o
2661 * routines initialize it on the fly, but it is necessary if
2662 * input might arrive while the hardware is switched back to an
2663 * uninitialized state. We can't handle multiple console devices
2664 * yet because our low-level routines don't take a device arg.
2665 * We trust the user to set the console flags properly so that we
2666 * don't need to probe.
2667 */
2668 cp->cn_pri = CN_DEAD;
2669 for (dvp = isa_devtab_tty; dvp->id_driver != NULL; dvp++)
2670 if (dvp->id_driver == &siodriver && dvp->id_enabled
2671 && COM_CONSOLE(dvp)) {
2672 siocniobase = dvp->id_iobase;
2673 s = spltty();
2674 if (boothowto & RB_SERIAL) {
2675 boot_speed = siocngetspeed(siocniobase,
2676 comspeedtab);
2677 if (boot_speed)
2678 comdefaultrate = boot_speed;
2679 }
2680
2681 /*
2682 * Initialize the divisor latch. We can't rely on
2683 * siocnopen() to do this the first time, since it
2684 * avoids writing to the latch if the latch appears
2685 * to have the correct value. Also, if we didn't
2686 * just read the speed from the hardware, then we
2687 * need to set the speed in hardware so that
2688 * switching it later is null.
2689 */
2690 cfcr = inb(siocniobase + com_cfcr);
2691 outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr);
2692 outb(siocniobase + com_dlbl,
2693 COMBRD(comdefaultrate) & 0xff);
2694 outb(siocniobase + com_dlbh,
2695 (u_int) COMBRD(comdefaultrate) >> 8);
2696 outb(siocniobase + com_cfcr, cfcr);
2697
2698 siocnopen(&sp);
2699 splx(s);
2700 if (!COM_LLCONSOLE(dvp)) {
2701 cp->cn_dev = makedev(CDEV_MAJOR, dvp->id_unit);
2702 cp->cn_pri = COM_FORCECONSOLE(dvp)
2703 || boothowto & RB_SERIAL
2704 ? CN_REMOTE : CN_NORMAL;
2705 }
2706 break;
2707 }
2708 }
2709
2710 static void
2711 siocninit(cp)
2712 struct consdev *cp;
2713 {
2714 comconsole = DEV_TO_UNIT(cp->cn_dev);
2715 }
2716
2717 static int
2718 siocncheckc(dev)
2719 dev_t dev;
2720 {
2721 int c;
2722 Port_t iobase;
2723 int s;
2724 struct siocnstate sp;
2725
2726 iobase = siocniobase;
2727 s = spltty();
2728 siocnopen(&sp);
2729 if (inb(iobase + com_lsr) & LSR_RXRDY)
2730 c = inb(iobase + com_data);
2731 else
2732 c = -1;
2733 siocnclose(&sp);
2734 splx(s);
2735 return (c);
2736 }
2737
2738
2739 int
2740 siocngetc(dev)
2741 dev_t dev;
2742 {
2743 int c;
2744 Port_t iobase;
2745 int s;
2746 struct siocnstate sp;
2747
2748 iobase = siocniobase;
2749 s = spltty();
2750 siocnopen(&sp);
2751 while (!(inb(iobase + com_lsr) & LSR_RXRDY))
2752 ;
2753 c = inb(iobase + com_data);
2754 siocnclose(&sp);
2755 splx(s);
2756 return (c);
2757 }
2758
2759 void
2760 siocnputc(dev, c)
2761 dev_t dev;
2762 int c;
2763 {
2764 int s;
2765 struct siocnstate sp;
2766
2767 s = spltty();
2768 siocnopen(&sp);
2769 siocntxwait();
2770 outb(siocniobase + com_data, c);
2771 siocnclose(&sp);
2772 splx(s);
2773 }
2774
2775
2776 /*
2777 * support PnP cards if we are using 'em
2778 */
2779
2780 #if NPNP > 0
2781
2782 static pnpid_t siopnp_ids[] = {
2783 { 0x5015f435, "MOT1550"},
2784 { 0x8113b04e, "Supra1381"},
2785 { 0x9012b04e, "Supra1290"},
2786 { 0x7121b04e, "SupraExpress 56i Sp"},
2787 { 0x11007256, "USR0011"},
2788 { 0x01017256, "USR0101"},
2789 { 0x30207256, "USR2030"},
2790 { 0x31307256, "USR3031"},
2791 { 0x50307256, "USR3050"},
2792 { 0x90307256, "USR3090"},
2793 { 0x0100440e, "Cardinal MVP288IV"},
2794 { 0 }
2795 };
2796
2797 static char *siopnp_probe(u_long csn, u_long vend_id);
2798 static void siopnp_attach(u_long csn, u_long vend_id, char *name,
2799 struct isa_device *dev);
2800 static u_long nsiopnp = NSIO;
2801
2802 static struct pnp_device siopnp = {
2803 "siopnp",
2804 siopnp_probe,
2805 siopnp_attach,
2806 &nsiopnp,
2807 &tty_imask
2808 };
2809 DATA_SET (pnpdevice_set, siopnp);
2810
2811 static char *
2812 siopnp_probe(u_long csn, u_long vend_id)
2813 {
2814 pnpid_t *id;
2815 char *s = NULL;
2816
2817 for(id = siopnp_ids; id->vend_id != 0; id++) {
2818 if (vend_id == id->vend_id) {
2819 s = id->id_str;
2820 break;
2821 }
2822 }
2823
2824 if (s) {
2825 struct pnp_cinfo d;
2826 read_pnp_parms(&d, 0);
2827 if (d.enable == 0 || d.flags & 1) {
2828 printf("CSN %lu is disabled.\n", csn);
2829 return (NULL);
2830 }
2831
2832 }
2833
2834 return (s);
2835 }
2836
2837 static void
2838 siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev)
2839 {
2840 struct pnp_cinfo d;
2841 struct isa_device *dvp;
2842
2843 if (dev->id_unit >= NSIOTOT)
2844 return;
2845
2846 if (read_pnp_parms(&d, 0) == 0) {
2847 printf("failed to read pnp parms\n");
2848 return;
2849 }
2850
2851 write_pnp_parms(&d, 0);
2852
2853 enable_pnp_card();
2854
2855 dev->id_iobase = d.port[0];
2856 dev->id_irq = (1 << d.irq[0]);
2857 dev->id_ointr = siointr;
2858 dev->id_ri_flags = RI_FAST;
2859 dev->id_drq = -1;
2860
2861 if (dev->id_driver == NULL) {
2862 dev->id_driver = &siodriver;
2863 dvp = find_isadev(isa_devtab_tty, &siodriver, 0);
2864 if (dvp != NULL)
2865 dev->id_id = dvp->id_id;
2866 }
2867
2868 if ((dev->id_alive = sioprobe(dev)) != 0)
2869 sioattach(dev);
2870 else
2871 printf("sio%d: probe failed\n", dev->id_unit);
2872 }
2873 #endif
Cache object: 64abb5f4976e15920b4e6edab8ac51e6
|