]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sio/sio.c
This commit was generated by cvs2svn to compensate for changes in r138287,
[FreeBSD/FreeBSD.git] / sys / dev / sio / 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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      from: @(#)com.c 7.5 (Berkeley) 5/16/91
30  *      from: i386/isa sio.c,v 1.234
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_comconsole.h"
37 #include "opt_compat.h"
38 #include "opt_gdb.h"
39 #include "opt_kdb.h"
40 #include "opt_sio.h"
41
42 /*
43  * Serial driver, based on 386BSD-0.1 com driver.
44  * Mostly rewritten to use pseudo-DMA.
45  * Works for National Semiconductor NS8250-NS16550AF UARTs.
46  * COM driver, based on HP dca driver.
47  *
48  * Changes for PC-Card integration:
49  *      - Added PC-Card driver table and handlers
50  */
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/bus.h>
54 #include <sys/conf.h>
55 #include <sys/fcntl.h>
56 #include <sys/interrupt.h>
57 #include <sys/kdb.h>
58 #include <sys/kernel.h>
59 #include <sys/limits.h>
60 #include <sys/lock.h>
61 #include <sys/malloc.h>
62 #include <sys/module.h>
63 #include <sys/mutex.h>
64 #include <sys/proc.h>
65 #include <sys/reboot.h>
66 #include <sys/serial.h>
67 #include <sys/sysctl.h>
68 #include <sys/syslog.h>
69 #include <sys/tty.h>
70 #include <machine/bus_pio.h>
71 #include <machine/bus.h>
72 #include <sys/rman.h>
73 #include <sys/timepps.h>
74 #include <sys/uio.h>
75 #include <sys/cons.h>
76
77 #include <isa/isavar.h>
78
79 #include <machine/resource.h>
80
81 #include <dev/sio/sioreg.h>
82 #include <dev/sio/siovar.h>
83
84 #ifdef COM_ESP
85 #include <dev/ic/esp.h>
86 #endif
87 #include <dev/ic/ns16550.h>
88
89 #define LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
90
91 #ifdef COM_MULTIPORT
92 /* checks in flags for multiport and which is multiport "master chip"
93  * for a given card
94  */
95 #define COM_ISMULTIPORT(flags)  ((flags) & 0x01)
96 #define COM_MPMASTER(flags)     (((flags) >> 8) & 0x0ff)
97 #define COM_NOTAST4(flags)      ((flags) & 0x04)
98 #else
99 #define COM_ISMULTIPORT(flags)  (0)
100 #endif /* COM_MULTIPORT */
101
102 #define COM_C_IIR_TXRDYBUG      0x80000
103 #define COM_CONSOLE(flags)      ((flags) & 0x10)
104 #define COM_DEBUGGER(flags)     ((flags) & 0x80)
105 #define COM_FIFOSIZE(flags)     (((flags) & 0xff000000) >> 24)
106 #define COM_FORCECONSOLE(flags) ((flags) & 0x20)
107 #define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG)
108 #define COM_LLCONSOLE(flags)    ((flags) & 0x40)
109 #define COM_LOSESOUTINTS(flags) ((flags) & 0x08)
110 #define COM_NOFIFO(flags)       ((flags) & 0x02)
111 #define COM_NOPROBE(flags)      ((flags) & 0x40000)
112 #define COM_NOSCR(flags)        ((flags) & 0x100000)
113 #define COM_PPSCTS(flags)       ((flags) & 0x10000)
114 #define COM_ST16650A(flags)     ((flags) & 0x20000)
115 #define COM_TI16754(flags)      ((flags) & 0x200000)
116
117 #define sio_getreg(com, off) \
118         (bus_space_read_1((com)->bst, (com)->bsh, (off)))
119 #define sio_setreg(com, off, value) \
120         (bus_space_write_1((com)->bst, (com)->bsh, (off), (value)))
121
122 /*
123  * com state bits.
124  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
125  * than the other bits so that they can be tested as a group without masking
126  * off the low bits.
127  *
128  * The following com and tty flags correspond closely:
129  *      CS_BUSY         = TS_BUSY (maintained by comstart(), siopoll() and
130  *                                 comstop())
131  *      CS_TTGO         = ~TS_TTSTOP (maintained by comparam() and comstart())
132  *      CS_CTS_OFLOW    = CCTS_OFLOW (maintained by comparam())
133  *      CS_RTS_IFLOW    = CRTS_IFLOW (maintained by comparam())
134  * TS_FLUSH is not used.
135  * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
136  * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
137  */
138 #define CS_BUSY         0x80    /* output in progress */
139 #define CS_TTGO         0x40    /* output not stopped by XOFF */
140 #define CS_ODEVREADY    0x20    /* external device h/w ready (CTS) */
141 #define CS_CHECKMSR     1       /* check of MSR scheduled */
142 #define CS_CTS_OFLOW    2       /* use CTS output flow control */
143 #define CS_ODONE        4       /* output completed */
144 #define CS_RTS_IFLOW    8       /* use RTS input flow control */
145 #define CSE_BUSYCHECK   1       /* siobusycheck() scheduled */
146
147 static  char const * const      error_desc[] = {
148 #define CE_OVERRUN                      0
149         "silo overflow",
150 #define CE_INTERRUPT_BUF_OVERFLOW       1
151         "interrupt-level buffer overflow",
152 #define CE_TTY_BUF_OVERFLOW             2
153         "tty-level buffer overflow",
154 };
155
156 #define CE_NTYPES                       3
157 #define CE_RECORD(com, errnum)          (++(com)->delta_error_counts[errnum])
158
159 /* types.  XXX - should be elsewhere */
160 typedef u_int   Port_t;         /* hardware port */
161 typedef u_char  bool_t;         /* boolean */
162
163 /* queue of linear buffers */
164 struct lbq {
165         u_char  *l_head;        /* next char to process */
166         u_char  *l_tail;        /* one past the last char to process */
167         struct lbq *l_next;     /* next in queue */
168         bool_t  l_queued;       /* nonzero if queued */
169 };
170
171 /* com device structure */
172 struct com_s {
173         u_char  state;          /* miscellaneous flag bits */
174         u_char  cfcr_image;     /* copy of value written to CFCR */
175 #ifdef COM_ESP
176         bool_t  esp;            /* is this unit a hayes esp board? */
177 #endif
178         u_char  extra_state;    /* more flag bits, separate for order trick */
179         u_char  fifo_image;     /* copy of value written to FIFO */
180         bool_t  hasfifo;        /* nonzero for 16550 UARTs */
181         bool_t  loses_outints;  /* nonzero if device loses output interrupts */
182         u_char  mcr_image;      /* copy of value written to MCR */
183 #ifdef COM_MULTIPORT
184         bool_t  multiport;      /* is this unit part of a multiport device? */
185 #endif /* COM_MULTIPORT */
186         bool_t  no_irq;         /* nonzero if irq is not attached */
187         bool_t  gone;           /* hardware disappeared */
188         bool_t  poll;           /* nonzero if polling is required */
189         bool_t  poll_output;    /* nonzero if polling for output is required */
190         bool_t  st16650a;       /* nonzero if Startech 16650A compatible */
191         int     unit;           /* unit number */
192         u_int   flags;          /* copy of device flags */
193         u_int   tx_fifo_size;
194
195         /*
196          * The high level of the driver never reads status registers directly
197          * because there would be too many side effects to handle conveniently.
198          * Instead, it reads copies of the registers stored here by the
199          * interrupt handler.
200          */
201         u_char  last_modem_status;      /* last MSR read by intr handler */
202         u_char  prev_modem_status;      /* last MSR handled by high level */
203
204         u_char  *ibuf;          /* start of input buffer */
205         u_char  *ibufend;       /* end of input buffer */
206         u_char  *ibufold;       /* old input buffer, to be freed */
207         u_char  *ihighwater;    /* threshold in input buffer */
208         u_char  *iptr;          /* next free spot in input buffer */
209         int     ibufsize;       /* size of ibuf (not include error bytes) */
210         int     ierroff;        /* offset of error bytes in ibuf */
211
212         struct lbq      obufq;  /* head of queue of output buffers */
213         struct lbq      obufs[2];       /* output buffers */
214
215         bus_space_tag_t         bst;
216         bus_space_handle_t      bsh;
217
218         Port_t  data_port;      /* i/o ports */
219 #ifdef COM_ESP
220         Port_t  esp_port;
221 #endif
222         Port_t  int_ctl_port;
223         Port_t  int_id_port;
224         Port_t  modem_ctl_port;
225         Port_t  line_status_port;
226         Port_t  modem_status_port;
227
228         struct tty      *tp;    /* cross reference */
229
230         struct  pps_state pps;
231         int     pps_bit;
232 #ifdef ALT_BREAK_TO_DEBUGGER
233         int     alt_brk_state;
234 #endif
235
236         u_long  bytes_in;       /* statistics */
237         u_long  bytes_out;
238         u_int   delta_error_counts[CE_NTYPES];
239         u_long  error_counts[CE_NTYPES];
240
241         u_long  rclk;
242
243         struct resource *irqres;
244         struct resource *ioportres;
245         int     ioportrid;
246         void    *cookie;
247
248         /*
249          * Data area for output buffers.  Someday we should build the output
250          * buffer queue without copying data.
251          */
252         u_char  obuf1[256];
253         u_char  obuf2[256];
254 };
255
256 #ifdef COM_ESP
257 static  int     espattach(struct com_s *com, Port_t esp_port);
258 #endif
259
260 static  void    combreak(struct tty *tp, int sig);
261 static  timeout_t siobusycheck;
262 static  u_int   siodivisor(u_long rclk, speed_t speed);
263 static  void    comclose(struct tty *tp);
264 static  int     comopen(struct tty *tp, struct cdev *dev);
265 static  void    sioinput(struct com_s *com);
266 static  void    siointr1(struct com_s *com);
267 static  void    siointr(void *arg);
268 static  int     commodem(struct tty *tp, int sigon, int sigoff);
269 static  int     comparam(struct tty *tp, struct termios *t);
270 static  void    siopoll(void *);
271 static  void    siosettimeout(void);
272 static  int     siosetwater(struct com_s *com, speed_t speed);
273 static  void    comstart(struct tty *tp);
274 static  void    comstop(struct tty *tp, int rw);
275 static  timeout_t comwakeup;
276
277 char            sio_driver_name[] = "sio";
278 static struct   mtx sio_lock;
279 static int      sio_inited;
280
281 /* table and macro for fast conversion from a unit number to its com struct */
282 devclass_t      sio_devclass;
283 #define com_addr(unit)  ((struct com_s *) \
284                          devclass_get_softc(sio_devclass, unit)) /* XXX */
285
286 int     comconsole = -1;
287 static  volatile speed_t        comdefaultrate = CONSPEED;
288 static  u_long                  comdefaultrclk = DEFAULT_RCLK;
289 SYSCTL_ULONG(_machdep, OID_AUTO, conrclk, CTLFLAG_RW, &comdefaultrclk, 0, "");
290 static  speed_t                 gdbdefaultrate = GDBSPEED;
291 SYSCTL_UINT(_machdep, OID_AUTO, gdbspeed, CTLFLAG_RW,
292             &gdbdefaultrate, GDBSPEED, "");
293 static  u_int   com_events;     /* input chars + weighted output completions */
294 static  Port_t  siocniobase;
295 static  int     siocnunit = -1;
296 static  void    *sio_slow_ih;
297 static  void    *sio_fast_ih;
298 static  int     sio_timeout;
299 static  int     sio_timeouts_until_log;
300 static  struct  callout_handle sio_timeout_handle
301     = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle);
302 static  int     sio_numunits;
303
304 #ifdef GDB
305 static  Port_t  siogdbiobase = 0;
306 #endif
307
308 #ifdef COM_ESP
309 /* XXX configure this properly. */
310 /* XXX quite broken for new-bus. */
311 static  Port_t  likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
312 static  Port_t  likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
313 #endif
314
315 /*
316  * handle sysctl read/write requests for console speed
317  * 
318  * In addition to setting comdefaultrate for I/O through /dev/console,
319  * also set the initial and lock values for the /dev/ttyXX device
320  * if there is one associated with the console.  Finally, if the /dev/tty
321  * device has already been open, change the speed on the open running port
322  * itself.
323  */
324
325 static int
326 sysctl_machdep_comdefaultrate(SYSCTL_HANDLER_ARGS)
327 {
328         int error, s;
329         speed_t newspeed;
330         struct com_s *com;
331         struct tty *tp;
332
333         newspeed = comdefaultrate;
334
335         error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
336         if (error || !req->newptr)
337                 return (error);
338
339         comdefaultrate = newspeed;
340
341         if (comconsole < 0)             /* serial console not selected? */
342                 return (0);
343
344         com = com_addr(comconsole);
345         if (com == NULL)
346                 return (ENXIO);
347
348         tp = com->tp;
349         if (tp == NULL)
350                 return (ENXIO);
351
352         /*
353          * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
354          * (note, the lock rates really are boolean -- if non-zero, disallow
355          *  speed changes)
356          */
357         tp->t_init_in.c_ispeed  = tp->t_init_in.c_ospeed =
358         tp->t_lock_in.c_ispeed  = tp->t_lock_in.c_ospeed =
359         tp->t_init_out.c_ispeed = tp->t_init_out.c_ospeed =
360         tp->t_lock_out.c_ispeed = tp->t_lock_out.c_ospeed = comdefaultrate;
361
362         if (tp->t_state & TS_ISOPEN) {
363                 tp->t_termios.c_ispeed =
364                 tp->t_termios.c_ospeed = comdefaultrate;
365                 s = spltty();
366                 error = comparam(tp, &tp->t_termios);
367                 splx(s);
368         }
369         return error;
370 }
371
372 SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
373             0, 0, sysctl_machdep_comdefaultrate, "I", "");
374 /* TUNABLE_INT("machdep.conspeed", &comdefaultrate); */
375
376 #define SET_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) | (bit))
377 #define CLR_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) & ~(bit))
378
379 /*
380  *      Unload the driver and clear the table.
381  *      XXX this is mostly wrong.
382  *      XXX TODO:
383  *      This is usually called when the card is ejected, but
384  *      can be caused by a kldunload of a controller driver.
385  *      The idea is to reset the driver's view of the device
386  *      and ensure that any driver entry points such as
387  *      read and write do not hang.
388  */
389 int
390 siodetach(device_t dev)
391 {
392         struct com_s    *com;
393
394         com = (struct com_s *) device_get_softc(dev);
395         if (com == NULL) {
396                 device_printf(dev, "NULL com in siounload\n");
397                 return (0);
398         }
399         com->gone = TRUE;
400         if (com->tp)
401                 ttyfree(com->tp);
402         if (com->irqres) {
403                 bus_teardown_intr(dev, com->irqres, com->cookie);
404                 bus_release_resource(dev, SYS_RES_IRQ, 0, com->irqres);
405         }
406         if (com->ioportres)
407                 bus_release_resource(dev, SYS_RES_IOPORT, com->ioportrid,
408                                      com->ioportres);
409         if (com->ibuf != NULL)
410                 free(com->ibuf, M_DEVBUF);
411
412         device_set_softc(dev, NULL);
413         free(com, M_DEVBUF);
414         return (0);
415 }
416
417 int
418 sioprobe(dev, xrid, rclk, noprobe)
419         device_t        dev;
420         int             xrid;
421         u_long          rclk;
422         int             noprobe;
423 {
424 #if 0
425         static bool_t   already_init;
426         device_t        xdev;
427 #endif
428         struct com_s    *com;
429         u_int           divisor;
430         bool_t          failures[10];
431         int             fn;
432         device_t        idev;
433         Port_t          iobase;
434         intrmask_t      irqmap[4];
435         intrmask_t      irqs;
436         u_char          mcr_image;
437         int             result;
438         u_long          xirq;
439         u_int           flags = device_get_flags(dev);
440         int             rid;
441         struct resource *port;
442
443         rid = xrid;
444         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
445                                   0, ~0, IO_COMSIZE, RF_ACTIVE);
446         if (!port)
447                 return (ENXIO);
448
449         com = malloc(sizeof(*com), M_DEVBUF, M_NOWAIT | M_ZERO);
450         if (com == NULL) {
451                 bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
452                 return (ENOMEM);
453         }
454         device_set_softc(dev, com);
455         com->bst = rman_get_bustag(port);
456         com->bsh = rman_get_bushandle(port);
457         if (rclk == 0)
458                 rclk = DEFAULT_RCLK;
459         com->rclk = rclk;
460
461         while (sio_inited != 2)
462                 if (atomic_cmpset_int(&sio_inited, 0, 1)) {
463                         mtx_init(&sio_lock, sio_driver_name, NULL,
464                             (comconsole != -1) ?
465                             MTX_SPIN | MTX_QUIET : MTX_SPIN);
466                         atomic_store_rel_int(&sio_inited, 2);
467                 }
468
469 #if 0
470         /*
471          * XXX this is broken - when we are first called, there are no
472          * previously configured IO ports.  We could hard code
473          * 0x3f8, 0x2f8, 0x3e8, 0x2e8 etc but that's probably worse.
474          * This code has been doing nothing since the conversion since
475          * "count" is zero the first time around.
476          */
477         if (!already_init) {
478                 /*
479                  * Turn off MCR_IENABLE for all likely serial ports.  An unused
480                  * port with its MCR_IENABLE gate open will inhibit interrupts
481                  * from any used port that shares the interrupt vector.
482                  * XXX the gate enable is elsewhere for some multiports.
483                  */
484                 device_t *devs;
485                 int count, i, xioport;
486
487                 devclass_get_devices(sio_devclass, &devs, &count);
488                 for (i = 0; i < count; i++) {
489                         xdev = devs[i];
490                         if (device_is_enabled(xdev) &&
491                             bus_get_resource(xdev, SYS_RES_IOPORT, 0, &xioport,
492                                              NULL) == 0)
493                                 outb(xioport + com_mcr, 0);
494                 }
495                 free(devs, M_TEMP);
496                 already_init = TRUE;
497         }
498 #endif
499
500         if (COM_LLCONSOLE(flags)) {
501                 printf("sio%d: reserved for low-level i/o\n",
502                        device_get_unit(dev));
503                 bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
504                 device_set_softc(dev, NULL);
505                 free(com, M_DEVBUF);
506                 return (ENXIO);
507         }
508
509         /*
510          * If the device is on a multiport card and has an AST/4
511          * compatible interrupt control register, initialize this
512          * register and prepare to leave MCR_IENABLE clear in the mcr.
513          * Otherwise, prepare to set MCR_IENABLE in the mcr.
514          * Point idev to the device struct giving the correct id_irq.
515          * This is the struct for the master device if there is one.
516          */
517         idev = dev;
518         mcr_image = MCR_IENABLE;
519 #ifdef COM_MULTIPORT
520         if (COM_ISMULTIPORT(flags)) {
521                 Port_t xiobase;
522                 u_long io;
523
524                 idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags));
525                 if (idev == NULL) {
526                         printf("sio%d: master device %d not configured\n",
527                                device_get_unit(dev), COM_MPMASTER(flags));
528                         idev = dev;
529                 }
530                 if (!COM_NOTAST4(flags)) {
531                         if (bus_get_resource(idev, SYS_RES_IOPORT, 0, &io,
532                                              NULL) == 0) {
533                                 xiobase = io;
534                                 if (bus_get_resource(idev, SYS_RES_IRQ, 0,
535                                     NULL, NULL) == 0)
536                                         outb(xiobase + com_scr, 0x80);
537                                 else
538                                         outb(xiobase + com_scr, 0);
539                         }
540                         mcr_image = 0;
541                 }
542         }
543 #endif /* COM_MULTIPORT */
544         if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL) != 0)
545                 mcr_image = 0;
546
547         bzero(failures, sizeof failures);
548         iobase = rman_get_start(port);
549
550         /*
551          * We don't want to get actual interrupts, just masked ones.
552          * Interrupts from this line should already be masked in the ICU,
553          * but mask them in the processor as well in case there are some
554          * (misconfigured) shared interrupts.
555          */
556         mtx_lock_spin(&sio_lock);
557 /* EXTRA DELAY? */
558
559         /*
560          * For the TI16754 chips, set prescaler to 1 (4 is often the
561          * default after-reset value) as otherwise it's impossible to
562          * get highest baudrates.
563          */
564         if (COM_TI16754(flags)) {
565                 u_char cfcr, efr;
566
567                 cfcr = sio_getreg(com, com_cfcr);
568                 sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
569                 efr = sio_getreg(com, com_efr);
570                 /* Unlock extended features to turn off prescaler. */
571                 sio_setreg(com, com_efr, efr | EFR_EFE);
572                 /* Disable EFR. */
573                 sio_setreg(com, com_cfcr, (cfcr != CFCR_EFR_ENABLE) ? cfcr : 0);
574                 /* Turn off prescaler. */
575                 sio_setreg(com, com_mcr,
576                            sio_getreg(com, com_mcr) & ~MCR_PRESCALE);
577                 sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
578                 sio_setreg(com, com_efr, efr);
579                 sio_setreg(com, com_cfcr, cfcr);
580         }
581
582         /*
583          * Initialize the speed and the word size and wait long enough to
584          * drain the maximum of 16 bytes of junk in device output queues.
585          * The speed is undefined after a master reset and must be set
586          * before relying on anything related to output.  There may be
587          * junk after a (very fast) soft reboot and (apparently) after
588          * master reset.
589          * XXX what about the UART bug avoided by waiting in comparam()?
590          * We don't want to to wait long enough to drain at 2 bps.
591          */
592         if (iobase == siocniobase)
593                 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
594         else {
595                 sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
596                 divisor = siodivisor(rclk, SIO_TEST_SPEED);
597                 sio_setreg(com, com_dlbl, divisor & 0xff);
598                 sio_setreg(com, com_dlbh, divisor >> 8);
599                 sio_setreg(com, com_cfcr, CFCR_8BITS);
600                 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
601         }
602
603         /*
604          * Enable the interrupt gate and disable device interupts.  This
605          * should leave the device driving the interrupt line low and
606          * guarantee an edge trigger if an interrupt can be generated.
607          */
608 /* EXTRA DELAY? */
609         sio_setreg(com, com_mcr, mcr_image);
610         sio_setreg(com, com_ier, 0);
611         DELAY(1000);            /* XXX */
612         irqmap[0] = isa_irq_pending();
613
614         /*
615          * Attempt to set loopback mode so that we can send a null byte
616          * without annoying any external device.
617          */
618 /* EXTRA DELAY? */
619         sio_setreg(com, com_mcr, mcr_image | MCR_LOOPBACK);
620
621         /*
622          * Attempt to generate an output interrupt.  On 8250's, setting
623          * IER_ETXRDY generates an interrupt independent of the current
624          * setting and independent of whether the THR is empty.  On 16450's,
625          * setting IER_ETXRDY generates an interrupt independent of the
626          * current setting.  On 16550A's, setting IER_ETXRDY only
627          * generates an interrupt when IER_ETXRDY is not already set.
628          */
629         sio_setreg(com, com_ier, IER_ETXRDY);
630
631         /*
632          * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
633          * an interrupt.  They'd better generate one for actually doing
634          * output.  Loopback may be broken on the same incompatibles but
635          * it's unlikely to do more than allow the null byte out.
636          */
637         sio_setreg(com, com_data, 0);
638         if (iobase == siocniobase)
639                 DELAY((1 + 2) * 1000000 / (comdefaultrate / 10));
640         else
641                 DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
642
643         /*
644          * Turn off loopback mode so that the interrupt gate works again
645          * (MCR_IENABLE was hidden).  This should leave the device driving
646          * an interrupt line high.  It doesn't matter if the interrupt
647          * line oscillates while we are not looking at it, since interrupts
648          * are disabled.
649          */
650 /* EXTRA DELAY? */
651         sio_setreg(com, com_mcr, mcr_image);
652  
653         /*
654          * It seems my Xircom CBEM56G Cardbus modem wants to be reset
655          * to 8 bits *again*, or else probe test 0 will fail.
656          * gwk@sgi.com, 4/19/2001
657          */
658         sio_setreg(com, com_cfcr, CFCR_8BITS);
659
660         /*
661          * Some PCMCIA cards (Palido 321s, DC-1S, ...) have the "TXRDY bug",
662          * so we probe for a buggy IIR_TXRDY implementation even in the
663          * noprobe case.  We don't probe for it in the !noprobe case because
664          * noprobe is always set for PCMCIA cards and the problem is not
665          * known to affect any other cards.
666          */
667         if (noprobe) {
668                 /* Read IIR a few times. */
669                 for (fn = 0; fn < 2; fn ++) {
670                         DELAY(10000);
671                         failures[6] = sio_getreg(com, com_iir);
672                 }
673
674                 /* IIR_TXRDY should be clear.  Is it? */
675                 result = 0;
676                 if (failures[6] & IIR_TXRDY) {
677                         /*
678                          * No.  We seem to have the bug.  Does our fix for
679                          * it work?
680                          */
681                         sio_setreg(com, com_ier, 0);
682                         if (sio_getreg(com, com_iir) & IIR_NOPEND) {
683                                 /* Yes.  We discovered the TXRDY bug! */
684                                 SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
685                         } else {
686                                 /* No.  Just fail.  XXX */
687                                 result = ENXIO;
688                                 sio_setreg(com, com_mcr, 0);
689                         }
690                 } else {
691                         /* Yes.  No bug. */
692                         CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
693                 }
694                 sio_setreg(com, com_ier, 0);
695                 sio_setreg(com, com_cfcr, CFCR_8BITS);
696                 mtx_unlock_spin(&sio_lock);
697                 bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
698                 if (iobase == siocniobase)
699                         result = 0;
700                 if (result != 0) {
701                         device_set_softc(dev, NULL);
702                         free(com, M_DEVBUF);
703                 }
704                 return (result);
705         }
706
707         /*
708          * Check that
709          *      o the CFCR, IER and MCR in UART hold the values written to them
710          *        (the values happen to be all distinct - this is good for
711          *        avoiding false positive tests from bus echoes).
712          *      o an output interrupt is generated and its vector is correct.
713          *      o the interrupt goes away when the IIR in the UART is read.
714          */
715 /* EXTRA DELAY? */
716         failures[0] = sio_getreg(com, com_cfcr) - CFCR_8BITS;
717         failures[1] = sio_getreg(com, com_ier) - IER_ETXRDY;
718         failures[2] = sio_getreg(com, com_mcr) - mcr_image;
719         DELAY(10000);           /* Some internal modems need this time */
720         irqmap[1] = isa_irq_pending();
721         failures[4] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_TXRDY;
722         DELAY(1000);            /* XXX */
723         irqmap[2] = isa_irq_pending();
724         failures[6] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
725
726         /*
727          * Turn off all device interrupts and check that they go off properly.
728          * Leave MCR_IENABLE alone.  For ports without a master port, it gates
729          * the OUT2 output of the UART to
730          * the ICU input.  Closing the gate would give a floating ICU input
731          * (unless there is another device driving it) and spurious interrupts.
732          * (On the system that this was first tested on, the input floats high
733          * and gives a (masked) interrupt as soon as the gate is closed.)
734          */
735         sio_setreg(com, com_ier, 0);
736         sio_setreg(com, com_cfcr, CFCR_8BITS);  /* dummy to avoid bus echo */
737         failures[7] = sio_getreg(com, com_ier);
738         DELAY(1000);            /* XXX */
739         irqmap[3] = isa_irq_pending();
740         failures[9] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
741
742         mtx_unlock_spin(&sio_lock);
743
744         irqs = irqmap[1] & ~irqmap[0];
745         if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 &&
746             ((1 << xirq) & irqs) == 0) {
747                 printf(
748                 "sio%d: configured irq %ld not in bitmap of probed irqs %#x\n",
749                     device_get_unit(dev), xirq, irqs);
750                 printf(
751                 "sio%d: port may not be enabled\n",
752                     device_get_unit(dev));
753         }
754         if (bootverbose)
755                 printf("sio%d: irq maps: %#x %#x %#x %#x\n",
756                     device_get_unit(dev),
757                     irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
758
759         result = 0;
760         for (fn = 0; fn < sizeof failures; ++fn)
761                 if (failures[fn]) {
762                         sio_setreg(com, com_mcr, 0);
763                         result = ENXIO;
764                         if (bootverbose) {
765                                 printf("sio%d: probe failed test(s):",
766                                     device_get_unit(dev));
767                                 for (fn = 0; fn < sizeof failures; ++fn)
768                                         if (failures[fn])
769                                                 printf(" %d", fn);
770                                 printf("\n");
771                         }
772                         break;
773                 }
774         bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
775         if (iobase == siocniobase)
776                 result = 0;
777         if (result != 0) {
778                 device_set_softc(dev, NULL);
779                 free(com, M_DEVBUF);
780         }
781         return (result);
782 }
783
784 #ifdef COM_ESP
785 static int
786 espattach(com, esp_port)
787         struct com_s            *com;
788         Port_t                  esp_port;
789 {
790         u_char  dips;
791         u_char  val;
792
793         /*
794          * Check the ESP-specific I/O port to see if we're an ESP
795          * card.  If not, return failure immediately.
796          */
797         if ((inb(esp_port) & 0xf3) == 0) {
798                 printf(" port 0x%x is not an ESP board?\n", esp_port);
799                 return (0);
800         }
801
802         /*
803          * We've got something that claims to be a Hayes ESP card.
804          * Let's hope so.
805          */
806
807         /* Get the dip-switch configuration */
808         outb(esp_port + ESP_CMD1, ESP_GETDIPS);
809         dips = inb(esp_port + ESP_STATUS1);
810
811         /*
812          * Bits 0,1 of dips say which COM port we are.
813          */
814         if (rman_get_start(com->ioportres) == likely_com_ports[dips & 0x03])
815                 printf(" : ESP");
816         else {
817                 printf(" esp_port has com %d\n", dips & 0x03);
818                 return (0);
819         }
820
821         /*
822          * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
823          */
824         outb(esp_port + ESP_CMD1, ESP_GETTEST);
825         val = inb(esp_port + ESP_STATUS1);      /* clear reg 1 */
826         val = inb(esp_port + ESP_STATUS2);
827         if ((val & 0x70) < 0x20) {
828                 printf("-old (%o)", val & 0x70);
829                 return (0);
830         }
831
832         /*
833          * Check for ability to emulate 16550:  bit 7 == 1
834          */
835         if ((dips & 0x80) == 0) {
836                 printf(" slave");
837                 return (0);
838         }
839
840         /*
841          * Okay, we seem to be a Hayes ESP card.  Whee.
842          */
843         com->esp = TRUE;
844         com->esp_port = esp_port;
845         return (1);
846 }
847 #endif /* COM_ESP */
848
849 int
850 sioattach(dev, xrid, rclk)
851         device_t        dev;
852         int             xrid;
853         u_long          rclk;
854 {
855         struct com_s    *com;
856 #ifdef COM_ESP
857         Port_t          *espp;
858 #endif
859         Port_t          iobase;
860         int             unit;
861         u_int           flags;
862         int             rid;
863         struct resource *port;
864         int             ret;
865         int             error;
866         struct tty      *tp;
867
868         rid = xrid;
869         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
870                                   0, ~0, IO_COMSIZE, RF_ACTIVE);
871         if (!port)
872                 return (ENXIO);
873
874         iobase = rman_get_start(port);
875         unit = device_get_unit(dev);
876         com = device_get_softc(dev);
877         flags = device_get_flags(dev);
878
879         if (unit >= sio_numunits)
880                 sio_numunits = unit + 1;
881         /*
882          * sioprobe() has initialized the device registers as follows:
883          *      o cfcr = CFCR_8BITS.
884          *        It is most important that CFCR_DLAB is off, so that the
885          *        data port is not hidden when we enable interrupts.
886          *      o ier = 0.
887          *        Interrupts are only enabled when the line is open.
888          *      o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
889          *        interrupt control register or the config specifies no irq.
890          *        Keeping MCR_DTR and MCR_RTS off might stop the external
891          *        device from sending before we are ready.
892          */
893         bzero(com, sizeof *com);
894         com->unit = unit;
895         com->ioportres = port;
896         com->ioportrid = rid;
897         com->bst = rman_get_bustag(port);
898         com->bsh = rman_get_bushandle(port);
899         com->cfcr_image = CFCR_8BITS;
900         com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
901         com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
902         com->tx_fifo_size = 1;
903         com->obufs[0].l_head = com->obuf1;
904         com->obufs[1].l_head = com->obuf2;
905
906         com->data_port = iobase + com_data;
907         com->int_ctl_port = iobase + com_ier;
908         com->int_id_port = iobase + com_iir;
909         com->modem_ctl_port = iobase + com_mcr;
910         com->mcr_image = inb(com->modem_ctl_port);
911         com->line_status_port = iobase + com_lsr;
912         com->modem_status_port = iobase + com_msr;
913
914         tp = com->tp = ttyalloc();
915         tp->t_oproc = comstart;
916         tp->t_param = comparam;
917         tp->t_stop = comstop;
918         tp->t_modem = commodem;
919         tp->t_break = combreak;
920         tp->t_close = comclose;
921         tp->t_open = comopen;
922         tp->t_sc = com;
923
924         if (rclk == 0)
925                 rclk = DEFAULT_RCLK;
926         com->rclk = rclk;
927
928         if (unit == comconsole)
929                 ttyconsolemode(tp, comdefaultrate);
930         error = siosetwater(com, tp->t_init_in.c_ispeed);
931         mtx_unlock_spin(&sio_lock);
932         if (error) {
933                 /*
934                  * Leave i/o resources allocated if this is a `cn'-level
935                  * console, so that other devices can't snarf them.
936                  */
937                 if (iobase != siocniobase)
938                         bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
939                 return (ENOMEM);
940         }
941
942         /* attempt to determine UART type */
943         printf("sio%d: type", unit);
944
945         if (!COM_ISMULTIPORT(flags) &&
946             !COM_IIR_TXRDYBUG(flags) && !COM_NOSCR(flags)) {
947                 u_char  scr;
948                 u_char  scr1;
949                 u_char  scr2;
950
951                 scr = sio_getreg(com, com_scr);
952                 sio_setreg(com, com_scr, 0xa5);
953                 scr1 = sio_getreg(com, com_scr);
954                 sio_setreg(com, com_scr, 0x5a);
955                 scr2 = sio_getreg(com, com_scr);
956                 sio_setreg(com, com_scr, scr);
957                 if (scr1 != 0xa5 || scr2 != 0x5a) {
958                         printf(" 8250 or not responding");
959                         goto determined_type;
960                 }
961         }
962         sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
963         DELAY(100);
964         switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
965         case FIFO_RX_LOW:
966                 printf(" 16450");
967                 break;
968         case FIFO_RX_MEDL:
969                 printf(" 16450?");
970                 break;
971         case FIFO_RX_MEDH:
972                 printf(" 16550?");
973                 break;
974         case FIFO_RX_HIGH:
975                 if (COM_NOFIFO(flags)) {
976                         printf(" 16550A fifo disabled");
977                         break;
978                 }
979                 com->hasfifo = TRUE;
980                 if (COM_ST16650A(flags)) {
981                         printf(" ST16650A");
982                         com->st16650a = TRUE;
983                         com->tx_fifo_size = 32;
984                         break;
985                 }
986                 if (COM_TI16754(flags)) {
987                         printf(" TI16754");
988                         com->tx_fifo_size = 64;
989                         break;
990                 }
991                 printf(" 16550A");
992 #ifdef COM_ESP
993                 for (espp = likely_esp_ports; *espp != 0; espp++)
994                         if (espattach(com, *espp)) {
995                                 com->tx_fifo_size = 1024;
996                                 break;
997                         }
998                 if (com->esp)
999                         break;
1000 #endif
1001                 com->tx_fifo_size = COM_FIFOSIZE(flags);
1002                 if (com->tx_fifo_size == 0)
1003                         com->tx_fifo_size = 16;
1004                 else
1005                         printf(" lookalike with %u bytes FIFO",
1006                                com->tx_fifo_size);
1007                 break;
1008         }
1009 #ifdef COM_ESP
1010         if (com->esp) {
1011                 /*
1012                  * Set 16550 compatibility mode.
1013                  * We don't use the ESP_MODE_SCALE bit to increase the
1014                  * fifo trigger levels because we can't handle large
1015                  * bursts of input.
1016                  * XXX flow control should be set in comparam(), not here.
1017                  */
1018                 outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1019                 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1020
1021                 /* Set RTS/CTS flow control. */
1022                 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1023                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1024                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1025
1026                 /* Set flow-control levels. */
1027                 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1028                 outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1029                 outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1030                 outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1031                 outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1032         }
1033 #endif /* COM_ESP */
1034         sio_setreg(com, com_fifo, 0);
1035 determined_type: ;
1036
1037 #ifdef COM_MULTIPORT
1038         if (COM_ISMULTIPORT(flags)) {
1039                 device_t masterdev;
1040
1041                 com->multiport = TRUE;
1042                 printf(" (multiport");
1043                 if (unit == COM_MPMASTER(flags))
1044                         printf(" master");
1045                 printf(")");
1046                 masterdev = devclass_get_device(sio_devclass,
1047                     COM_MPMASTER(flags));
1048                 com->no_irq = (masterdev == NULL || bus_get_resource(masterdev,
1049                     SYS_RES_IRQ, 0, NULL, NULL) != 0);
1050          }
1051 #endif /* COM_MULTIPORT */
1052         if (unit == comconsole)
1053                 printf(", console");
1054         if (COM_IIR_TXRDYBUG(flags))
1055                 printf(" with a buggy IIR_TXRDY implementation");
1056         printf("\n");
1057
1058         if (sio_fast_ih == NULL) {
1059                 swi_add(&tty_ithd, "sio", siopoll, NULL, SWI_TTY, 0,
1060                     &sio_fast_ih);
1061                 swi_add(&clk_ithd, "sio", siopoll, NULL, SWI_CLOCK, 0,
1062                     &sio_slow_ih);
1063         }
1064
1065         com->flags = flags;
1066         com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
1067         tp->t_pps = &com->pps;
1068
1069         if (COM_PPSCTS(flags))
1070                 com->pps_bit = MSR_CTS;
1071         else
1072                 com->pps_bit = MSR_DCD;
1073         pps_init(&com->pps);
1074
1075         rid = 0;
1076         com->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
1077         if (com->irqres) {
1078                 ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
1079                                      INTR_TYPE_TTY | INTR_FAST,
1080                                      siointr, com, &com->cookie);
1081                 if (ret) {
1082                         ret = BUS_SETUP_INTR(device_get_parent(dev), dev,
1083                                              com->irqres, INTR_TYPE_TTY,
1084                                              siointr, com, &com->cookie);
1085                         if (ret == 0)
1086                                 device_printf(dev, "unable to activate interrupt in fast mode - using normal mode\n");
1087                 }
1088                 if (ret)
1089                         device_printf(dev, "could not activate interrupt\n");
1090 #if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
1091     defined(ALT_BREAK_TO_DEBUGGER))
1092                 /*
1093                  * Enable interrupts for early break-to-debugger support
1094                  * on the console.
1095                  */
1096                 if (ret == 0 && unit == comconsole)
1097                         outb(siocniobase + com_ier, IER_ERXRDY | IER_ERLS |
1098                             IER_EMSC);
1099 #endif
1100         }
1101
1102         /* We're ready, open the doors... */
1103         ttycreate(tp, NULL, unit, MINOR_CALLOUT, "d%r", unit);
1104
1105         return (0);
1106 }
1107
1108 static int
1109 comopen(struct tty *tp, struct cdev *dev)
1110 {
1111         struct com_s    *com;
1112         int i;
1113
1114         com = tp->t_sc;
1115         com->poll = com->no_irq;
1116         com->poll_output = com->loses_outints;
1117         if (com->hasfifo) {
1118                 /*
1119                  * (Re)enable and drain fifos.
1120                  *
1121                  * Certain SMC chips cause problems if the fifos
1122                  * are enabled while input is ready.  Turn off the
1123                  * fifo if necessary to clear the input.  We test
1124                  * the input ready bit after enabling the fifos
1125                  * since we've already enabled them in comparam()
1126                  * and to handle races between enabling and fresh
1127                  * input.
1128                  */
1129                 for (i = 0; i < 500; i++) {
1130                         sio_setreg(com, com_fifo,
1131                                    FIFO_RCV_RST | FIFO_XMT_RST
1132                                    | com->fifo_image);
1133                         /*
1134                          * XXX the delays are for superstitious
1135                          * historical reasons.  It must be less than
1136                          * the character time at the maximum
1137                          * supported speed (87 usec at 115200 bps
1138                          * 8N1).  Otherwise we might loop endlessly
1139                          * if data is streaming in.  We used to use
1140                          * delays of 100.  That usually worked
1141                          * because DELAY(100) used to usually delay
1142                          * for about 85 usec instead of 100.
1143                          */
1144                         DELAY(50);
1145                         if (!(inb(com->line_status_port) & LSR_RXRDY))
1146                                 break;
1147                         sio_setreg(com, com_fifo, 0);
1148                         DELAY(50);
1149                         (void) inb(com->data_port);
1150                 }
1151                 if (i == 500)
1152                         return (EIO);
1153         }
1154
1155         mtx_lock_spin(&sio_lock);
1156         (void) inb(com->line_status_port);
1157         (void) inb(com->data_port);
1158         com->prev_modem_status = com->last_modem_status
1159             = inb(com->modem_status_port);
1160         outb(com->int_ctl_port,
1161              IER_ERXRDY | IER_ERLS | IER_EMSC
1162              | (COM_IIR_TXRDYBUG(com->flags) ? 0 : IER_ETXRDY));
1163         mtx_unlock_spin(&sio_lock);
1164         siosettimeout();
1165         /* XXX: should be generic ? */
1166         if (com->prev_modem_status & MSR_DCD || ISCALLOUT(dev))
1167                 ttyld_modem(tp, 1);
1168         return (0);
1169 }
1170
1171 static void
1172 comclose(tp)
1173         struct tty      *tp;
1174 {
1175         int             s;
1176         struct com_s    *com;
1177
1178         s = spltty();
1179         com = tp->t_sc;
1180         com->poll = FALSE;
1181         com->poll_output = FALSE;
1182         sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1183
1184 #if defined(KDB) && (defined(BREAK_TO_DEBUGGER) || \
1185     defined(ALT_BREAK_TO_DEBUGGER))
1186         /*
1187          * Leave interrupts enabled and don't clear DTR if this is the
1188          * console. This allows us to detect break-to-debugger events
1189          * while the console device is closed.
1190          */
1191         if (com->unit != comconsole)
1192 #endif
1193         {
1194                 sio_setreg(com, com_ier, 0);
1195                 if (tp->t_cflag & HUPCL
1196                     /*
1197                      * XXX we will miss any carrier drop between here and the
1198                      * next open.  Perhaps we should watch DCD even when the
1199                      * port is closed; it is not sufficient to check it at
1200                      * the next open because it might go up and down while
1201                      * we're not watching.
1202                      */
1203                     || (!tp->t_actout
1204                         && !(com->prev_modem_status & MSR_DCD)
1205                         && !(tp->t_init_in.c_cflag & CLOCAL))
1206                     || !(tp->t_state & TS_ISOPEN)) {
1207                         (void)commodem(tp, 0, SER_DTR);
1208                         ttydtrwaitstart(tp);
1209                 }
1210         }
1211         if (com->hasfifo) {
1212                 /*
1213                  * Disable fifos so that they are off after controlled
1214                  * reboots.  Some BIOSes fail to detect 16550s when the
1215                  * fifos are enabled.
1216                  */
1217                 sio_setreg(com, com_fifo, 0);
1218         }
1219         tp->t_actout = FALSE;
1220         wakeup(&tp->t_actout);
1221         wakeup(TSA_CARR_ON(tp));        /* restart any wopeners */
1222         siosettimeout();
1223         splx(s);
1224 }
1225
1226 static void
1227 siobusycheck(chan)
1228         void    *chan;
1229 {
1230         struct com_s    *com;
1231         int             s;
1232
1233         com = (struct com_s *)chan;
1234
1235         /*
1236          * Clear TS_BUSY if low-level output is complete.
1237          * spl locking is sufficient because siointr1() does not set CS_BUSY.
1238          * If siointr1() clears CS_BUSY after we look at it, then we'll get
1239          * called again.  Reading the line status port outside of siointr1()
1240          * is safe because CS_BUSY is clear so there are no output interrupts
1241          * to lose.
1242          */
1243         s = spltty();
1244         if (com->state & CS_BUSY)
1245                 com->extra_state &= ~CSE_BUSYCHECK;     /* False alarm. */
1246         else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1247             == (LSR_TSRE | LSR_TXRDY)) {
1248                 com->tp->t_state &= ~TS_BUSY;
1249                 ttwwakeup(com->tp);
1250                 com->extra_state &= ~CSE_BUSYCHECK;
1251         } else
1252                 timeout(siobusycheck, com, hz / 100);
1253         splx(s);
1254 }
1255
1256 static u_int
1257 siodivisor(rclk, speed)
1258         u_long  rclk;
1259         speed_t speed;
1260 {
1261         long    actual_speed;
1262         u_int   divisor;
1263         int     error;
1264
1265         if (speed == 0)
1266                 return (0);
1267 #if UINT_MAX > (ULONG_MAX - 1) / 8
1268         if (speed > (ULONG_MAX - 1) / 8)
1269                 return (0);
1270 #endif
1271         divisor = (rclk / (8UL * speed) + 1) / 2;
1272         if (divisor == 0 || divisor >= 65536)
1273                 return (0);
1274         actual_speed = rclk / (16UL * divisor);
1275
1276         /* 10 times error in percent: */
1277         error = ((actual_speed - (long)speed) * 2000 / (long)speed + 1) / 2;
1278
1279         /* 3.0% maximum error tolerance: */
1280         if (error < -30 || error > 30)
1281                 return (0);
1282
1283         return (divisor);
1284 }
1285
1286 /*
1287  * Call this function with the sio_lock mutex held.  It will return with the
1288  * lock still held.
1289  */
1290 static void
1291 sioinput(com)
1292         struct com_s    *com;
1293 {
1294         u_char          *buf;
1295         int             incc;
1296         u_char          line_status;
1297         int             recv_data;
1298         struct tty      *tp;
1299
1300         buf = com->ibuf;
1301         tp = com->tp;
1302         if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) {
1303                 com_events -= (com->iptr - com->ibuf);
1304                 com->iptr = com->ibuf;
1305                 return;
1306         }
1307         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1308                 /*
1309                  * Avoid the grotesquely inefficient lineswitch routine
1310                  * (ttyinput) in "raw" mode.  It usually takes about 450
1311                  * instructions (that's without canonical processing or echo!).
1312                  * slinput is reasonably fast (usually 40 instructions plus
1313                  * call overhead).
1314                  */
1315                 do {
1316                         /*
1317                          * This may look odd, but it is using save-and-enable
1318                          * semantics instead of the save-and-disable semantics
1319                          * that are used everywhere else.
1320                          */
1321                         mtx_unlock_spin(&sio_lock);
1322                         incc = com->iptr - buf;
1323                         if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
1324                             && (com->state & CS_RTS_IFLOW
1325                                 || tp->t_iflag & IXOFF)
1326                             && !(tp->t_state & TS_TBLOCK))
1327                                 ttyblock(tp);
1328                         com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1329                                 += b_to_q((char *)buf, incc, &tp->t_rawq);
1330                         buf += incc;
1331                         tk_nin += incc;
1332                         tk_rawcc += incc;
1333                         tp->t_rawcc += incc;
1334                         ttwakeup(tp);
1335                         if (tp->t_state & TS_TTSTOP
1336                             && (tp->t_iflag & IXANY
1337                                 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1338                                 tp->t_state &= ~TS_TTSTOP;
1339                                 tp->t_lflag &= ~FLUSHO;
1340                                 comstart(tp);
1341                         }
1342                         mtx_lock_spin(&sio_lock);
1343                 } while (buf < com->iptr);
1344         } else {
1345                 do {
1346                         /*
1347                          * This may look odd, but it is using save-and-enable
1348                          * semantics instead of the save-and-disable semantics
1349                          * that are used everywhere else.
1350                          */
1351                         mtx_unlock_spin(&sio_lock);
1352                         line_status = buf[com->ierroff];
1353                         recv_data = *buf++;
1354                         if (line_status
1355                             & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1356                                 if (line_status & LSR_BI)
1357                                         recv_data |= TTY_BI;
1358                                 if (line_status & LSR_FE)
1359                                         recv_data |= TTY_FE;
1360                                 if (line_status & LSR_OE)
1361                                         recv_data |= TTY_OE;
1362                                 if (line_status & LSR_PE)
1363                                         recv_data |= TTY_PE;
1364                         }
1365                         ttyld_rint(tp, recv_data);
1366                         mtx_lock_spin(&sio_lock);
1367                 } while (buf < com->iptr);
1368         }
1369         com_events -= (com->iptr - com->ibuf);
1370         com->iptr = com->ibuf;
1371
1372         /*
1373          * There is now room for another low-level buffer full of input,
1374          * so enable RTS if it is now disabled and there is room in the
1375          * high-level buffer.
1376          */
1377         if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
1378             !(tp->t_state & TS_TBLOCK))
1379                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1380 }
1381
1382 static void
1383 siointr(arg)
1384         void            *arg;
1385 {
1386         struct com_s    *com;
1387
1388 #ifndef COM_MULTIPORT
1389         com = (struct com_s *)arg;
1390
1391         mtx_lock_spin(&sio_lock);
1392         siointr1(com);
1393         mtx_unlock_spin(&sio_lock);
1394 #else /* COM_MULTIPORT */
1395         bool_t          possibly_more_intrs;
1396         int             unit;
1397
1398         /*
1399          * Loop until there is no activity on any port.  This is necessary
1400          * to get an interrupt edge more than to avoid another interrupt.
1401          * If the IRQ signal is just an OR of the IRQ signals from several
1402          * devices, then the edge from one may be lost because another is
1403          * on.
1404          */
1405         mtx_lock_spin(&sio_lock);
1406         do {
1407                 possibly_more_intrs = FALSE;
1408                 for (unit = 0; unit < sio_numunits; ++unit) {
1409                         com = com_addr(unit);
1410                         /*
1411                          * XXX COM_LOCK();
1412                          * would it work here, or be counter-productive?
1413                          */
1414                         if (com != NULL 
1415                             && !com->gone
1416                             && (inb(com->int_id_port) & IIR_IMASK)
1417                                != IIR_NOPEND) {
1418                                 siointr1(com);
1419                                 possibly_more_intrs = TRUE;
1420                         }
1421                         /* XXX COM_UNLOCK(); */
1422                 }
1423         } while (possibly_more_intrs);
1424         mtx_unlock_spin(&sio_lock);
1425 #endif /* COM_MULTIPORT */
1426 }
1427
1428 static struct timespec siots[8];
1429 static int siotso;
1430 static int volatile siotsunit = -1;
1431
1432 static int
1433 sysctl_siots(SYSCTL_HANDLER_ARGS)
1434 {
1435         char buf[128];
1436         long long delta;
1437         size_t len;
1438         int error, i, tso;
1439
1440         for (i = 1, tso = siotso; i < tso; i++) {
1441                 delta = (long long)(siots[i].tv_sec - siots[i - 1].tv_sec) *
1442                     1000000000 +
1443                     (siots[i].tv_nsec - siots[i - 1].tv_nsec);
1444                 len = sprintf(buf, "%lld\n", delta);
1445                 if (delta >= 110000)
1446                         len += sprintf(buf + len - 1, ": *** %ld.%09ld\n",
1447                             (long)siots[i].tv_sec, siots[i].tv_nsec) - 1;
1448                 if (i == tso - 1)
1449                         buf[len - 1] = '\0';
1450                 error = SYSCTL_OUT(req, buf, len);
1451                 if (error != 0)
1452                         return (error);
1453                 uio_yield();
1454         }
1455         return (0);
1456 }
1457
1458 SYSCTL_PROC(_machdep, OID_AUTO, siots, CTLTYPE_STRING | CTLFLAG_RD,
1459     0, 0, sysctl_siots, "A", "sio timestamps");
1460
1461 static void
1462 siointr1(com)
1463         struct com_s    *com;
1464 {
1465         u_char  int_ctl;
1466         u_char  int_ctl_new;
1467         u_char  line_status;
1468         u_char  modem_status;
1469         u_char  *ioptr;
1470         u_char  recv_data;
1471
1472         if (COM_IIR_TXRDYBUG(com->flags)) {
1473                 int_ctl = inb(com->int_ctl_port);
1474                 int_ctl_new = int_ctl;
1475         } else {
1476                 int_ctl = 0;
1477                 int_ctl_new = 0;
1478         }
1479
1480         while (!com->gone) {
1481                 if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) {
1482                         modem_status = inb(com->modem_status_port);
1483                         if ((modem_status ^ com->last_modem_status) &
1484                             com->pps_bit) {
1485                                 pps_capture(&com->pps);
1486                                 pps_event(&com->pps,
1487                                     (modem_status & com->pps_bit) ? 
1488                                     PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
1489                         }
1490                 }
1491                 line_status = inb(com->line_status_port);
1492
1493                 /* input event? (check first to help avoid overruns) */
1494                 while (line_status & LSR_RCV_MASK) {
1495                         /* break/unnattached error bits or real input? */
1496                         if (!(line_status & LSR_RXRDY))
1497                                 recv_data = 0;
1498                         else
1499                                 recv_data = inb(com->data_port);
1500 #ifdef KDB
1501 #ifdef ALT_BREAK_TO_DEBUGGER
1502                         if (com->unit == comconsole &&
1503                             kdb_alt_break(recv_data, &com->alt_brk_state) != 0)
1504                                 kdb_enter("Break sequence on console");
1505 #endif /* ALT_BREAK_TO_DEBUGGER */
1506 #endif /* KDB */
1507                         if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
1508                                 /*
1509                                  * Don't store BI if IGNBRK or FE/PE if IGNPAR.
1510                                  * Otherwise, push the work to a higher level
1511                                  * (to handle PARMRK) if we're bypassing.
1512                                  * Otherwise, convert BI/FE and PE+INPCK to 0.
1513                                  *
1514                                  * This makes bypassing work right in the
1515                                  * usual "raw" case (IGNBRK set, and IGNPAR
1516                                  * and INPCK clear).
1517                                  *
1518                                  * Note: BI together with FE/PE means just BI.
1519                                  */
1520                                 if (line_status & LSR_BI) {
1521 #if defined(KDB) && defined(BREAK_TO_DEBUGGER)
1522                                         if (com->unit == comconsole) {
1523                                                 kdb_enter("Line break on console");
1524                                                 goto cont;
1525                                         }
1526 #endif
1527                                         if (com->tp == NULL
1528                                             || com->tp->t_iflag & IGNBRK)
1529                                                 goto cont;
1530                                 } else {
1531                                         if (com->tp == NULL
1532                                             || com->tp->t_iflag & IGNPAR)
1533                                                 goto cont;
1534                                 }
1535                                 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1536                                     && (line_status & (LSR_BI | LSR_FE)
1537                                         || com->tp->t_iflag & INPCK))
1538                                         recv_data = 0;
1539                         }
1540                         ++com->bytes_in;
1541                         if (com->tp != NULL &&
1542                             com->tp->t_hotchar != 0 && recv_data == com->tp->t_hotchar)
1543                                 swi_sched(sio_fast_ih, 0);
1544                         ioptr = com->iptr;
1545                         if (ioptr >= com->ibufend)
1546                                 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1547                         else {
1548                                 if (com->tp != NULL && com->tp->t_do_timestamp)
1549                                         microtime(&com->tp->t_timestamp);
1550                                 ++com_events;
1551                                 swi_sched(sio_slow_ih, SWI_DELAY);
1552 #if 0 /* for testing input latency vs efficiency */
1553 if (com->iptr - com->ibuf == 8)
1554         swi_sched(sio_fast_ih, 0);
1555 #endif
1556                                 ioptr[0] = recv_data;
1557                                 ioptr[com->ierroff] = line_status;
1558                                 com->iptr = ++ioptr;
1559                                 if (ioptr == com->ihighwater
1560                                     && com->state & CS_RTS_IFLOW)
1561                                         outb(com->modem_ctl_port,
1562                                              com->mcr_image &= ~MCR_RTS);
1563                                 if (line_status & LSR_OE)
1564                                         CE_RECORD(com, CE_OVERRUN);
1565                         }
1566 cont:
1567                         if (line_status & LSR_TXRDY
1568                             && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY))
1569                                 goto txrdy;
1570
1571                         /*
1572                          * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1573                          * jump from the top of the loop to here
1574                          */
1575                         line_status = inb(com->line_status_port) & 0x7F;
1576                 }
1577
1578                 /* modem status change? (always check before doing output) */
1579                 modem_status = inb(com->modem_status_port);
1580                 if (modem_status != com->last_modem_status) {
1581                         /*
1582                          * Schedule high level to handle DCD changes.  Note
1583                          * that we don't use the delta bits anywhere.  Some
1584                          * UARTs mess them up, and it's easy to remember the
1585                          * previous bits and calculate the delta.
1586                          */
1587                         com->last_modem_status = modem_status;
1588                         if (!(com->state & CS_CHECKMSR)) {
1589                                 com_events += LOTS_OF_EVENTS;
1590                                 com->state |= CS_CHECKMSR;
1591                                 swi_sched(sio_fast_ih, 0);
1592                         }
1593
1594                         /* handle CTS change immediately for crisp flow ctl */
1595                         if (com->state & CS_CTS_OFLOW) {
1596                                 if (modem_status & MSR_CTS)
1597                                         com->state |= CS_ODEVREADY;
1598                                 else
1599                                         com->state &= ~CS_ODEVREADY;
1600                         }
1601                 }
1602
1603 txrdy:
1604                 /* output queued and everything ready? */
1605                 if (line_status & LSR_TXRDY
1606                     && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1607                         ioptr = com->obufq.l_head;
1608                         if (com->tx_fifo_size > 1 && com->unit != siotsunit) {
1609                                 u_int   ocount;
1610
1611                                 ocount = com->obufq.l_tail - ioptr;
1612                                 if (ocount > com->tx_fifo_size)
1613                                         ocount = com->tx_fifo_size;
1614                                 com->bytes_out += ocount;
1615                                 do
1616                                         outb(com->data_port, *ioptr++);
1617                                 while (--ocount != 0);
1618                         } else {
1619                                 outb(com->data_port, *ioptr++);
1620                                 ++com->bytes_out;
1621                                 if (com->unit == siotsunit
1622                                     && siotso < sizeof siots / sizeof siots[0])
1623                                         nanouptime(&siots[siotso++]);
1624                         }
1625                         com->obufq.l_head = ioptr;
1626                         if (COM_IIR_TXRDYBUG(com->flags))
1627                                 int_ctl_new = int_ctl | IER_ETXRDY;
1628                         if (ioptr >= com->obufq.l_tail) {
1629                                 struct lbq      *qp;
1630
1631                                 qp = com->obufq.l_next;
1632                                 qp->l_queued = FALSE;
1633                                 qp = qp->l_next;
1634                                 if (qp != NULL) {
1635                                         com->obufq.l_head = qp->l_head;
1636                                         com->obufq.l_tail = qp->l_tail;
1637                                         com->obufq.l_next = qp;
1638                                 } else {
1639                                         /* output just completed */
1640                                         if (COM_IIR_TXRDYBUG(com->flags))
1641                                                 int_ctl_new = int_ctl
1642                                                               & ~IER_ETXRDY;
1643                                         com->state &= ~CS_BUSY;
1644                                 }
1645                                 if (!(com->state & CS_ODONE)) {
1646                                         com_events += LOTS_OF_EVENTS;
1647                                         com->state |= CS_ODONE;
1648                                         /* handle at high level ASAP */
1649                                         swi_sched(sio_fast_ih, 0);
1650                                 }
1651                         }
1652                         if (COM_IIR_TXRDYBUG(com->flags)
1653                             && int_ctl != int_ctl_new)
1654                                 outb(com->int_ctl_port, int_ctl_new);
1655                 }
1656
1657                 /* finished? */
1658 #ifndef COM_MULTIPORT
1659                 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
1660 #endif /* COM_MULTIPORT */
1661                         return;
1662         }
1663 }
1664
1665 /* software interrupt handler for SWI_TTY */
1666 static void
1667 siopoll(void *dummy)
1668 {
1669         int             unit;
1670
1671         if (com_events == 0)
1672                 return;
1673 repeat:
1674         for (unit = 0; unit < sio_numunits; ++unit) {
1675                 struct com_s    *com;
1676                 int             incc;
1677                 struct tty      *tp;
1678
1679                 com = com_addr(unit);
1680                 if (com == NULL)
1681                         continue;
1682                 tp = com->tp;
1683                 if (tp == NULL || com->gone) {
1684                         /*
1685                          * Discard any events related to never-opened or
1686                          * going-away devices.
1687                          */
1688                         mtx_lock_spin(&sio_lock);
1689                         incc = com->iptr - com->ibuf;
1690                         com->iptr = com->ibuf;
1691                         if (com->state & CS_CHECKMSR) {
1692                                 incc += LOTS_OF_EVENTS;
1693                                 com->state &= ~CS_CHECKMSR;
1694                         }
1695                         com_events -= incc;
1696                         mtx_unlock_spin(&sio_lock);
1697                         continue;
1698                 }
1699                 if (com->iptr != com->ibuf) {
1700                         mtx_lock_spin(&sio_lock);
1701                         sioinput(com);
1702                         mtx_unlock_spin(&sio_lock);
1703                 }
1704                 if (com->state & CS_CHECKMSR) {
1705                         u_char  delta_modem_status;
1706
1707                         mtx_lock_spin(&sio_lock);
1708                         delta_modem_status = com->last_modem_status
1709                                              ^ com->prev_modem_status;
1710                         com->prev_modem_status = com->last_modem_status;
1711                         com_events -= LOTS_OF_EVENTS;
1712                         com->state &= ~CS_CHECKMSR;
1713                         mtx_unlock_spin(&sio_lock);
1714                         if (delta_modem_status & MSR_DCD)
1715                                 ttyld_modem(tp,
1716                                     com->prev_modem_status & MSR_DCD);
1717                 }
1718                 if (com->state & CS_ODONE) {
1719                         mtx_lock_spin(&sio_lock);
1720                         com_events -= LOTS_OF_EVENTS;
1721                         com->state &= ~CS_ODONE;
1722                         mtx_unlock_spin(&sio_lock);
1723                         if (!(com->state & CS_BUSY)
1724                             && !(com->extra_state & CSE_BUSYCHECK)) {
1725                                 timeout(siobusycheck, com, hz / 100);
1726                                 com->extra_state |= CSE_BUSYCHECK;
1727                         }
1728                         ttyld_start(tp);
1729                 }
1730                 if (com_events == 0)
1731                         break;
1732         }
1733         if (com_events >= LOTS_OF_EVENTS)
1734                 goto repeat;
1735 }
1736
1737 static void
1738 combreak(tp, sig)
1739         struct tty      *tp;
1740         int             sig;
1741 {
1742         struct com_s    *com;
1743
1744         com = tp->t_sc;
1745
1746         if (sig)
1747                 sio_setreg(com, com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1748         else
1749                 sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1750 }
1751
1752 static int
1753 comparam(tp, t)
1754         struct tty      *tp;
1755         struct termios  *t;
1756 {
1757         u_int           cfcr;
1758         int             cflag;
1759         struct com_s    *com;
1760         u_int           divisor;
1761         u_char          dlbh;
1762         u_char          dlbl;
1763         u_char          efr_flowbits;
1764         int             s;
1765
1766         com = tp->t_sc;
1767         if (com == NULL)
1768                 return (ENODEV);
1769
1770         /* check requested parameters */
1771         if (t->c_ispeed != (t->c_ospeed != 0 ? t->c_ospeed : tp->t_ospeed))
1772                 return (EINVAL);
1773         divisor = siodivisor(com->rclk, t->c_ispeed);
1774         if (divisor == 0)
1775                 return (EINVAL);
1776
1777         /* parameters are OK, convert them to the com struct and the device */
1778         s = spltty();
1779         if (t->c_ospeed == 0)
1780                 (void)commodem(tp, 0, SER_DTR); /* hang up line */
1781         else
1782                 (void)commodem(tp, SER_DTR, 0);
1783         cflag = t->c_cflag;
1784         switch (cflag & CSIZE) {
1785         case CS5:
1786                 cfcr = CFCR_5BITS;
1787                 break;
1788         case CS6:
1789                 cfcr = CFCR_6BITS;
1790                 break;
1791         case CS7:
1792                 cfcr = CFCR_7BITS;
1793                 break;
1794         default:
1795                 cfcr = CFCR_8BITS;
1796                 break;
1797         }
1798         if (cflag & PARENB) {
1799                 cfcr |= CFCR_PENAB;
1800                 if (!(cflag & PARODD))
1801                         cfcr |= CFCR_PEVEN;
1802         }
1803         if (cflag & CSTOPB)
1804                 cfcr |= CFCR_STOPB;
1805
1806         if (com->hasfifo) {
1807                 /*
1808                  * Use a fifo trigger level low enough so that the input
1809                  * latency from the fifo is less than about 16 msec and
1810                  * the total latency is less than about 30 msec.  These
1811                  * latencies are reasonable for humans.  Serial comms
1812                  * protocols shouldn't expect anything better since modem
1813                  * latencies are larger.
1814                  *
1815                  * The fifo trigger level cannot be set at RX_HIGH for high
1816                  * speed connections without further work on reducing 
1817                  * interrupt disablement times in other parts of the system,
1818                  * without producing silo overflow errors.
1819                  */
1820                 com->fifo_image = com->unit == siotsunit ? 0
1821                                   : t->c_ispeed <= 4800
1822                                   ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_MEDH;
1823 #ifdef COM_ESP
1824                 /*
1825                  * The Hayes ESP card needs the fifo DMA mode bit set
1826                  * in compatibility mode.  If not, it will interrupt
1827                  * for each character received.
1828                  */
1829                 if (com->esp)
1830                         com->fifo_image |= FIFO_DMA_MODE;
1831 #endif
1832                 sio_setreg(com, com_fifo, com->fifo_image);
1833         }
1834
1835         /*
1836          * This returns with interrupts disabled so that we can complete
1837          * the speed change atomically.  Keeping interrupts disabled is
1838          * especially important while com_data is hidden.
1839          */
1840         (void) siosetwater(com, t->c_ispeed);
1841
1842         sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
1843         /*
1844          * Only set the divisor registers if they would change, since on
1845          * some 16550 incompatibles (UMC8669F), setting them while input
1846          * is arriving loses sync until data stops arriving.
1847          */
1848         dlbl = divisor & 0xFF;
1849         if (sio_getreg(com, com_dlbl) != dlbl)
1850                 sio_setreg(com, com_dlbl, dlbl);
1851         dlbh = divisor >> 8;
1852         if (sio_getreg(com, com_dlbh) != dlbh)
1853                 sio_setreg(com, com_dlbh, dlbh);
1854
1855         efr_flowbits = 0;
1856
1857         if (cflag & CRTS_IFLOW) {
1858                 com->state |= CS_RTS_IFLOW;
1859                 efr_flowbits |= EFR_AUTORTS;
1860                 /*
1861                  * If CS_RTS_IFLOW just changed from off to on, the change
1862                  * needs to be propagated to MCR_RTS.  This isn't urgent,
1863                  * so do it later by calling comstart() instead of repeating
1864                  * a lot of code from comstart() here.
1865                  */
1866         } else if (com->state & CS_RTS_IFLOW) {
1867                 com->state &= ~CS_RTS_IFLOW;
1868                 /*
1869                  * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
1870                  * on here, since comstart() won't do it later.
1871                  */
1872                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1873         }
1874
1875         /*
1876          * Set up state to handle output flow control.
1877          * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
1878          * Now has 10+ msec latency, while CTS flow has 50- usec latency.
1879          */
1880         com->state |= CS_ODEVREADY;
1881         com->state &= ~CS_CTS_OFLOW;
1882         if (cflag & CCTS_OFLOW) {
1883                 com->state |= CS_CTS_OFLOW;
1884                 efr_flowbits |= EFR_AUTOCTS;
1885                 if (!(com->last_modem_status & MSR_CTS))
1886                         com->state &= ~CS_ODEVREADY;
1887         }
1888
1889         if (com->st16650a) {
1890                 sio_setreg(com, com_lcr, LCR_EFR_ENABLE);
1891                 sio_setreg(com, com_efr,
1892                            (sio_getreg(com, com_efr)
1893                             & ~(EFR_AUTOCTS | EFR_AUTORTS)) | efr_flowbits);
1894         }
1895         sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
1896
1897         /* XXX shouldn't call functions while intrs are disabled. */
1898         ttyldoptim(tp);
1899
1900         mtx_unlock_spin(&sio_lock);
1901         splx(s);
1902         comstart(tp);
1903         if (com->ibufold != NULL) {
1904                 free(com->ibufold, M_DEVBUF);
1905                 com->ibufold = NULL;
1906         }
1907         return (0);
1908 }
1909
1910 /*
1911  * This function must be called with the sio_lock mutex released and will
1912  * return with it obtained.
1913  */
1914 static int
1915 siosetwater(com, speed)
1916         struct com_s    *com;
1917         speed_t         speed;
1918 {
1919         int             cp4ticks;
1920         u_char          *ibuf;
1921         int             ibufsize;
1922         struct tty      *tp;
1923
1924         /*
1925          * Make the buffer size large enough to handle a softtty interrupt
1926          * latency of about 2 ticks without loss of throughput or data
1927          * (about 3 ticks if input flow control is not used or not honoured,
1928          * but a bit less for CS5-CS7 modes).
1929          */
1930         cp4ticks = speed / 10 / hz * 4;
1931         for (ibufsize = 128; ibufsize < cp4ticks;)
1932                 ibufsize <<= 1;
1933         if (ibufsize == com->ibufsize) {
1934                 mtx_lock_spin(&sio_lock);
1935                 return (0);
1936         }
1937
1938         /*
1939          * Allocate input buffer.  The extra factor of 2 in the size is
1940          * to allow for an error byte for each input byte.
1941          */
1942         ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT);
1943         if (ibuf == NULL) {
1944                 mtx_lock_spin(&sio_lock);
1945                 return (ENOMEM);
1946         }
1947
1948         /* Initialize non-critical variables. */
1949         com->ibufold = com->ibuf;
1950         com->ibufsize = ibufsize;
1951         tp = com->tp;
1952         if (tp != NULL) {
1953                 tp->t_ififosize = 2 * ibufsize;
1954                 tp->t_ispeedwat = (speed_t)-1;
1955                 tp->t_ospeedwat = (speed_t)-1;
1956         }
1957
1958         /*
1959          * Read current input buffer, if any.  Continue with interrupts
1960          * disabled.
1961          */
1962         mtx_lock_spin(&sio_lock);
1963         if (com->iptr != com->ibuf)
1964                 sioinput(com);
1965
1966         /*-
1967          * Initialize critical variables, including input buffer watermarks.
1968          * The external device is asked to stop sending when the buffer
1969          * exactly reaches high water, or when the high level requests it.
1970          * The high level is notified immediately (rather than at a later
1971          * clock tick) when this watermark is reached.
1972          * The buffer size is chosen so the watermark should almost never
1973          * be reached.
1974          * The low watermark is invisibly 0 since the buffer is always
1975          * emptied all at once.
1976          */
1977         com->iptr = com->ibuf = ibuf;
1978         com->ibufend = ibuf + ibufsize;
1979         com->ierroff = ibufsize;
1980         com->ihighwater = ibuf + 3 * ibufsize / 4;
1981         return (0);
1982 }
1983
1984 static void
1985 comstart(tp)
1986         struct tty      *tp;
1987 {
1988         struct com_s    *com;
1989         int             s;
1990
1991         com = tp->t_sc;
1992         if (com == NULL)
1993                 return;
1994         s = spltty();
1995         mtx_lock_spin(&sio_lock);
1996         if (tp->t_state & TS_TTSTOP)
1997                 com->state &= ~CS_TTGO;
1998         else
1999                 com->state |= CS_TTGO;
2000         if (tp->t_state & TS_TBLOCK) {
2001                 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2002                         outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2003         } else {
2004                 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2005                     && com->state & CS_RTS_IFLOW)
2006                         outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2007         }
2008         mtx_unlock_spin(&sio_lock);
2009         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2010                 ttwwakeup(tp);
2011                 splx(s);
2012                 return;
2013         }
2014         if (tp->t_outq.c_cc != 0) {
2015                 struct lbq      *qp;
2016                 struct lbq      *next;
2017
2018                 if (!com->obufs[0].l_queued) {
2019                         com->obufs[0].l_tail
2020                             = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2021                                                   sizeof com->obuf1);
2022                         com->obufs[0].l_next = NULL;
2023                         com->obufs[0].l_queued = TRUE;
2024                         mtx_lock_spin(&sio_lock);
2025                         if (com->state & CS_BUSY) {
2026                                 qp = com->obufq.l_next;
2027                                 while ((next = qp->l_next) != NULL)
2028                                         qp = next;
2029                                 qp->l_next = &com->obufs[0];
2030                         } else {
2031                                 com->obufq.l_head = com->obufs[0].l_head;
2032                                 com->obufq.l_tail = com->obufs[0].l_tail;
2033                                 com->obufq.l_next = &com->obufs[0];
2034                                 com->state |= CS_BUSY;
2035                         }
2036                         mtx_unlock_spin(&sio_lock);
2037                 }
2038                 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2039                         com->obufs[1].l_tail
2040                             = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2041                                                   sizeof com->obuf2);
2042                         com->obufs[1].l_next = NULL;
2043                         com->obufs[1].l_queued = TRUE;
2044                         mtx_lock_spin(&sio_lock);
2045                         if (com->state & CS_BUSY) {
2046                                 qp = com->obufq.l_next;
2047                                 while ((next = qp->l_next) != NULL)
2048                                         qp = next;
2049                                 qp->l_next = &com->obufs[1];
2050                         } else {
2051                                 com->obufq.l_head = com->obufs[1].l_head;
2052                                 com->obufq.l_tail = com->obufs[1].l_tail;
2053                                 com->obufq.l_next = &com->obufs[1];
2054                                 com->state |= CS_BUSY;
2055                         }
2056                         mtx_unlock_spin(&sio_lock);
2057                 }
2058                 tp->t_state |= TS_BUSY;
2059         }
2060         mtx_lock_spin(&sio_lock);
2061         if (com->state >= (CS_BUSY | CS_TTGO))
2062                 siointr1(com);  /* fake interrupt to start output */
2063         mtx_unlock_spin(&sio_lock);
2064         ttwwakeup(tp);
2065         splx(s);
2066 }
2067
2068 static void
2069 comstop(tp, rw)
2070         struct tty      *tp;
2071         int             rw;
2072 {
2073         struct com_s    *com;
2074
2075         com = tp->t_sc;
2076         if (com == NULL || com->gone)
2077                 return;
2078         mtx_lock_spin(&sio_lock);
2079         if (rw & FWRITE) {
2080                 if (com->hasfifo)
2081 #ifdef COM_ESP
2082                     /* XXX avoid h/w bug. */
2083                     if (!com->esp)
2084 #endif
2085                         sio_setreg(com, com_fifo,
2086                                    FIFO_XMT_RST | com->fifo_image);
2087                 com->obufs[0].l_queued = FALSE;
2088                 com->obufs[1].l_queued = FALSE;
2089                 if (com->state & CS_ODONE)
2090                         com_events -= LOTS_OF_EVENTS;
2091                 com->state &= ~(CS_ODONE | CS_BUSY);
2092                 com->tp->t_state &= ~TS_BUSY;
2093         }
2094         if (rw & FREAD) {
2095                 if (com->hasfifo)
2096 #ifdef COM_ESP
2097                     /* XXX avoid h/w bug. */
2098                     if (!com->esp)
2099 #endif
2100                         sio_setreg(com, com_fifo,
2101                                    FIFO_RCV_RST | com->fifo_image);
2102                 com_events -= (com->iptr - com->ibuf);
2103                 com->iptr = com->ibuf;
2104         }
2105         mtx_unlock_spin(&sio_lock);
2106         comstart(tp);
2107 }
2108
2109 static int
2110 commodem(struct tty *tp, int sigon, int sigoff)
2111 {
2112         struct com_s    *com;
2113         int     bitand, bitor, msr;
2114
2115         com = tp->t_sc;
2116         if (com->gone)
2117                 return(0);
2118         if (sigon != 0 || sigoff != 0) {
2119                 bitand = bitor = 0;
2120                 if (sigoff & SER_DTR)
2121                         bitand |= MCR_DTR;
2122                 if (sigoff & SER_RTS)
2123                         bitand |= MCR_RTS;
2124                 if (sigon & SER_DTR)
2125                         bitor |= MCR_DTR;
2126                 if (sigon & SER_RTS)
2127                         bitor |= MCR_RTS;
2128                 bitand = ~bitand;
2129                 mtx_lock_spin(&sio_lock);
2130                 com->mcr_image &= bitand;
2131                 com->mcr_image |= bitor;
2132                 outb(com->modem_ctl_port, com->mcr_image);
2133                 mtx_unlock_spin(&sio_lock);
2134                 return (0);
2135         } else {
2136                 bitor = 0;
2137                 if (com->mcr_image & MCR_DTR)
2138                         bitor |= SER_DTR;
2139                 if (com->mcr_image & MCR_RTS)
2140                         bitor |= SER_RTS;
2141                 msr = com->prev_modem_status;
2142                 if (msr & MSR_CTS)
2143                         bitor |= SER_CTS;
2144                 if (msr & MSR_DCD)
2145                         bitor |= SER_DCD;
2146                 if (msr & MSR_DSR)
2147                         bitor |= SER_DSR;
2148                 if (msr & MSR_DSR)
2149                         bitor |= SER_DSR;
2150                 if (msr & (MSR_RI | MSR_TERI))
2151                         bitor |= SER_RI;
2152                 return (bitor);
2153         }
2154 }
2155
2156 static void
2157 siosettimeout()
2158 {
2159         struct com_s    *com;
2160         bool_t          someopen;
2161         int             unit;
2162
2163         /*
2164          * Set our timeout period to 1 second if no polled devices are open.
2165          * Otherwise set it to max(1/200, 1/hz).
2166          * Enable timeouts iff some device is open.
2167          */
2168         untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2169         sio_timeout = hz;
2170         someopen = FALSE;
2171         for (unit = 0; unit < sio_numunits; ++unit) {
2172                 com = com_addr(unit);
2173                 if (com != NULL && com->tp != NULL
2174                     && com->tp->t_state & TS_ISOPEN && !com->gone) {
2175                         someopen = TRUE;
2176                         if (com->poll || com->poll_output) {
2177                                 sio_timeout = hz > 200 ? hz / 200 : 1;
2178                                 break;
2179                         }
2180                 }
2181         }
2182         if (someopen) {
2183                 sio_timeouts_until_log = hz / sio_timeout;
2184                 sio_timeout_handle = timeout(comwakeup, (void *)NULL,
2185                                              sio_timeout);
2186         } else {
2187                 /* Flush error messages, if any. */
2188                 sio_timeouts_until_log = 1;
2189                 comwakeup((void *)NULL);
2190                 untimeout(comwakeup, (void *)NULL, sio_timeout_handle);
2191         }
2192 }
2193
2194 static void
2195 comwakeup(chan)
2196         void    *chan;
2197 {
2198         struct com_s    *com;
2199         int             unit;
2200
2201         sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout);
2202
2203         /*
2204          * Recover from lost output interrupts.
2205          * Poll any lines that don't use interrupts.
2206          */
2207         for (unit = 0; unit < sio_numunits; ++unit) {
2208                 com = com_addr(unit);
2209                 if (com != NULL && !com->gone
2210                     && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2211                         mtx_lock_spin(&sio_lock);
2212                         siointr1(com);
2213                         mtx_unlock_spin(&sio_lock);
2214                 }
2215         }
2216
2217         /*
2218          * Check for and log errors, but not too often.
2219          */
2220         if (--sio_timeouts_until_log > 0)
2221                 return;
2222         sio_timeouts_until_log = hz / sio_timeout;
2223         for (unit = 0; unit < sio_numunits; ++unit) {
2224                 int     errnum;
2225
2226                 com = com_addr(unit);
2227                 if (com == NULL)
2228                         continue;
2229                 if (com->gone)
2230                         continue;
2231                 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2232                         u_int   delta;
2233                         u_long  total;
2234
2235                         mtx_lock_spin(&sio_lock);
2236                         delta = com->delta_error_counts[errnum];
2237                         com->delta_error_counts[errnum] = 0;
2238                         mtx_unlock_spin(&sio_lock);
2239                         if (delta == 0)
2240                                 continue;
2241                         total = com->error_counts[errnum] += delta;
2242                         log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
2243                             unit, delta, error_desc[errnum],
2244                             delta == 1 ? "" : "s", total);
2245                 }
2246         }
2247 }
2248
2249 /*
2250  * Following are all routines needed for SIO to act as console
2251  */
2252 struct siocnstate {
2253         u_char  dlbl;
2254         u_char  dlbh;
2255         u_char  ier;
2256         u_char  cfcr;
2257         u_char  mcr;
2258 };
2259
2260 /*
2261  * This is a function in order to not replicate "ttyd%d" more
2262  * places than absolutely necessary.
2263  */
2264 static void
2265 siocnset(struct consdev *cd, int unit)
2266 {
2267
2268         cd->cn_unit = unit;
2269         sprintf(cd->cn_name, "ttyd%d", unit);
2270 }
2271
2272 static speed_t siocngetspeed(Port_t, u_long rclk);
2273 static void siocnclose(struct siocnstate *sp, Port_t iobase);
2274 static void siocnopen(struct siocnstate *sp, Port_t iobase, int speed);
2275 static void siocntxwait(Port_t iobase);
2276
2277 static cn_probe_t siocnprobe;
2278 static cn_init_t siocninit;
2279 static cn_term_t siocnterm;
2280 static cn_checkc_t siocncheckc;
2281 static cn_getc_t siocngetc;
2282 static cn_putc_t siocnputc;
2283
2284 CONS_DRIVER(sio, siocnprobe, siocninit, siocnterm, siocngetc, siocncheckc,
2285             siocnputc, NULL);
2286
2287 static void
2288 siocntxwait(iobase)
2289         Port_t  iobase;
2290 {
2291         int     timo;
2292
2293         /*
2294          * Wait for any pending transmission to finish.  Required to avoid
2295          * the UART lockup bug when the speed is changed, and for normal
2296          * transmits.
2297          */
2298         timo = 100000;
2299         while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
2300                != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
2301                 ;
2302 }
2303
2304 /*
2305  * Read the serial port specified and try to figure out what speed
2306  * it's currently running at.  We're assuming the serial port has
2307  * been initialized and is basicly idle.  This routine is only intended
2308  * to be run at system startup.
2309  *
2310  * If the value read from the serial port doesn't make sense, return 0.
2311  */
2312
2313 static speed_t
2314 siocngetspeed(iobase, rclk)
2315         Port_t  iobase;
2316         u_long  rclk;
2317 {
2318         u_int   divisor;
2319         u_char  dlbh;
2320         u_char  dlbl;
2321         u_char  cfcr;
2322
2323         cfcr = inb(iobase + com_cfcr);
2324         outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
2325
2326         dlbl = inb(iobase + com_dlbl);
2327         dlbh = inb(iobase + com_dlbh);
2328
2329         outb(iobase + com_cfcr, cfcr);
2330
2331         divisor = dlbh << 8 | dlbl;
2332
2333         /* XXX there should be more sanity checking. */
2334         if (divisor == 0)
2335                 return (CONSPEED);
2336         return (rclk / (16UL * divisor));
2337 }
2338
2339 static void
2340 siocnopen(sp, iobase, speed)
2341         struct siocnstate       *sp;
2342         Port_t                  iobase;
2343         int                     speed;
2344 {
2345         u_int   divisor;
2346         u_char  dlbh;
2347         u_char  dlbl;
2348
2349         /*
2350          * Save all the device control registers except the fifo register
2351          * and set our default ones (cs8 -parenb speed=comdefaultrate).
2352          * We can't save the fifo register since it is read-only.
2353          */
2354         sp->ier = inb(iobase + com_ier);
2355         outb(iobase + com_ier, 0);      /* spltty() doesn't stop siointr() */
2356         siocntxwait(iobase);
2357         sp->cfcr = inb(iobase + com_cfcr);
2358         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2359         sp->dlbl = inb(iobase + com_dlbl);
2360         sp->dlbh = inb(iobase + com_dlbh);
2361         /*
2362          * Only set the divisor registers if they would change, since on
2363          * some 16550 incompatibles (Startech), setting them clears the
2364          * data input register.  This also reduces the effects of the
2365          * UMC8669F bug.
2366          */
2367         divisor = siodivisor(comdefaultrclk, speed);
2368         dlbl = divisor & 0xFF;
2369         if (sp->dlbl != dlbl)
2370                 outb(iobase + com_dlbl, dlbl);
2371         dlbh = divisor >> 8;
2372         if (sp->dlbh != dlbh)
2373                 outb(iobase + com_dlbh, dlbh);
2374         outb(iobase + com_cfcr, CFCR_8BITS);
2375         sp->mcr = inb(iobase + com_mcr);
2376         /*
2377          * We don't want interrupts, but must be careful not to "disable"
2378          * them by clearing the MCR_IENABLE bit, since that might cause
2379          * an interrupt by floating the IRQ line.
2380          */
2381         outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
2382 }
2383
2384 static void
2385 siocnclose(sp, iobase)
2386         struct siocnstate       *sp;
2387         Port_t                  iobase;
2388 {
2389         /*
2390          * Restore the device control registers.
2391          */
2392         siocntxwait(iobase);
2393         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2394         if (sp->dlbl != inb(iobase + com_dlbl))
2395                 outb(iobase + com_dlbl, sp->dlbl);
2396         if (sp->dlbh != inb(iobase + com_dlbh))
2397                 outb(iobase + com_dlbh, sp->dlbh);
2398         outb(iobase + com_cfcr, sp->cfcr);
2399         /*
2400          * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
2401          */
2402         outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
2403         outb(iobase + com_ier, sp->ier);
2404 }
2405
2406 static void
2407 siocnprobe(cp)
2408         struct consdev  *cp;
2409 {
2410         speed_t                 boot_speed;
2411         u_char                  cfcr;
2412         u_int                   divisor;
2413         int                     s, unit;
2414         struct siocnstate       sp;
2415
2416         /*
2417          * Find our first enabled console, if any.  If it is a high-level
2418          * console device, then initialize it and return successfully.
2419          * If it is a low-level console device, then initialize it and
2420          * return unsuccessfully.  It must be initialized in both cases
2421          * for early use by console drivers and debuggers.  Initializing
2422          * the hardware is not necessary in all cases, since the i/o
2423          * routines initialize it on the fly, but it is necessary if
2424          * input might arrive while the hardware is switched back to an
2425          * uninitialized state.  We can't handle multiple console devices
2426          * yet because our low-level routines don't take a device arg.
2427          * We trust the user to set the console flags properly so that we
2428          * don't need to probe.
2429          */
2430         cp->cn_pri = CN_DEAD;
2431
2432         for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
2433                 int flags;
2434
2435                 if (resource_disabled("sio", unit))
2436                         continue;
2437                 if (resource_int_value("sio", unit, "flags", &flags))
2438                         continue;
2439                 if (COM_CONSOLE(flags) || COM_DEBUGGER(flags)) {
2440                         int port;
2441                         Port_t iobase;
2442
2443                         if (resource_int_value("sio", unit, "port", &port))
2444                                 continue;
2445                         iobase = port;
2446                         s = spltty();
2447                         if (boothowto & RB_SERIAL) {
2448                                 boot_speed =
2449                                     siocngetspeed(iobase, comdefaultrclk);
2450                                 if (boot_speed)
2451                                         comdefaultrate = boot_speed;
2452                         }
2453
2454                         /*
2455                          * Initialize the divisor latch.  We can't rely on
2456                          * siocnopen() to do this the first time, since it 
2457                          * avoids writing to the latch if the latch appears
2458                          * to have the correct value.  Also, if we didn't
2459                          * just read the speed from the hardware, then we
2460                          * need to set the speed in hardware so that
2461                          * switching it later is null.
2462                          */
2463                         cfcr = inb(iobase + com_cfcr);
2464                         outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
2465                         divisor = siodivisor(comdefaultrclk, comdefaultrate);
2466                         outb(iobase + com_dlbl, divisor & 0xff);
2467                         outb(iobase + com_dlbh, divisor >> 8);
2468                         outb(iobase + com_cfcr, cfcr);
2469
2470                         siocnopen(&sp, iobase, comdefaultrate);
2471
2472                         splx(s);
2473                         if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) {
2474                                 siocnset(cp, unit);
2475                                 cp->cn_pri = COM_FORCECONSOLE(flags)
2476                                              || boothowto & RB_SERIAL
2477                                              ? CN_REMOTE : CN_NORMAL;
2478                                 siocniobase = iobase;
2479                                 siocnunit = unit;
2480                         }
2481 #ifdef GDB
2482                         if (COM_DEBUGGER(flags))
2483                                 siogdbiobase = iobase;
2484 #endif
2485                 }
2486         }
2487 }
2488
2489 static void
2490 siocninit(cp)
2491         struct consdev  *cp;
2492 {
2493         comconsole = cp->cn_unit;
2494 }
2495
2496 static void
2497 siocnterm(cp)
2498         struct consdev  *cp;
2499 {
2500         comconsole = -1;
2501 }
2502
2503 static int
2504 siocncheckc(struct consdev *cd)
2505 {
2506         int     c;
2507         Port_t  iobase;
2508         int     s;
2509         struct siocnstate       sp;
2510         speed_t speed;
2511
2512         if (cd != NULL && cd->cn_unit == siocnunit) {
2513                 iobase = siocniobase;
2514                 speed = comdefaultrate;
2515         } else {
2516 #ifdef GDB
2517                 iobase = siogdbiobase;
2518                 speed = gdbdefaultrate;
2519 #else
2520                 return (-1);
2521 #endif
2522         }
2523         s = spltty();
2524         siocnopen(&sp, iobase, speed);
2525         if (inb(iobase + com_lsr) & LSR_RXRDY)
2526                 c = inb(iobase + com_data);
2527         else
2528                 c = -1;
2529         siocnclose(&sp, iobase);
2530         splx(s);
2531         return (c);
2532 }
2533
2534 static int
2535 siocngetc(struct consdev *cd)
2536 {
2537         int     c;
2538         Port_t  iobase;
2539         int     s;
2540         struct siocnstate       sp;
2541         speed_t speed;
2542
2543         if (cd != NULL && cd->cn_unit == siocnunit) {
2544                 iobase = siocniobase;
2545                 speed = comdefaultrate;
2546         } else {
2547 #ifdef GDB
2548                 iobase = siogdbiobase;
2549                 speed = gdbdefaultrate;
2550 #else
2551                 return (-1);
2552 #endif
2553         }
2554         s = spltty();
2555         siocnopen(&sp, iobase, speed);
2556         while (!(inb(iobase + com_lsr) & LSR_RXRDY))
2557                 ;
2558         c = inb(iobase + com_data);
2559         siocnclose(&sp, iobase);
2560         splx(s);
2561         return (c);
2562 }
2563
2564 static void
2565 siocnputc(struct consdev *cd, int c)
2566 {
2567         int     need_unlock;
2568         int     s;
2569         struct siocnstate       sp;
2570         Port_t  iobase;
2571         speed_t speed;
2572
2573         if (cd != NULL && cd->cn_unit == siocnunit) {
2574                 iobase = siocniobase;
2575                 speed = comdefaultrate;
2576         } else {
2577 #ifdef GDB
2578                 iobase = siogdbiobase;
2579                 speed = gdbdefaultrate;
2580 #else
2581                 return;
2582 #endif
2583         }
2584         s = spltty();
2585         need_unlock = 0;
2586         if (sio_inited == 2 && !mtx_owned(&sio_lock)) {
2587                 mtx_lock_spin(&sio_lock);
2588                 need_unlock = 1;
2589         }
2590         siocnopen(&sp, iobase, speed);
2591         siocntxwait(iobase);
2592         outb(iobase + com_data, c);
2593         siocnclose(&sp, iobase);
2594         if (need_unlock)
2595                 mtx_unlock_spin(&sio_lock);
2596         splx(s);
2597 }
2598
2599 /*
2600  * Remote gdb(1) support.
2601  */
2602
2603 #if defined(GDB)
2604
2605 #include <gdb/gdb.h>
2606
2607 static gdb_probe_f siogdbprobe;
2608 static gdb_init_f siogdbinit;
2609 static gdb_term_f siogdbterm;
2610 static gdb_getc_f siogdbgetc;
2611 static gdb_checkc_f siogdbcheckc;
2612 static gdb_putc_f siogdbputc;
2613
2614 GDB_DBGPORT(sio, siogdbprobe, siogdbinit, siogdbterm, siogdbcheckc,
2615     siogdbgetc, siogdbputc);
2616
2617 static int
2618 siogdbprobe(void)
2619 {
2620         return ((siogdbiobase != 0) ? 0 : -1);
2621 }
2622
2623 static void
2624 siogdbinit(void)
2625 {
2626 }
2627
2628 static void
2629 siogdbterm(void)
2630 {
2631 }
2632
2633 static void
2634 siogdbputc(int c)
2635 {
2636         siocnputc(NULL, c);
2637 }
2638
2639 static int
2640 siogdbcheckc(void)
2641 {
2642         return (siocncheckc(NULL));
2643 }
2644
2645 static int
2646 siogdbgetc(void)
2647 {
2648         return (siocngetc(NULL));
2649 }
2650
2651 #endif