MASSIVE reorganization of the device operations vector. Change cdevsw
[dragonfly.git] / sys / dev / serial / 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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/isa/sio.c,v 1.291.2.35 2003/05/18 08:51:15 murray Exp $
34  * $DragonFly: src/sys/dev/serial/sio/sio.c,v 1.32 2006/07/28 02:17:38 dillon Exp $
35  *      from: @(#)com.c 7.5 (Berkeley) 5/16/91
36  *      from: i386/isa sio.c,v 1.234
37  */
38
39 #include "opt_comconsole.h"
40 #include "opt_compat.h"
41 #include "opt_ddb.h"
42 #include "opt_sio.h"
43 #include "use_pci.h"
44 #ifdef __i386__
45 #include "use_puc.h"
46 #endif
47 #include "use_sio.h"
48
49 /*
50  * Serial driver, based on 386BSD-0.1 com driver.
51  * Mostly rewritten to use pseudo-DMA.
52  * Works for National Semiconductor NS8250-NS16550AF UARTs.
53  * COM driver, based on HP dca driver.
54  *
55  * Changes for PC-Card integration:
56  *      - Added PC-Card driver table and handlers
57  */
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/reboot.h>
61 #include <sys/malloc.h>
62 #include <sys/tty.h>
63 #include <sys/proc.h>
64 #include <sys/module.h>
65 #include <sys/conf.h>
66 #include <sys/dkstat.h>
67 #include <sys/fcntl.h>
68 #include <sys/interrupt.h>
69 #include <sys/kernel.h>
70 #include <sys/syslog.h>
71 #include <sys/sysctl.h>
72 #include <sys/bus.h>
73 #include <machine/bus_pio.h>
74 #include <machine/bus.h>
75 #include <sys/rman.h>
76 #include <sys/timepps.h>
77 #include <sys/thread2.h>
78
79 #include <machine/limits.h>
80
81 #include <bus/isa/isareg.h>
82 #include <bus/isa/isavar.h>
83 #if NPCI > 0
84 #include <bus/pci/pcireg.h>
85 #include <bus/pci/pcivar.h>
86 #endif
87 #if NPUC > 0
88 #include <dev/misc/puc/pucvar.h>
89 #endif
90 #include <machine/lock.h>
91
92 #include <machine/clock.h>
93 #include <machine/ipl.h>
94 #ifndef SMP
95 #include <machine/lock.h>
96 #endif
97 #include <machine/resource.h>
98
99 #include "sioreg.h"
100 #include "sio_private.h"
101
102 #ifdef COM_ESP
103 #include "../ic_layer/esp.h"
104 #endif
105
106 #define LOTS_OF_EVENTS  64      /* helps separate urgent events from input */
107
108 #define CALLOUT_MASK            0x80
109 #define CONTROL_MASK            0x60
110 #define CONTROL_INIT_STATE      0x20
111 #define CONTROL_LOCK_STATE      0x40
112 #define DEV_TO_UNIT(dev)        (MINOR_TO_UNIT(minor(dev)))
113 #define MINOR_TO_UNIT(mynor)    ((((mynor) & ~0xffffU) >> (8 + 3)) \
114                                  | ((mynor) & 0x1f))
115 #define UNIT_TO_MINOR(unit)     ((((unit) & ~0x1fU) << (8 + 3)) \
116                                  | ((unit) & 0x1f))
117
118 #define com_scr         7       /* scratch register for 16450-16550 (R/W) */
119
120 #define sio_getreg(com, off) \
121         (bus_space_read_1((com)->bst, (com)->bsh, (off)))
122 #define sio_setreg(com, off, value) \
123         (bus_space_write_1((com)->bst, (com)->bsh, (off), (value)))
124
125 /*
126  * com state bits.
127  * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
128  * than the other bits so that they can be tested as a group without masking
129  * off the low bits.
130  *
131  * The following com and tty flags correspond closely:
132  *      CS_BUSY         = TS_BUSY (maintained by comstart(), siopoll() and
133  *                                 comstop())
134  *      CS_TTGO         = ~TS_TTSTOP (maintained by comparam() and comstart())
135  *      CS_CTS_OFLOW    = CCTS_OFLOW (maintained by comparam())
136  *      CS_RTS_IFLOW    = CRTS_IFLOW (maintained by comparam())
137  * TS_FLUSH is not used.
138  * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
139  * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
140  */
141 #define CS_BUSY         0x80    /* output in progress */
142 #define CS_TTGO         0x40    /* output not stopped by XOFF */
143 #define CS_ODEVREADY    0x20    /* external device h/w ready (CTS) */
144 #define CS_CHECKMSR     1       /* check of MSR scheduled */
145 #define CS_CTS_OFLOW    2       /* use CTS output flow control */
146 #define CS_DTR_OFF      0x10    /* DTR held off */
147 #define CS_ODONE        4       /* output completed */
148 #define CS_RTS_IFLOW    8       /* use RTS input flow control */
149 #define CSE_BUSYCHECK   1       /* siobusycheck() scheduled */
150
151 static  char const * const      error_desc[] = {
152 #define CE_OVERRUN                      0
153         "silo overflow",
154 #define CE_INTERRUPT_BUF_OVERFLOW       1
155         "interrupt-level buffer overflow",
156 #define CE_TTY_BUF_OVERFLOW             2
157         "tty-level buffer overflow",
158 };
159
160 #ifdef COM_ESP
161 static  int     espattach       (struct com_s *com, Port_t esp_port);
162 #endif
163 static  int     sio_isa_attach  (device_t dev);
164
165 static  timeout_t siobusycheck;
166 static  u_int   siodivisor      (u_long rclk, speed_t speed);
167 static  timeout_t siodtrwakeup;
168 static  void    comhardclose    (struct com_s *com);
169 static  void    sioinput        (struct com_s *com);
170 static  void    siointr1        (struct com_s *com);
171 static  void    siointr         (void *arg);
172 static  int     commctl         (struct com_s *com, int bits, int how);
173 static  int     comparam        (struct tty *tp, struct termios *t);
174 static  inthand2_t siopoll;
175 static  int     sio_isa_probe   (device_t dev);
176 static  void    siosettimeout   (void);
177 static  int     siosetwater     (struct com_s *com, speed_t speed);
178 static  void    comstart        (struct tty *tp);
179 static  void    comstop         (struct tty *tp, int rw);
180 static  timeout_t comwakeup;
181 static  void    disc_optim      (struct tty     *tp, struct termios *t,
182                                      struct com_s *com);
183
184 #if NPCI > 0
185 static  int     sio_pci_attach (device_t dev);
186 static  void    sio_pci_kludge_unit (device_t dev);
187 static  int     sio_pci_probe (device_t dev);
188 #endif /* NPCI > 0 */
189
190 #if NPUC > 0
191 static  int     sio_puc_attach (device_t dev);
192 static  int     sio_puc_probe (device_t dev);
193 #endif /* NPUC > 0 */
194
195 static char driver_name[] = "sio";
196
197 /* table and macro for fast conversion from a unit number to its com struct */
198 devclass_t      sio_devclass;
199 #define com_addr(unit)  ((struct com_s *) \
200                          devclass_get_softc(sio_devclass, unit))
201
202 static device_method_t sio_isa_methods[] = {
203         /* Device interface */
204         DEVMETHOD(device_probe,         sio_isa_probe),
205         DEVMETHOD(device_attach,        sio_isa_attach),
206
207         { 0, 0 }
208 };
209
210 static driver_t sio_isa_driver = {
211         driver_name,
212         sio_isa_methods,
213         sizeof(struct com_s),
214 };
215
216 #if NPCI > 0
217 static device_method_t sio_pci_methods[] = {
218         /* Device interface */
219         DEVMETHOD(device_probe,         sio_pci_probe),
220         DEVMETHOD(device_attach,        sio_pci_attach),
221
222         { 0, 0 }
223 };
224
225 static driver_t sio_pci_driver = {
226         driver_name,
227         sio_pci_methods,
228         sizeof(struct com_s),
229 };
230 #endif /* NPCI > 0 */
231
232 #if NPUC > 0
233 static device_method_t sio_puc_methods[] = {
234         /* Device interface */
235         DEVMETHOD(device_probe,         sio_puc_probe),
236         DEVMETHOD(device_attach,        sio_puc_attach),
237
238         { 0, 0 }
239 };
240
241 static driver_t sio_puc_driver = {
242         driver_name,
243         sio_puc_methods,
244         sizeof(struct com_s),
245 };
246 #endif /* NPUC > 0 */
247
248 static  d_open_t        sioopen;
249 static  d_close_t       sioclose;
250 static  d_read_t        sioread;
251 static  d_write_t       siowrite;
252 static  d_ioctl_t       sioioctl;
253
254 #define CDEV_MAJOR      28
255 static struct dev_ops sio_ops = {
256         { driver_name, CDEV_MAJOR, D_TTY | D_KQFILTER },
257         .d_open =       sioopen,
258         .d_close =      sioclose,
259         .d_read =       sioread,
260         .d_write =      siowrite,
261         .d_ioctl =      sioioctl,
262         .d_poll =       ttypoll,
263         .d_kqfilter =   ttykqfilter
264 };
265
266 int     comconsole = -1;
267 static  volatile speed_t        comdefaultrate = CONSPEED;
268 static  u_long                  comdefaultrclk = DEFAULT_RCLK;
269 SYSCTL_ULONG(_machdep, OID_AUTO, conrclk, CTLFLAG_RW, &comdefaultrclk, 0, "");
270 static  u_int   com_events;     /* input chars + weighted output completions */
271 static  Port_t  siocniobase;
272 static  int     siocnunit;
273 static  Port_t  siogdbiobase;
274 static  int     siogdbunit = -1;
275 static  bool_t  sio_registered;
276 static  int     sio_timeout;
277 static  int     sio_timeouts_until_log;
278 static  struct  callout sio_timeout_handle;
279 static  int     sio_numunits;
280
281 #ifdef COM_ESP
282 /* XXX configure this properly. */
283 static  Port_t  likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
284 static  Port_t  likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
285 #endif
286
287 /*
288  * handle sysctl read/write requests for console speed
289  * 
290  * In addition to setting comdefaultrate for I/O through /dev/console,
291  * also set the initial and lock values for the /dev/ttyXX device
292  * if there is one associated with the console.  Finally, if the /dev/tty
293  * device has already been open, change the speed on the open running port
294  * itself.
295  */
296
297 static int
298 sysctl_machdep_comdefaultrate(SYSCTL_HANDLER_ARGS)
299 {
300         int error;
301         speed_t newspeed;
302         struct com_s *com;
303         struct tty *tp;
304
305         newspeed = comdefaultrate;
306
307         error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req);
308         if (error || !req->newptr)
309                 return (error);
310
311         comdefaultrate = newspeed;
312
313         if (comconsole < 0)             /* serial console not selected? */
314                 return (0);
315
316         com = com_addr(comconsole);
317         if (com == NULL)
318                 return (ENXIO);
319
320         /*
321          * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX
322          * (note, the lock rates really are boolean -- if non-zero, disallow
323          *  speed changes)
324          */
325         com->it_in.c_ispeed  = com->it_in.c_ospeed =
326         com->lt_in.c_ispeed  = com->lt_in.c_ospeed =
327         com->it_out.c_ispeed = com->it_out.c_ospeed =
328         com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate;
329
330         /*
331          * if we're open, change the running rate too
332          */
333         tp = com->tp;
334         if (tp && (tp->t_state & TS_ISOPEN)) {
335                 tp->t_termios.c_ispeed =
336                 tp->t_termios.c_ospeed = comdefaultrate;
337                 crit_enter();
338                 error = comparam(tp, &tp->t_termios);
339                 crit_exit();
340         }
341         return error;
342 }
343
344 SYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW,
345             0, 0, sysctl_machdep_comdefaultrate, "I", "");
346
347 #if NPCI > 0
348 struct pci_ids {
349         u_int32_t       type;
350         const char      *desc;
351         int             rid;
352 };
353
354 static struct pci_ids pci_ids[] = {
355         { 0x100812b9, "3COM PCI FaxModem", 0x10 },
356         { 0x2000131f, "CyberSerial (1-port) 16550", 0x10 },
357         { 0x01101407, "Koutech IOFLEX-2S PCI Dual Port Serial", 0x10 },
358         { 0x01111407, "Koutech IOFLEX-2S PCI Dual Port Serial", 0x10 },
359         { 0x048011c1, "Lucent kermit based PCI Modem", 0x14 },
360         { 0x95211415, "Oxford Semiconductor PCI Dual Port Serial", 0x10 },
361         { 0x7101135e, "SeaLevel Ultra 530.PCI Single Port Serial", 0x18 },
362         { 0x0000151f, "SmartLink 5634PCV SurfRider", 0x10 },
363         { 0x98459710, "Netmos Nm9845 PCI Bridge with Dual UART", 0x10 },
364         { 0x00000000, NULL, 0 }
365 };
366
367 static int
368 sio_pci_attach(dev)
369         device_t        dev;
370 {
371         u_int32_t       type;
372         struct pci_ids  *id;
373
374         type = pci_get_devid(dev);
375         id = pci_ids;
376         while (id->type && id->type != type)
377                 id++;
378         if (id->desc == NULL)
379                 return (ENXIO);
380         sio_pci_kludge_unit(dev);
381         return (sioattach(dev, id->rid, 0UL));
382 }
383
384 /*
385  * Don't cut and paste this to other drivers.  It is a horrible kludge
386  * which will fail to work and also be unnecessary in future versions.
387  */
388 static void
389 sio_pci_kludge_unit(dev)
390         device_t dev;
391 {
392         devclass_t      dc;
393         int             err;
394         int             start;
395         int             unit;
396
397         unit = 0;
398         start = 0;
399         while (resource_int_value("sio", unit, "port", &start) == 0 && 
400             start > 0)
401                 unit++;
402         if (device_get_unit(dev) < unit) {
403                 dc = device_get_devclass(dev);
404                 while (devclass_get_device(dc, unit))
405                         unit++;
406                 device_printf(dev, "moving to sio%d\n", unit);
407                 err = device_set_unit(dev, unit);       /* EVIL DO NOT COPY */
408                 if (err)
409                         device_printf(dev, "error moving device %d\n", err);
410         }
411 }
412
413 static int
414 sio_pci_probe(dev)
415         device_t        dev;
416 {
417         u_int32_t       type;
418         struct pci_ids  *id;
419
420         type = pci_get_devid(dev);
421         id = pci_ids;
422         while (id->type && id->type != type)
423                 id++;
424         if (id->desc == NULL)
425                 return (ENXIO);
426         device_set_desc(dev, id->desc);
427         return (sioprobe(dev, id->rid, 0UL));
428 }
429 #endif /* NPCI > 0 */
430
431 #if NPUC > 0
432 static int
433 sio_puc_attach(dev)
434         device_t        dev;
435 {
436         u_int rclk;
437
438         if (BUS_READ_IVAR(device_get_parent(dev), dev, PUC_IVAR_FREQ,
439             &rclk) != 0)
440                 rclk = DEFAULT_RCLK;
441         return (sioattach(dev, 0, rclk));
442 }
443
444 static int
445 sio_puc_probe(dev)
446         device_t        dev;
447 {
448         u_int rclk;
449
450         if (BUS_READ_IVAR(device_get_parent(dev), dev, PUC_IVAR_FREQ,
451             &rclk) != 0)
452                 rclk = DEFAULT_RCLK;
453         return (sioprobe(dev, 0, rclk));
454 }
455 #endif /* NPUC */
456
457 static struct isa_pnp_id sio_ids[] = {
458         {0x0005d041, "Standard PC COM port"},   /* PNP0500 */
459         {0x0105d041, "16550A-compatible COM port"},     /* PNP0501 */
460         {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
461         {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */
462         {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */
463         /* Devices that do not have a compatid */
464         {0x12206804, NULL},     /* ACH2012 - 5634BTS 56K Video Ready Modem */
465         {0x7602a904, NULL},     /* AEI0276 - 56K v.90 Fax Modem (LKT) */
466         {0x00007905, NULL},     /* AKY0000 - 56K Plug&Play Modem */
467         {0x21107905, NULL},     /* AKY1021 - 56K Plug&Play Modem */
468         {0x01405407, NULL},     /* AZT4001 - AZT3000 PnP SOUND DEVICE, MODEM */
469         {0x56039008, NULL},     /* BDP0356 - Best Data 56x2 */
470         {0x56159008, NULL},     /* BDP1556 - B.D. Smart One 56SPS,Voice Modem*/
471         {0x36339008, NULL},     /* BDP3336 - Best Data Prods. 336F */
472         {0x0014490a, NULL},     /* BRI1400 - Boca 33.6 PnP */
473         {0x0015490a, NULL},     /* BRI1500 - Internal Fax Data */
474         {0x0034490a, NULL},     /* BRI3400 - Internal ACF Modem */
475         {0x0094490a, NULL},     /* BRI9400 - Boca K56Flex PnP */
476         {0x00b4490a, NULL},     /* BRIB400 - Boca 56k PnP */
477         {0x0030320d, NULL},     /* CIR3000 - Cirrus Logic V43 */
478         {0x0100440e, NULL},     /* CRD0001 - Cardinal MVP288IV ? */
479         {0x01308c0e, NULL},     /* CTL3001 - Creative Labs Phoneblaster */
480         {0x36033610, NULL},     /* DAV0336 - DAVICOM 336PNP MODEM */
481         {0x01009416, NULL},     /* ETT0001 - E-Tech Bullet 33k6 PnP */
482         {0x0000aa1a, NULL},     /* FUJ0000 - FUJITSU Modem 33600 PNP/I2 */
483         {0x1200c31e, NULL},     /* GVC0012 - VF1128HV-R9 (win modem?) */
484         {0x0303c31e, NULL},     /* GVC0303 - MaxTech 33.6 PnP D/F/V */
485         {0x0505c31e, NULL},     /* GVC0505 - GVC 56k Faxmodem */
486         {0x0116c31e, NULL},     /* GVC1601 - Rockwell V.34 Plug & Play Modem */
487         {0x0050c31e, NULL},     /* GVC5000 - some GVC modem */
488         {0x3800f91e, NULL},     /* GWY0038 - Telepath with v.90 */
489         {0x9062f91e, NULL},     /* GWY6290 - Telepath with x2 Technology */
490         {0x8100e425, NULL},     /* IOD0081 - I-O DATA DEVICE,INC. IFML-560 */
491         {0x21002534, NULL},     /* MAE0021 - Jetstream Int V.90 56k Voice Series 2*/
492         {0x0000f435, NULL},     /* MOT0000 - Motorola ModemSURFR 33.6 Intern */
493         {0x5015f435, NULL},     /* MOT1550 - Motorola ModemSURFR 56K Modem */
494         {0xf015f435, NULL},     /* MOT15F0 - Motorola VoiceSURFR 56K Modem */
495         {0x6045f435, NULL},     /* MOT4560 - Motorola ? */
496         {0x61e7a338, NULL},     /* NECE761 - 33.6Modem */
497         {0x08804f3f, NULL},     /* OZO8008 - Zoom  (33.6k Modem) */
498         {0x0f804f3f, NULL},     /* OZO800f - Zoom 2812 (56k Modem) */
499         {0x39804f3f, NULL},     /* OZO8039 - Zoom 56k flex */
500         {0x00914f3f, NULL},     /* OZO9100 - Zoom 2919 (K56 Faxmodem) */
501         {0x3024a341, NULL},     /* PMC2430 - Pace 56 Voice Internal Modem */
502         {0x1000eb49, NULL},     /* ROK0010 - Rockwell ? */
503         {0x1200b23d, NULL},     /* RSS0012 - OMRON ME5614ISA */
504         {0x5002734a, NULL},     /* RSS0250 - 5614Jx3(G) Internal Modem */
505         {0x6202734a, NULL},     /* RSS0262 - 5614Jx3[G] V90+K56Flex Modem */
506         {0x1010104d, NULL},     /* SHP1010 - Rockwell 33600bps Modem */
507         {0xc100ad4d, NULL},     /* SMM00C1 - Leopard 56k PnP */
508         {0x9012b04e, NULL},     /* SUP1290 - Supra ? */
509         {0x1013b04e, NULL},     /* SUP1310 - SupraExpress 336i PnP */
510         {0x8013b04e, NULL},     /* SUP1380 - SupraExpress 288i PnP Voice */
511         {0x8113b04e, NULL},     /* SUP1381 - SupraExpress 336i PnP Voice */
512         {0x5016b04e, NULL},     /* SUP1650 - Supra 336i Sp Intl */
513         {0x7016b04e, NULL},     /* SUP1670 - Supra 336i V+ Intl */
514         {0x7420b04e, NULL},     /* SUP2070 - Supra ? */
515         {0x8020b04e, NULL},     /* SUP2080 - Supra ? */
516         {0x8420b04e, NULL},     /* SUP2084 - SupraExpress 56i PnP */
517         {0x7121b04e, NULL},     /* SUP2171 - SupraExpress 56i Sp? */
518         {0x8024b04e, NULL},     /* SUP2480 - Supra ? */
519         {0x01007256, NULL},     /* USR0001 - U.S. Robotics Inc., Sportster W */
520         {0x02007256, NULL},     /* USR0002 - U.S. Robotics Inc. Sportster 33. */
521         {0x04007256, NULL},     /* USR0004 - USR Sportster 14.4k */
522         {0x06007256, NULL},     /* USR0006 - USR Sportster 33.6k */
523         {0x11007256, NULL},     /* USR0011 - USR ? */
524         {0x01017256, NULL},     /* USR0101 - USR ? */
525         {0x30207256, NULL},     /* USR2030 - U.S.Robotics Inc. Sportster 560 */
526         {0x50207256, NULL},     /* USR2050 - U.S.Robotics Inc. Sportster 33. */
527         {0x70207256, NULL},     /* USR2070 - U.S.Robotics Inc. Sportster 560 */
528         {0x30307256, NULL},     /* USR3030 - U.S. Robotics 56K FAX INT */
529         {0x31307256, NULL},     /* USR3031 - U.S. Robotics 56K FAX INT */
530         {0x50307256, NULL},     /* USR3050 - U.S. Robotics 56K FAX INT */
531         {0x70307256, NULL},     /* USR3070 - U.S. Robotics 56K Voice INT */
532         {0x90307256, NULL},     /* USR3090 - USR ? */
533         {0x70917256, NULL},     /* USR9170 - U.S. Robotics 56K FAX INT */
534         {0x90917256, NULL},     /* USR9190 - USR 56k Voice INT */
535         {0x0300695c, NULL},     /* WCI0003 - Fax/Voice/Modem/Speakphone/Asvd */
536         {0x01a0896a, NULL},     /* ZTIA001 - Zoom Internal V90 Faxmodem */
537         {0x61f7896a, NULL},     /* ZTIF761 - Zoom ComStar 33.6 */
538         {0}
539 };
540
541
542
543 static int
544 sio_isa_probe(dev)
545         device_t        dev;
546 {
547         /* Check isapnp ids */
548         if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO)
549                 return (ENXIO);
550         return (sioprobe(dev, 0, 0UL));
551 }
552
553 int
554 sioprobe(dev, xrid, rclk)
555         device_t        dev;
556         int             xrid;
557         u_long          rclk;
558 {
559 #if 0
560         static bool_t   already_init;
561         device_t        xdev;
562 #endif
563         struct com_s    *com;
564         u_int           divisor;
565         bool_t          failures[10];
566         int             fn;
567         device_t        idev;
568         Port_t          iobase;
569         intrmask_t      irqmap[4];
570         intrmask_t      irqs;
571         u_char          mcr_image;
572         int             result;
573         u_long          xirq;
574         u_int           flags = device_get_flags(dev);
575         int             rid;
576         struct resource *port;
577
578         rid = xrid;
579         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
580                                   0, ~0, IO_COMSIZE, RF_ACTIVE);
581         if (!port)
582                 return (ENXIO);
583
584         com = device_get_softc(dev);
585         com->bst = rman_get_bustag(port);
586         com->bsh = rman_get_bushandle(port);
587         if (rclk == 0)
588                 rclk = DEFAULT_RCLK;
589         com->rclk = rclk;
590
591 #if 0
592         /*
593          * XXX this is broken - when we are first called, there are no
594          * previously configured IO ports.  We could hard code
595          * 0x3f8, 0x2f8, 0x3e8, 0x2e8 etc but that's probably worse.
596          * This code has been doing nothing since the conversion since
597          * "count" is zero the first time around.
598          */
599         if (!already_init) {
600                 /*
601                  * Turn off MCR_IENABLE for all likely serial ports.  An unused
602                  * port with its MCR_IENABLE gate open will inhibit interrupts
603                  * from any used port that shares the interrupt vector.
604                  * XXX the gate enable is elsewhere for some multiports.
605                  */
606                 device_t *devs;
607                 int count, i, xioport;
608
609                 devclass_get_devices(sio_devclass, &devs, &count);
610                 for (i = 0; i < count; i++) {
611                         xdev = devs[i];
612                         if (device_is_enabled(xdev) &&
613                             bus_get_resource(xdev, SYS_RES_IOPORT, 0, &xioport,
614                                              NULL) == 0)
615                                 outb(xioport + com_mcr, 0);
616                 }
617                 free(devs, M_TEMP);
618                 already_init = TRUE;
619         }
620 #endif
621
622         if (COM_LLCONSOLE(flags)) {
623                 printf("sio%d: reserved for low-level i/o\n",
624                        device_get_unit(dev));
625                 bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
626                 return (ENXIO);
627         }
628
629         /*
630          * If the device is on a multiport card and has an AST/4
631          * compatible interrupt control register, initialize this
632          * register and prepare to leave MCR_IENABLE clear in the mcr.
633          * Otherwise, prepare to set MCR_IENABLE in the mcr.
634          * Point idev to the device struct giving the correct id_irq.
635          * This is the struct for the master device if there is one.
636          */
637         idev = dev;
638         mcr_image = MCR_IENABLE;
639 #ifdef COM_MULTIPORT
640         if (COM_ISMULTIPORT(flags)) {
641                 Port_t xiobase;
642                 u_long io;
643
644                 idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags));
645                 if (idev == NULL) {
646                         printf("sio%d: master device %d not configured\n",
647                                device_get_unit(dev), COM_MPMASTER(flags));
648                         idev = dev;
649                 }
650                 if (!COM_NOTAST4(flags)) {
651                         if (bus_get_resource(idev, SYS_RES_IOPORT, 0, &io,
652                                              NULL) == 0) {
653                                 xiobase = io;
654                                 if (bus_get_resource(idev, SYS_RES_IRQ, 0,
655                                     NULL, NULL) == 0)
656                                         outb(xiobase + com_scr, 0x80);
657                                 else
658                                         outb(xiobase + com_scr, 0);
659                         }
660                         mcr_image = 0;
661                 }
662         }
663 #endif /* COM_MULTIPORT */
664         if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL) != 0)
665                 mcr_image = 0;
666
667         bzero(failures, sizeof failures);
668         iobase = rman_get_start(port);
669
670         /*
671          * We don't want to get actual interrupts, just masked ones.
672          * Interrupts from this line should already be masked in the ICU,
673          * but mask them in the processor as well in case there are some
674          * (misconfigured) shared interrupts.
675          */
676         com_lock();
677 /* EXTRA DELAY? */
678
679         /*
680          * For the TI16754 chips, set prescaler to 1 (4 is often the
681          * default after-reset value) as otherwise it's impossible to
682          * get highest baudrates.
683          */
684         if (COM_TI16754(flags)) {
685                 u_char cfcr, efr;
686
687                 cfcr = sio_getreg(com, com_cfcr);
688                 sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
689                 efr = sio_getreg(com, com_efr);
690                 /* Unlock extended features to turn off prescaler. */
691                 sio_setreg(com, com_efr, efr | EFR_EFE);
692                 /* Disable EFR. */
693                 sio_setreg(com, com_cfcr, (cfcr != CFCR_EFR_ENABLE) ? cfcr : 0);
694                 /* Turn off prescaler. */
695                 sio_setreg(com, com_mcr,
696                            sio_getreg(com, com_mcr) & ~MCR_PRESCALE);
697                 sio_setreg(com, com_cfcr, CFCR_EFR_ENABLE);
698                 sio_setreg(com, com_efr, efr);
699                 sio_setreg(com, com_cfcr, cfcr);
700         }
701
702         /*
703          * Initialize the speed and the word size and wait long enough to
704          * drain the maximum of 16 bytes of junk in device output queues.
705          * The speed is undefined after a master reset and must be set
706          * before relying on anything related to output.  There may be
707          * junk after a (very fast) soft reboot and (apparently) after
708          * master reset.
709          * XXX what about the UART bug avoided by waiting in comparam()?
710          * We don't want to to wait long enough to drain at 2 bps.
711          */
712         if (iobase == siocniobase) {
713                 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10));
714         } else {
715                 sio_setreg(com, com_cfcr, CFCR_DLAB | CFCR_8BITS);
716                 divisor = siodivisor(rclk, SIO_TEST_SPEED);
717                 sio_setreg(com, com_dlbl, divisor & 0xff);
718                 sio_setreg(com, com_dlbh, divisor >> 8);
719                 sio_setreg(com, com_cfcr, CFCR_8BITS);
720                 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10));
721         }
722
723         /*
724          * Make sure we can drain the receiver.  If we can't, the serial
725          * port may not exist.
726          */
727         for (fn = 0; fn < 256; ++fn) {
728                 if ((sio_getreg(com, com_lsr) & LSR_RXRDY) == 0)
729                         break;
730                 (void)sio_getreg(com, com_data);
731         }
732         if (fn == 256) {
733                 printf("sio%d: can't drain, serial port might "
734                         "not exist, disabling\n", device_get_unit(dev));
735                 com_unlock();
736                 return (ENXIO);
737         }
738
739         /*
740          * Enable the interrupt gate and disable device interupts.  This
741          * should leave the device driving the interrupt line low and
742          * guarantee an edge trigger if an interrupt can be generated.
743          */
744 /* EXTRA DELAY? */
745         sio_setreg(com, com_mcr, mcr_image);
746         sio_setreg(com, com_ier, 0);
747         DELAY(1000);            /* XXX */
748         irqmap[0] = isa_irq_pending();
749
750         /*
751          * Attempt to set loopback mode so that we can send a null byte
752          * without annoying any external device.
753          */
754 /* EXTRA DELAY? */
755         sio_setreg(com, com_mcr, mcr_image | MCR_LOOPBACK);
756
757         /*
758          * Attempt to generate an output interrupt.  On 8250's, setting
759          * IER_ETXRDY generates an interrupt independent of the current
760          * setting and independent of whether the THR is empty.  On 16450's,
761          * setting IER_ETXRDY generates an interrupt independent of the
762          * current setting.  On 16550A's, setting IER_ETXRDY only
763          * generates an interrupt when IER_ETXRDY is not already set.
764          */
765         sio_setreg(com, com_ier, IER_ETXRDY);
766
767         /*
768          * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
769          * an interrupt.  They'd better generate one for actually doing
770          * output.  Loopback may be broken on the same incompatibles but
771          * it's unlikely to do more than allow the null byte out.
772          */
773         sio_setreg(com, com_data, 0);
774         DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10));
775
776         /*
777          * Turn off loopback mode so that the interrupt gate works again
778          * (MCR_IENABLE was hidden).  This should leave the device driving
779          * an interrupt line high.  It doesn't matter if the interrupt
780          * line oscillates while we are not looking at it, since interrupts
781          * are disabled.
782          */
783 /* EXTRA DELAY? */
784         sio_setreg(com, com_mcr, mcr_image);
785
786         /*
787          * Some pcmcia cards have the "TXRDY bug", so we check everyone
788          * for IIR_TXRDY implementation ( Palido 321s, DC-1S... )
789          */
790         if (COM_NOPROBE(flags)) {
791                 /* Reading IIR register twice */
792                 for (fn = 0; fn < 2; fn ++) {
793                         DELAY(10000);
794                         failures[6] = sio_getreg(com, com_iir);
795                 }
796                 /* Check IIR_TXRDY clear ? */
797                 result = 0;
798                 if (failures[6] & IIR_TXRDY) {
799                         /* Nop, Double check with clearing IER */
800                         sio_setreg(com, com_ier, 0);
801                         if (sio_getreg(com, com_iir) & IIR_NOPEND) {
802                                 /* Ok. we're familia this gang */
803                                 SET_FLAG(dev, COM_C_IIR_TXRDYBUG);
804                         } else {
805                                 /* Unknown, Just omit this chip.. XXX */
806                                 result = ENXIO;
807                                 sio_setreg(com, com_mcr, 0);
808                         }
809                 } else {
810                         /* OK. this is well-known guys */
811                         CLR_FLAG(dev, COM_C_IIR_TXRDYBUG);
812                 }
813                 sio_setreg(com, com_ier, 0);
814                 sio_setreg(com, com_cfcr, CFCR_8BITS);
815                 com_unlock();
816                 bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
817                 return (iobase == siocniobase ? 0 : result);
818         }
819
820         /*
821          * Check that
822          *      o the CFCR, IER and MCR in UART hold the values written to them
823          *        (the values happen to be all distinct - this is good for
824          *        avoiding false positive tests from bus echoes).
825          *      o an output interrupt is generated and its vector is correct.
826          *      o the interrupt goes away when the IIR in the UART is read.
827          */
828 /* EXTRA DELAY? */
829         failures[0] = sio_getreg(com, com_cfcr) - CFCR_8BITS;
830         failures[1] = sio_getreg(com, com_ier) - IER_ETXRDY;
831         failures[2] = sio_getreg(com, com_mcr) - mcr_image;
832         DELAY(10000);           /* Some internal modems need this time */
833         irqmap[1] = isa_irq_pending();
834         failures[4] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_TXRDY;
835         DELAY(1000);            /* XXX */
836         irqmap[2] = isa_irq_pending();
837         failures[6] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
838
839         /*
840          * Turn off all device interrupts and check that they go off properly.
841          * Leave MCR_IENABLE alone.  For ports without a master port, it gates
842          * the OUT2 output of the UART to
843          * the ICU input.  Closing the gate would give a floating ICU input
844          * (unless there is another device driving it) and spurious interrupts.
845          * (On the system that this was first tested on, the input floats high
846          * and gives a (masked) interrupt as soon as the gate is closed.)
847          */
848         sio_setreg(com, com_ier, 0);
849         sio_setreg(com, com_cfcr, CFCR_8BITS);  /* dummy to avoid bus echo */
850         failures[7] = sio_getreg(com, com_ier);
851         DELAY(1000);            /* XXX */
852         irqmap[3] = isa_irq_pending();
853         failures[9] = (sio_getreg(com, com_iir) & IIR_IMASK) - IIR_NOPEND;
854
855         com_unlock();
856
857         irqs = irqmap[1] & ~irqmap[0];
858         if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 &&
859             ((1 << xirq) & irqs) == 0)
860                 printf(
861                 "sio%d: configured irq %ld not in bitmap of probed irqs %#x\n",
862                     device_get_unit(dev), xirq, irqs);
863         if (bootverbose)
864                 printf("sio%d: irq maps: %#x %#x %#x %#x\n",
865                     device_get_unit(dev),
866                     irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
867
868         result = 0;
869         for (fn = 0; fn < sizeof failures; ++fn)
870                 if (failures[fn]) {
871                         sio_setreg(com, com_mcr, 0);
872                         result = ENXIO;
873                         if (bootverbose) {
874                                 printf("sio%d: probe failed test(s):",
875                                     device_get_unit(dev));
876                                 for (fn = 0; fn < sizeof failures; ++fn)
877                                         if (failures[fn])
878                                                 printf(" %d", fn);
879                                 printf("\n");
880                         }
881                         break;
882                 }
883         bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
884         return (iobase == siocniobase ? 0 : result);
885 }
886
887 #ifdef COM_ESP
888 static int
889 espattach(com, esp_port)
890         struct com_s            *com;
891         Port_t                  esp_port;
892 {
893         u_char  dips;
894         u_char  val;
895
896         /*
897          * Check the ESP-specific I/O port to see if we're an ESP
898          * card.  If not, return failure immediately.
899          */
900         if ((inb(esp_port) & 0xf3) == 0) {
901                 printf(" port 0x%x is not an ESP board?\n", esp_port);
902                 return (0);
903         }
904
905         /*
906          * We've got something that claims to be a Hayes ESP card.
907          * Let's hope so.
908          */
909
910         /* Get the dip-switch configuration */
911         outb(esp_port + ESP_CMD1, ESP_GETDIPS);
912         dips = inb(esp_port + ESP_STATUS1);
913
914         /*
915          * Bits 0,1 of dips say which COM port we are.
916          */
917         if (rman_get_start(com->ioportres) == likely_com_ports[dips & 0x03])
918                 printf(" : ESP");
919         else {
920                 printf(" esp_port has com %d\n", dips & 0x03);
921                 return (0);
922         }
923
924         /*
925          * Check for ESP version 2.0 or later:  bits 4,5,6 = 010.
926          */
927         outb(esp_port + ESP_CMD1, ESP_GETTEST);
928         val = inb(esp_port + ESP_STATUS1);      /* clear reg 1 */
929         val = inb(esp_port + ESP_STATUS2);
930         if ((val & 0x70) < 0x20) {
931                 printf("-old (%o)", val & 0x70);
932                 return (0);
933         }
934
935         /*
936          * Check for ability to emulate 16550:  bit 7 == 1
937          */
938         if ((dips & 0x80) == 0) {
939                 printf(" slave");
940                 return (0);
941         }
942
943         /*
944          * Okay, we seem to be a Hayes ESP card.  Whee.
945          */
946         com->esp = TRUE;
947         com->esp_port = esp_port;
948         return (1);
949 }
950 #endif /* COM_ESP */
951
952 static int
953 sio_isa_attach(dev)
954         device_t        dev;
955 {
956         return (sioattach(dev, 0, 0UL));
957 }
958
959 int
960 sioattach(dev, xrid, rclk)
961         device_t        dev;
962         int             xrid;
963         u_long          rclk;
964 {
965         struct com_s    *com;
966 #ifdef COM_ESP
967         Port_t          *espp;
968 #endif
969         Port_t          iobase;
970         int             minorbase;
971         int             unit;
972         u_int           flags;
973         int             rid;
974         struct resource *port;
975         int             ret;
976         static int      did_init;
977
978         if (did_init == 0) {
979                 did_init = 1;
980                 callout_init(&sio_timeout_handle);
981         }
982
983         rid = xrid;
984         port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
985                                   0, ~0, IO_COMSIZE, RF_ACTIVE);
986         if (!port)
987                 return (ENXIO);
988
989         iobase = rman_get_start(port);
990         unit = device_get_unit(dev);
991         com = device_get_softc(dev);
992         flags = device_get_flags(dev);
993
994         if (unit >= sio_numunits)
995                 sio_numunits = unit + 1;
996         /*
997          * sioprobe() has initialized the device registers as follows:
998          *      o cfcr = CFCR_8BITS.
999          *        It is most important that CFCR_DLAB is off, so that the
1000          *        data port is not hidden when we enable interrupts.
1001          *      o ier = 0.
1002          *        Interrupts are only enabled when the line is open.
1003          *      o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
1004          *        interrupt control register or the config specifies no irq.
1005          *        Keeping MCR_DTR and MCR_RTS off might stop the external
1006          *        device from sending before we are ready.
1007          */
1008         bzero(com, sizeof *com);
1009         com->unit = unit;
1010         com->ioportres = port;
1011         com->bst = rman_get_bustag(port);
1012         com->bsh = rman_get_bushandle(port);
1013         com->cfcr_image = CFCR_8BITS;
1014         com->dtr_wait = 3 * hz;
1015         callout_init(&com->dtr_ch);
1016         callout_init(&com->busy_ch);
1017         com->loses_outints = COM_LOSESOUTINTS(flags) != 0;
1018         com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL) != 0;
1019         com->tx_fifo_size = 1;
1020         com->obufs[0].l_head = com->obuf1;
1021         com->obufs[1].l_head = com->obuf2;
1022
1023         com->data_port = iobase + com_data;
1024         com->int_id_port = iobase + com_iir;
1025         com->modem_ctl_port = iobase + com_mcr;
1026         com->mcr_image = inb(com->modem_ctl_port);
1027         com->line_status_port = iobase + com_lsr;
1028         com->modem_status_port = iobase + com_msr;
1029         com->intr_ctl_port = iobase + com_ier;
1030
1031         if (rclk == 0)
1032                 rclk = DEFAULT_RCLK;
1033         com->rclk = rclk;
1034
1035         /*
1036          * We don't use all the flags from <sys/ttydefaults.h> since they
1037          * are only relevant for logins.  It's important to have echo off
1038          * initially so that the line doesn't start blathering before the
1039          * echo flag can be turned off.
1040          */
1041         com->it_in.c_iflag = 0;
1042         com->it_in.c_oflag = 0;
1043         com->it_in.c_cflag = TTYDEF_CFLAG;
1044         com->it_in.c_lflag = 0;
1045         if (unit == comconsole) {
1046                 com->it_in.c_iflag = TTYDEF_IFLAG;
1047                 com->it_in.c_oflag = TTYDEF_OFLAG;
1048                 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
1049                 com->it_in.c_lflag = TTYDEF_LFLAG;
1050                 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
1051                 com->lt_out.c_ispeed = com->lt_out.c_ospeed =
1052                 com->lt_in.c_ispeed = com->lt_in.c_ospeed =
1053                 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
1054         } else
1055                 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
1056         if (siosetwater(com, com->it_in.c_ispeed) != 0) {
1057                 com_unlock();
1058                 /*
1059                  * Leave i/o resources allocated if this is a `cn'-level
1060                  * console, so that other devices can't snarf them.
1061                  */
1062                 if (iobase != siocniobase)
1063                         bus_release_resource(dev, SYS_RES_IOPORT, rid, port);
1064                 return (ENOMEM);
1065         }
1066         com_unlock();
1067         termioschars(&com->it_in);
1068         com->it_out = com->it_in;
1069
1070         /* attempt to determine UART type */
1071         printf("sio%d: type", unit);
1072
1073
1074 #ifdef COM_MULTIPORT
1075         if (!COM_ISMULTIPORT(flags) && !COM_IIR_TXRDYBUG(flags))
1076 #else
1077         if (!COM_IIR_TXRDYBUG(flags))
1078 #endif
1079         {
1080                 u_char  scr;
1081                 u_char  scr1;
1082                 u_char  scr2;
1083
1084                 scr = sio_getreg(com, com_scr);
1085                 sio_setreg(com, com_scr, 0xa5);
1086                 scr1 = sio_getreg(com, com_scr);
1087                 sio_setreg(com, com_scr, 0x5a);
1088                 scr2 = sio_getreg(com, com_scr);
1089                 sio_setreg(com, com_scr, scr);
1090                 if (scr1 != 0xa5 || scr2 != 0x5a) {
1091                         printf(" 8250");
1092                         goto determined_type;
1093                 }
1094         }
1095         sio_setreg(com, com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
1096         DELAY(100);
1097         com->st16650a = 0;
1098         switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
1099         case FIFO_RX_LOW:
1100                 printf(" 16450");
1101                 break;
1102         case FIFO_RX_MEDL:
1103                 printf(" 16450?");
1104                 break;
1105         case FIFO_RX_MEDH:
1106                 printf(" 16550?");
1107                 break;
1108         case FIFO_RX_HIGH:
1109                 if (COM_NOFIFO(flags)) {
1110                         printf(" 16550A fifo disabled");
1111                 } else {
1112                         com->hasfifo = TRUE;
1113                         if (COM_ST16650A(flags)) {
1114                                 com->st16650a = 1;
1115                                 com->tx_fifo_size = 32;
1116                                 printf(" ST16650A");
1117                         } else if (COM_TI16754(flags)) {
1118                                 com->tx_fifo_size = 64;
1119                                 printf(" TI16754");
1120                         } else {
1121                                 com->tx_fifo_size = COM_FIFOSIZE(flags);
1122                                 printf(" 16550A");
1123                         }
1124                 }
1125 #ifdef COM_ESP
1126                 for (espp = likely_esp_ports; *espp != 0; espp++)
1127                         if (espattach(com, *espp)) {
1128                                 com->tx_fifo_size = 1024;
1129                                 break;
1130                         }
1131 #endif
1132                 if (!com->st16650a && !COM_TI16754(flags)) {
1133                         if (!com->tx_fifo_size)
1134                                 com->tx_fifo_size = 16;
1135                         else
1136                                 printf(" lookalike with %d bytes FIFO",
1137                                     com->tx_fifo_size);
1138                 }
1139
1140                 break;
1141         }
1142         
1143 #ifdef COM_ESP
1144         if (com->esp) {
1145                 /*
1146                  * Set 16550 compatibility mode.
1147                  * We don't use the ESP_MODE_SCALE bit to increase the
1148                  * fifo trigger levels because we can't handle large
1149                  * bursts of input.
1150                  * XXX flow control should be set in comparam(), not here.
1151                  */
1152                 outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
1153                 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
1154
1155                 /* Set RTS/CTS flow control. */
1156                 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
1157                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
1158                 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
1159
1160                 /* Set flow-control levels. */
1161                 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
1162                 outb(com->esp_port + ESP_CMD2, HIBYTE(768));
1163                 outb(com->esp_port + ESP_CMD2, LOBYTE(768));
1164                 outb(com->esp_port + ESP_CMD2, HIBYTE(512));
1165                 outb(com->esp_port + ESP_CMD2, LOBYTE(512));
1166         }
1167 #endif /* COM_ESP */
1168         sio_setreg(com, com_fifo, 0);
1169 determined_type: ;
1170
1171 #ifdef COM_MULTIPORT
1172         if (COM_ISMULTIPORT(flags)) {
1173                 device_t masterdev;
1174
1175                 com->multiport = TRUE;
1176                 printf(" (multiport");
1177                 if (unit == COM_MPMASTER(flags))
1178                         printf(" master");
1179                 printf(")");
1180                 masterdev = devclass_get_device(sio_devclass,
1181                     COM_MPMASTER(flags));
1182                 com->no_irq = (masterdev == NULL || bus_get_resource(masterdev,
1183                     SYS_RES_IRQ, 0, NULL, NULL) != 0);
1184          }
1185 #endif /* COM_MULTIPORT */
1186         if (unit == comconsole)
1187                 printf(", console");
1188         if (COM_IIR_TXRDYBUG(flags))
1189                 printf(" with a bogus IIR_TXRDY register");
1190         printf("\n");
1191
1192         if (!sio_registered) {
1193                 register_swi(SWI_TTY, siopoll, NULL ,"swi_siopoll", NULL);
1194                 sio_registered = TRUE;
1195         }
1196         minorbase = UNIT_TO_MINOR(unit);
1197         dev_ops_add(&sio_ops, UNIT_TO_MINOR(-1), minorbase);
1198         make_dev(&sio_ops, minorbase,
1199             UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit);
1200         make_dev(&sio_ops, minorbase | CONTROL_INIT_STATE,
1201             UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit);
1202         make_dev(&sio_ops, minorbase | CONTROL_LOCK_STATE,
1203             UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit);
1204         make_dev(&sio_ops, minorbase | CALLOUT_MASK,
1205             UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit);
1206         make_dev(&sio_ops, minorbase | CALLOUT_MASK | CONTROL_INIT_STATE,
1207             UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit);
1208         make_dev(&sio_ops, minorbase | CALLOUT_MASK | CONTROL_LOCK_STATE,
1209             UID_UUCP, GID_DIALER, 0660, "cuala%r", unit);
1210         com->flags = flags;
1211         com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
1212         pps_init(&com->pps);
1213
1214         rid = 0;
1215         com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1,
1216             RF_ACTIVE);
1217         if (com->irqres) {
1218                 ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres,
1219                                      INTR_FAST, siointr, com,
1220                                      &com->cookie, NULL);
1221                 if (ret) {
1222                         ret = BUS_SETUP_INTR(device_get_parent(dev), dev,
1223                                              com->irqres, 0, siointr, com,
1224                                              &com->cookie, NULL);
1225                         if (ret == 0)
1226                                 device_printf(dev, "unable to activate interrupt in fast mode - using normal mode\n");
1227                 }
1228                 if (ret)
1229                         device_printf(dev, "could not activate interrupt\n");
1230 #if defined(DDB) && (defined(BREAK_TO_DEBUGGER) || \
1231     defined(ALT_BREAK_TO_DEBUGGER))
1232                 /*
1233                  * Enable interrupts for early break-to-debugger support
1234                  * on the console.
1235                  */
1236                 if (ret == 0 && unit == comconsole)
1237                         outb(siocniobase + com_ier, IER_ERXRDY | IER_ERLS |
1238                             IER_EMSC);
1239 #endif
1240         }
1241
1242         return (0);
1243 }
1244
1245 static int
1246 sioopen(struct dev_open_args *ap)
1247 {
1248         dev_t dev = ap->a_head.a_dev;
1249         struct com_s    *com;
1250         int             error;
1251         int             mynor;
1252         struct tty      *tp;
1253         int             unit;
1254
1255         mynor = minor(dev);
1256         unit = MINOR_TO_UNIT(mynor);
1257         com = com_addr(unit);
1258         if (com == NULL)
1259                 return (ENXIO);
1260         if (com->gone)
1261                 return (ENXIO);
1262         if (mynor & CONTROL_MASK)
1263                 return (0);
1264         tp = dev->si_tty = com->tp = ttymalloc(com->tp);
1265         crit_enter();
1266         /*
1267          * We jump to this label after all non-interrupted sleeps to pick
1268          * up any changes of the device state.
1269          */
1270 open_top:
1271         while (com->state & CS_DTR_OFF) {
1272                 error = tsleep(&com->dtr_wait, PCATCH, "siodtr", 0);
1273                 if (com_addr(unit) == NULL) {
1274                         crit_exit();
1275                         return (ENXIO);
1276                 }
1277                 if (error != 0 || com->gone)
1278                         goto out;
1279         }
1280         if (tp->t_state & TS_ISOPEN) {
1281                 /*
1282                  * The device is open, so everything has been initialized.
1283                  * Handle conflicts.
1284                  */
1285                 if (mynor & CALLOUT_MASK) {
1286                         if (!com->active_out) {
1287                                 error = EBUSY;
1288                                 goto out;
1289                         }
1290                 } else {
1291                         if (com->active_out) {
1292                                 if (ap->a_oflags & O_NONBLOCK) {
1293                                         error = EBUSY;
1294                                         goto out;
1295                                 }
1296                                 error = tsleep(&com->active_out,
1297                                                PCATCH, "siobi", 0);
1298                                 if (com_addr(unit) == NULL) {
1299                                         crit_exit();
1300                                         return (ENXIO);
1301                                 }
1302                                 if (error != 0 || com->gone)
1303                                         goto out;
1304                                 goto open_top;
1305                         }
1306                 }
1307                 if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0)) {
1308                         error = EBUSY;
1309                         goto out;
1310                 }
1311         } else {
1312                 /*
1313                  * The device isn't open, so there are no conflicts.
1314                  * Initialize it.  Initialization is done twice in many
1315                  * cases: to preempt sleeping callin opens if we are
1316                  * callout, and to complete a callin open after DCD rises.
1317                  */
1318                 tp->t_oproc = comstart;
1319                 tp->t_param = comparam;
1320                 tp->t_stop = comstop;
1321                 tp->t_dev = dev;
1322                 tp->t_termios = mynor & CALLOUT_MASK
1323                                 ? com->it_out : com->it_in;
1324                 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
1325                 com->poll = com->no_irq;
1326                 com->poll_output = com->loses_outints;
1327                 ++com->wopeners;
1328                 error = comparam(tp, &tp->t_termios);
1329                 --com->wopeners;
1330                 if (error != 0)
1331                         goto out;
1332                 /*
1333                  * XXX we should goto open_top if comparam() slept.
1334                  */
1335                 if (com->hasfifo) {
1336                         /*
1337                          * (Re)enable and drain fifos.
1338                          *
1339                          * Certain SMC chips cause problems if the fifos
1340                          * are enabled while input is ready.  Turn off the
1341                          * fifo if necessary to clear the input.  We test
1342                          * the input ready bit after enabling the fifos
1343                          * since we've already enabled them in comparam()
1344                          * and to handle races between enabling and fresh
1345                          * input.
1346                          */
1347                         while (TRUE) {
1348                                 sio_setreg(com, com_fifo,
1349                                            FIFO_RCV_RST | FIFO_XMT_RST
1350                                            | com->fifo_image);
1351                                 /*
1352                                  * XXX the delays are for superstitious
1353                                  * historical reasons.  It must be less than
1354                                  * the character time at the maximum
1355                                  * supported speed (87 usec at 115200 bps
1356                                  * 8N1).  Otherwise we might loop endlessly
1357                                  * if data is streaming in.  We used to use
1358                                  * delays of 100.  That usually worked
1359                                  * because DELAY(100) used to usually delay
1360                                  * for about 85 usec instead of 100.
1361                                  */
1362                                 DELAY(50);
1363                                 if (!(inb(com->line_status_port) & LSR_RXRDY))
1364                                         break;
1365                                 sio_setreg(com, com_fifo, 0);
1366                                 DELAY(50);
1367                                 (void) inb(com->data_port);
1368                         }
1369                 }
1370
1371                 com_lock();
1372                 (void) inb(com->line_status_port);
1373                 (void) inb(com->data_port);
1374                 com->prev_modem_status = com->last_modem_status
1375                     = inb(com->modem_status_port);
1376                 if (COM_IIR_TXRDYBUG(com->flags)) {
1377                         outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS
1378                                                 | IER_EMSC);
1379                 } else {
1380                         outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY
1381                                                 | IER_ERLS | IER_EMSC);
1382                 }
1383                 com_unlock();
1384                 /*
1385                  * Handle initial DCD.  Callout devices get a fake initial
1386                  * DCD (trapdoor DCD).  If we are callout, then any sleeping
1387                  * callin opens get woken up and resume sleeping on "siobi"
1388                  * instead of "siodcd".
1389                  */
1390                 /*
1391                  * XXX `mynor & CALLOUT_MASK' should be
1392                  * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
1393                  * TRAPDOOR_CARRIER is the default initial state for callout
1394                  * devices and SOFT_CARRIER is like CLOCAL except it hides
1395                  * the true carrier.
1396                  */
1397                 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
1398                         (*linesw[tp->t_line].l_modem)(tp, 1);
1399         }
1400         /*
1401          * Wait for DCD if necessary.
1402          */
1403         if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1404             && !(tp->t_cflag & CLOCAL) && !(ap->a_oflags & O_NONBLOCK)) {
1405                 ++com->wopeners;
1406                 error = tsleep(TSA_CARR_ON(tp), PCATCH, "siodcd", 0);
1407                 if (com_addr(unit) == NULL) {
1408                         crit_exit();
1409                         return (ENXIO);
1410                 }
1411                 --com->wopeners;
1412                 if (error != 0 || com->gone)
1413                         goto out;
1414                 goto open_top;
1415         }
1416         error = (*linesw[tp->t_line].l_open)(dev, tp);
1417         disc_optim(tp, &tp->t_termios, com);
1418         if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1419                 com->active_out = TRUE;
1420         siosettimeout();
1421 out:
1422         crit_exit();
1423         if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
1424                 comhardclose(com);
1425         return (error);
1426 }
1427
1428 static int
1429 sioclose(struct dev_close_args *ap)
1430 {
1431         dev_t dev = ap->a_head.a_dev;
1432         struct com_s    *com;
1433         int             mynor;
1434         struct tty      *tp;
1435
1436         mynor = minor(dev);
1437         if (mynor & CONTROL_MASK)
1438                 return (0);
1439         com = com_addr(MINOR_TO_UNIT(mynor));
1440         if (com == NULL)
1441                 return (ENODEV);
1442         tp = com->tp;
1443         crit_enter();
1444         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
1445         disc_optim(tp, &tp->t_termios, com);
1446         comstop(tp, FREAD | FWRITE);
1447         comhardclose(com);
1448         ttyclose(tp);
1449         siosettimeout();
1450         crit_exit();
1451         if (com->gone) {
1452                 printf("sio%d: gone\n", com->unit);
1453                 crit_enter();
1454                 if (com->ibuf != NULL)
1455                         free(com->ibuf, M_DEVBUF);
1456                 bzero(tp, sizeof *tp);
1457                 crit_exit();
1458         }
1459         return (0);
1460 }
1461
1462 static void
1463 comhardclose(com)
1464         struct com_s    *com;
1465 {
1466         struct tty      *tp;
1467         int             unit;
1468
1469         unit = com->unit;
1470         crit_enter();
1471         com->poll = FALSE;
1472         com->poll_output = FALSE;
1473         com->do_timestamp = FALSE;
1474         com->do_dcd_timestamp = FALSE;
1475         com->pps.ppsparam.mode = 0;
1476         sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1477         tp = com->tp;
1478
1479 #if defined(DDB) && (defined(BREAK_TO_DEBUGGER) || \
1480     defined(ALT_BREAK_TO_DEBUGGER))
1481         /*
1482          * Leave interrupts enabled and don't clear DTR if this is the
1483          * console. This allows us to detect break-to-debugger events
1484          * while the console device is closed.
1485          */
1486         if (com->unit != comconsole)
1487 #endif
1488         {
1489                 sio_setreg(com, com_ier, 0);
1490                 if (tp->t_cflag & HUPCL
1491                     /*
1492                      * XXX we will miss any carrier drop between here and the
1493                      * next open.  Perhaps we should watch DCD even when the
1494                      * port is closed; it is not sufficient to check it at
1495                      * the next open because it might go up and down while
1496                      * we're not watching.
1497                      */
1498                     || (!com->active_out
1499                         && !(com->prev_modem_status & MSR_DCD)
1500                         && !(com->it_in.c_cflag & CLOCAL))
1501                     || !(tp->t_state & TS_ISOPEN)) {
1502                         (void)commctl(com, TIOCM_DTR, DMBIC);
1503                         if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
1504                                 callout_reset(&com->dtr_ch, com->dtr_wait,
1505                                                 siodtrwakeup, com);
1506                                 com->state |= CS_DTR_OFF;
1507                         }
1508                 }
1509         }
1510         if (com->hasfifo) {
1511                 /*
1512                  * Disable fifos so that they are off after controlled
1513                  * reboots.  Some BIOSes fail to detect 16550s when the
1514                  * fifos are enabled.
1515                  */
1516                 sio_setreg(com, com_fifo, 0);
1517         }
1518         com->active_out = FALSE;
1519         wakeup(&com->active_out);
1520         wakeup(TSA_CARR_ON(tp));        /* restart any wopeners */
1521         crit_exit();
1522 }
1523
1524 static int
1525 sioread(struct dev_read_args *ap)
1526 {
1527         dev_t dev = ap->a_head.a_dev;
1528         int             mynor;
1529         struct com_s    *com;
1530
1531         mynor = minor(dev);
1532         if (mynor & CONTROL_MASK)
1533                 return (ENODEV);
1534         com = com_addr(MINOR_TO_UNIT(mynor));
1535         if (com == NULL || com->gone)
1536                 return (ENODEV);
1537         return ((*linesw[com->tp->t_line].l_read)(com->tp, ap->a_uio, ap->a_ioflag));
1538 }
1539
1540 static int
1541 siowrite(struct dev_write_args *ap)
1542 {
1543         dev_t dev = ap->a_head.a_dev;
1544         int             mynor;
1545         struct com_s    *com;
1546         int             unit;
1547
1548         mynor = minor(dev);
1549         if (mynor & CONTROL_MASK)
1550                 return (ENODEV);
1551
1552         unit = MINOR_TO_UNIT(mynor);
1553         com = com_addr(unit);
1554         if (com == NULL || com->gone)
1555                 return (ENODEV);
1556         /*
1557          * (XXX) We disallow virtual consoles if the physical console is
1558          * a serial port.  This is in case there is a display attached that
1559          * is not the console.  In that situation we don't need/want the X
1560          * server taking over the console.
1561          */
1562         if (constty != NULL && unit == comconsole)
1563                 constty = NULL;
1564         return ((*linesw[com->tp->t_line].l_write)(com->tp, ap->a_uio, ap->a_ioflag));
1565 }
1566
1567 static void
1568 siobusycheck(chan)
1569         void    *chan;
1570 {
1571         struct com_s    *com;
1572
1573         com = (struct com_s *)chan;
1574
1575         /*
1576          * Clear TS_BUSY if low-level output is complete.
1577          * spl locking is sufficient because siointr1() does not set CS_BUSY.
1578          * If siointr1() clears CS_BUSY after we look at it, then we'll get
1579          * called again.  Reading the line status port outside of siointr1()
1580          * is safe because CS_BUSY is clear so there are no output interrupts
1581          * to lose.
1582          */
1583         crit_enter();
1584         if (com->state & CS_BUSY)
1585                 com->extra_state &= ~CSE_BUSYCHECK;     /* False alarm. */
1586         else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1587             == (LSR_TSRE | LSR_TXRDY)) {
1588                 com->tp->t_state &= ~TS_BUSY;
1589                 ttwwakeup(com->tp);
1590                 com->extra_state &= ~CSE_BUSYCHECK;
1591         } else {
1592                 callout_reset(&com->busy_ch, hz / 100, siobusycheck, com);
1593         }
1594         crit_exit();
1595 }
1596
1597 static u_int
1598 siodivisor(rclk, speed)
1599         u_long  rclk;
1600         speed_t speed;
1601 {
1602         long    actual_speed;
1603         u_int   divisor;
1604         int     error;
1605
1606         if (speed == 0 || speed > (ULONG_MAX - 1) / 8)
1607                 return (0);
1608         divisor = (rclk / (8UL * speed) + 1) / 2;
1609         if (divisor == 0 || divisor >= 65536)
1610                 return (0);
1611         actual_speed = rclk / (16UL * divisor);
1612
1613         /* 10 times error in percent: */
1614         error = ((actual_speed - (long)speed) * 2000 / (long)speed + 1) / 2;
1615
1616         /* 3.0% maximum error tolerance: */
1617         if (error < -30 || error > 30)
1618                 return (0);
1619
1620         return (divisor);
1621 }
1622
1623 static void
1624 siodtrwakeup(chan)
1625         void    *chan;
1626 {
1627         struct com_s    *com;
1628
1629         com = (struct com_s *)chan;
1630         com->state &= ~CS_DTR_OFF;
1631         wakeup(&com->dtr_wait);
1632 }
1633
1634 static void
1635 sioinput(com)
1636         struct com_s    *com;
1637 {
1638         u_char          *buf;
1639         int             incc;
1640         u_char          line_status;
1641         int             recv_data;
1642         struct tty      *tp;
1643
1644         buf = com->ibuf;
1645         tp = com->tp;
1646         if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) {
1647                 com_events -= (com->iptr - com->ibuf);
1648                 com->iptr = com->ibuf;
1649                 return;
1650         }
1651         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1652                 /*
1653                  * Avoid the grotesquely inefficient lineswitch routine
1654                  * (ttyinput) in "raw" mode.  It usually takes about 450
1655                  * instructions (that's without canonical processing or echo!).
1656                  * slinput is reasonably fast (usually 40 instructions plus
1657                  * call overhead).
1658                  */
1659                 do {
1660                         com_unlock();
1661                         incc = com->iptr - buf;
1662                         if (tp->t_rawq.c_cc + incc > tp->t_ihiwat
1663                             && (com->state & CS_RTS_IFLOW
1664                                 || tp->t_iflag & IXOFF)
1665                             && !(tp->t_state & TS_TBLOCK))
1666                                 ttyblock(tp);
1667                         com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1668                                 += b_to_q((char *)buf, incc, &tp->t_rawq);
1669                         buf += incc;
1670                         tk_nin += incc;
1671                         tk_rawcc += incc;
1672                         tp->t_rawcc += incc;
1673                         ttwakeup(tp);
1674                         if (tp->t_state & TS_TTSTOP
1675                             && (tp->t_iflag & IXANY
1676                                 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1677                                 tp->t_state &= ~TS_TTSTOP;
1678                                 tp->t_lflag &= ~FLUSHO;
1679                                 comstart(tp);
1680                         }
1681                         com_lock();
1682                 } while (buf < com->iptr);
1683         } else {
1684                 do {
1685                         com_unlock();
1686                         line_status = buf[com->ierroff];
1687                         recv_data = *buf++;
1688                         if (line_status
1689                             & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1690                                 if (line_status & LSR_BI)
1691                                         recv_data |= TTY_BI;
1692                                 if (line_status & LSR_FE)
1693                                         recv_data |= TTY_FE;
1694                                 if (line_status & LSR_OE)
1695                                         recv_data |= TTY_OE;
1696                                 if (line_status & LSR_PE)
1697                                         recv_data |= TTY_PE;
1698                         }
1699                         (*linesw[tp->t_line].l_rint)(recv_data, tp);
1700                         com_lock();
1701                 } while (buf < com->iptr);
1702         }
1703         com_events -= (com->iptr - com->ibuf);
1704         com->iptr = com->ibuf;
1705
1706         /*
1707          * There is now room for another low-level buffer full of input,
1708          * so enable RTS if it is now disabled and there is room in the
1709          * high-level buffer.
1710          */
1711         if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) &&
1712             !(tp->t_state & TS_TBLOCK))
1713                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
1714 }
1715
1716 void
1717 siointr(arg)
1718         void            *arg;
1719 {
1720 #ifndef COM_MULTIPORT
1721         com_lock();
1722         siointr1((struct com_s *) arg);
1723         com_unlock();
1724 #else /* COM_MULTIPORT */
1725         bool_t          possibly_more_intrs;
1726         int             unit;
1727         struct com_s    *com;
1728
1729         /*
1730          * Loop until there is no activity on any port.  This is necessary
1731          * to get an interrupt edge more than to avoid another interrupt.
1732          * If the IRQ signal is just an OR of the IRQ signals from several
1733          * devices, then the edge from one may be lost because another is
1734          * on.
1735          */
1736         com_lock();
1737         do {
1738                 possibly_more_intrs = FALSE;
1739                 for (unit = 0; unit < sio_numunits; ++unit) {
1740                         com = com_addr(unit);
1741                         /*
1742                          * XXX com_lock();
1743                          * would it work here, or be counter-productive?
1744                          */
1745                         if (com != NULL 
1746                             && !com->gone
1747                             && (inb(com->int_id_port) & IIR_IMASK)
1748                                != IIR_NOPEND) {
1749                                 siointr1(com);
1750                                 possibly_more_intrs = TRUE;
1751                         }
1752                         /* XXX com_unlock(); */
1753                 }
1754         } while (possibly_more_intrs);
1755         com_unlock();
1756 #endif /* COM_MULTIPORT */
1757 }
1758
1759 static void
1760 siointr1(com)
1761         struct com_s    *com;
1762 {
1763         u_char  line_status;
1764         u_char  modem_status;
1765         u_char  *ioptr;
1766         u_char  recv_data;
1767         u_char  int_ctl;
1768         u_char  int_ctl_new;
1769         u_int   count;
1770
1771         int_ctl = inb(com->intr_ctl_port);
1772         int_ctl_new = int_ctl;
1773
1774         while (!com->gone) {
1775                 if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) {
1776                         modem_status = inb(com->modem_status_port);
1777                         if ((modem_status ^ com->last_modem_status) & MSR_DCD) {
1778                                 count = sys_cputimer->count();
1779                                 pps_event(&com->pps, count, 
1780                                     (modem_status & MSR_DCD) ? 
1781                                     PPS_CAPTUREASSERT : PPS_CAPTURECLEAR);
1782                         }
1783                 }
1784                 line_status = inb(com->line_status_port);
1785
1786                 /* input event? (check first to help avoid overruns) */
1787                 while (line_status & LSR_RCV_MASK) {
1788                         /* break/unnattached error bits or real input? */
1789                         if (!(line_status & LSR_RXRDY))
1790                                 recv_data = 0;
1791                         else
1792                                 recv_data = inb(com->data_port);
1793 #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
1794                         /*
1795                          * Solaris implements a new BREAK which is initiated
1796                          * by a character sequence CR ~ ^b which is similar
1797                          * to a familiar pattern used on Sun servers by the
1798                          * Remote Console.
1799                          */
1800 #define KEY_CRTLB       2       /* ^B */
1801 #define KEY_CR          13      /* CR '\r' */
1802 #define KEY_TILDE       126     /* ~ */
1803
1804                         if (com->unit == comconsole) {
1805                                 static int brk_state1 = 0, brk_state2 = 0;
1806                                 if (recv_data == KEY_CR) {
1807                                         brk_state1 = recv_data;
1808                                         brk_state2 = 0;
1809                                 } else if (brk_state1 == KEY_CR && (recv_data == KEY_TILDE || recv_data == KEY_CRTLB)) {
1810                                         if (recv_data == KEY_TILDE)
1811                                                 brk_state2 = recv_data;
1812                                         else if (brk_state2 == KEY_TILDE && recv_data == KEY_CRTLB) {
1813                                                         breakpoint();
1814                                                         brk_state1 = brk_state2 = 0;
1815                                                         goto cont;
1816                                         } else
1817                                                 brk_state2 = 0;
1818                                 } else
1819                                         brk_state1 = 0;
1820                         }
1821 #endif
1822                         if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
1823                                 /*
1824                                  * Don't store BI if IGNBRK or FE/PE if IGNPAR.
1825                                  * Otherwise, push the work to a higher level
1826                                  * (to handle PARMRK) if we're bypassing.
1827                                  * Otherwise, convert BI/FE and PE+INPCK to 0.
1828                                  *
1829                                  * This makes bypassing work right in the
1830                                  * usual "raw" case (IGNBRK set, and IGNPAR
1831                                  * and INPCK clear).
1832                                  *
1833                                  * Note: BI together with FE/PE means just BI.
1834                                  */
1835                                 if (line_status & LSR_BI) {
1836 #if defined(DDB) && defined(BREAK_TO_DEBUGGER)
1837                                         if (com->unit == comconsole) {
1838                                                 breakpoint();
1839                                                 goto cont;
1840                                         }
1841 #endif
1842                                         if (com->tp == NULL
1843                                             || com->tp->t_iflag & IGNBRK)
1844                                                 goto cont;
1845                                 } else {
1846                                         if (com->tp == NULL
1847                                             || com->tp->t_iflag & IGNPAR)
1848                                                 goto cont;
1849                                 }
1850                                 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1851                                     && (line_status & (LSR_BI | LSR_FE)
1852                                         || com->tp->t_iflag & INPCK))
1853                                         recv_data = 0;
1854                         }
1855                         ++com->bytes_in;
1856                         if (com->hotchar != 0 && recv_data == com->hotchar)
1857                                 setsofttty();
1858                         ioptr = com->iptr;
1859                         if (ioptr >= com->ibufend)
1860                                 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1861                         else {
1862                                 if (com->do_timestamp)
1863                                         microtime(&com->timestamp);
1864                                 ++com_events;
1865                                 schedsofttty();
1866 #if 0 /* for testing input latency vs efficiency */
1867 if (com->iptr - com->ibuf == 8)
1868         setsofttty();
1869 #endif
1870                                 ioptr[0] = recv_data;
1871                                 ioptr[com->ierroff] = line_status;
1872                                 com->iptr = ++ioptr;
1873                                 if (ioptr == com->ihighwater
1874                                     && com->state & CS_RTS_IFLOW)
1875                                         outb(com->modem_ctl_port,
1876                                              com->mcr_image &= ~MCR_RTS);
1877                                 if (line_status & LSR_OE)
1878                                         CE_RECORD(com, CE_OVERRUN);
1879                         }
1880 cont:
1881                         /*
1882                          * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1883                          * jump from the top of the loop to here
1884                          */
1885                         line_status = inb(com->line_status_port) & 0x7F;
1886                 }
1887
1888                 /* modem status change? (always check before doing output) */
1889                 modem_status = inb(com->modem_status_port);
1890                 if (modem_status != com->last_modem_status) {
1891                         if (com->do_dcd_timestamp
1892                             && !(com->last_modem_status & MSR_DCD)
1893                             && modem_status & MSR_DCD)
1894                                 microtime(&com->dcd_timestamp);
1895
1896                         /*
1897                          * Schedule high level to handle DCD changes.  Note
1898                          * that we don't use the delta bits anywhere.  Some
1899                          * UARTs mess them up, and it's easy to remember the
1900                          * previous bits and calculate the delta.
1901                          */
1902                         com->last_modem_status = modem_status;
1903                         if (!(com->state & CS_CHECKMSR)) {
1904                                 com_events += LOTS_OF_EVENTS;
1905                                 com->state |= CS_CHECKMSR;
1906                                 setsofttty();
1907                         }
1908
1909                         /* handle CTS change immediately for crisp flow ctl */
1910                         if (com->state & CS_CTS_OFLOW) {
1911                                 if (modem_status & MSR_CTS)
1912                                         com->state |= CS_ODEVREADY;
1913                                 else
1914                                         com->state &= ~CS_ODEVREADY;
1915                         }
1916                 }
1917
1918                 /* output queued and everything ready? */
1919                 if (line_status & LSR_TXRDY
1920                     && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1921                         ioptr = com->obufq.l_head;
1922                         if (com->tx_fifo_size > 1) {
1923                                 u_int   ocount;
1924
1925                                 ocount = com->obufq.l_tail - ioptr;
1926                                 if (ocount > com->tx_fifo_size)
1927                                         ocount = com->tx_fifo_size;
1928                                 com->bytes_out += ocount;
1929                                 do
1930                                         outb(com->data_port, *ioptr++);
1931                                 while (--ocount != 0);
1932                         } else {
1933                                 outb(com->data_port, *ioptr++);
1934                                 ++com->bytes_out;
1935                         }
1936                         com->obufq.l_head = ioptr;
1937                         if (COM_IIR_TXRDYBUG(com->flags)) {
1938                                 int_ctl_new = int_ctl | IER_ETXRDY;
1939                         }
1940                         if (ioptr >= com->obufq.l_tail) {
1941                                 struct lbq      *qp;
1942
1943                                 qp = com->obufq.l_next;
1944                                 qp->l_queued = FALSE;
1945                                 qp = qp->l_next;
1946                                 if (qp != NULL) {
1947                                         com->obufq.l_head = qp->l_head;
1948                                         com->obufq.l_tail = qp->l_tail;
1949                                         com->obufq.l_next = qp;
1950                                 } else {
1951                                         /* output just completed */
1952                                         if (COM_IIR_TXRDYBUG(com->flags)) {
1953                                                 int_ctl_new = int_ctl & ~IER_ETXRDY;
1954                                         }
1955                                         com->state &= ~CS_BUSY;
1956                                 }
1957                                 if (!(com->state & CS_ODONE)) {
1958                                         com_events += LOTS_OF_EVENTS;
1959                                         com->state |= CS_ODONE;
1960                                         setsofttty();   /* handle at high level ASAP */
1961                                 }
1962                         }
1963                         if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) {
1964                                 outb(com->intr_ctl_port, int_ctl_new);
1965                         }
1966                 }
1967
1968                 /* finished? */
1969 #ifndef COM_MULTIPORT
1970                 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
1971 #endif /* COM_MULTIPORT */
1972                         return;
1973         }
1974 }
1975
1976 static int
1977 sioioctl(struct dev_ioctl_args *ap)
1978 {
1979         dev_t dev = ap->a_head.a_dev;
1980         caddr_t data = ap->a_data;
1981         struct com_s    *com;
1982         int             error;
1983         int             mynor;
1984         struct tty      *tp;
1985 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1986         u_long          oldcmd;
1987         struct termios  term;
1988 #endif
1989
1990         mynor = minor(dev);
1991         com = com_addr(MINOR_TO_UNIT(mynor));
1992         if (com == NULL || com->gone)
1993                 return (ENODEV);
1994         if (mynor & CONTROL_MASK) {
1995                 struct termios  *ct;
1996
1997                 switch (mynor & CONTROL_MASK) {
1998                 case CONTROL_INIT_STATE:
1999                         ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
2000                         break;
2001                 case CONTROL_LOCK_STATE:
2002                         ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
2003                         break;
2004                 default:
2005                         return (ENODEV);        /* /dev/nodev */
2006                 }
2007                 switch (ap->a_cmd) {
2008                 case TIOCSETA:
2009                         error = suser_cred(ap->a_cred, 0);
2010                         if (error != 0)
2011                                 return (error);
2012                         *ct = *(struct termios *)data;
2013                         return (0);
2014                 case TIOCGETA:
2015                         *(struct termios *)data = *ct;
2016                         return (0);
2017                 case TIOCGETD:
2018                         *(int *)data = TTYDISC;
2019                         return (0);
2020                 case TIOCGWINSZ:
2021                         bzero(data, sizeof(struct winsize));
2022                         return (0);
2023                 default:
2024                         return (ENOTTY);
2025                 }
2026         }
2027         tp = com->tp;
2028 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2029         term = tp->t_termios;
2030         oldcmd = ap->a_cmd;
2031         error = ttsetcompat(tp, &ap->a_cmd, data, &term);
2032         if (error != 0)
2033                 return (error);
2034         if (ap->a_cmd != oldcmd)
2035                 data = (caddr_t)&term;
2036 #endif
2037         if (ap->a_cmd == TIOCSETA || ap->a_cmd == TIOCSETAW ||
2038             ap->a_cmd == TIOCSETAF) {
2039                 int     cc;
2040                 struct termios *dt = (struct termios *)data;
2041                 struct termios *lt = mynor & CALLOUT_MASK
2042                                      ? &com->lt_out : &com->lt_in;
2043
2044                 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
2045                               | (dt->c_iflag & ~lt->c_iflag);
2046                 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
2047                               | (dt->c_oflag & ~lt->c_oflag);
2048                 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
2049                               | (dt->c_cflag & ~lt->c_cflag);
2050                 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
2051                               | (dt->c_lflag & ~lt->c_lflag);
2052                 for (cc = 0; cc < NCCS; ++cc)
2053                         if (lt->c_cc[cc] != 0)
2054                                 dt->c_cc[cc] = tp->t_cc[cc];
2055                 if (lt->c_ispeed != 0)
2056                         dt->c_ispeed = tp->t_ispeed;
2057                 if (lt->c_ospeed != 0)
2058                         dt->c_ospeed = tp->t_ospeed;
2059         }
2060         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, data, ap->a_fflag, ap->a_cred);
2061         if (error != ENOIOCTL)
2062                 return (error);
2063         crit_enter();
2064         error = ttioctl(tp, ap->a_cmd, data, ap->a_fflag);
2065         disc_optim(tp, &tp->t_termios, com);
2066         if (error != ENOIOCTL) {
2067                 crit_exit();
2068                 return (error);
2069         }
2070         switch (ap->a_cmd) {
2071         case TIOCSBRK:
2072                 sio_setreg(com, com_cfcr, com->cfcr_image |= CFCR_SBREAK);
2073                 break;
2074         case TIOCCBRK:
2075                 sio_setreg(com, com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
2076                 break;
2077         case TIOCSDTR:
2078                 (void)commctl(com, TIOCM_DTR, DMBIS);
2079                 break;
2080         case TIOCCDTR:
2081                 (void)commctl(com, TIOCM_DTR, DMBIC);
2082                 break;
2083         /*
2084          * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set.  The
2085          * changes get undone on the next call to comparam().
2086          */
2087         case TIOCMSET:
2088                 (void)commctl(com, *(int *)data, DMSET);
2089                 break;
2090         case TIOCMBIS:
2091                 (void)commctl(com, *(int *)data, DMBIS);
2092                 break;
2093         case TIOCMBIC:
2094                 (void)commctl(com, *(int *)data, DMBIC);
2095                 break;
2096         case TIOCMGET:
2097                 *(int *)data = commctl(com, 0, DMGET);
2098                 break;
2099         case TIOCMSDTRWAIT:
2100                 /* must be root since the wait applies to following logins */
2101                 error = suser_cred(ap->a_cred, 0);
2102                 if (error != 0) {
2103                         crit_exit();
2104                         return (error);
2105                 }
2106                 com->dtr_wait = *(int *)data * hz / 100;
2107                 break;
2108         case TIOCMGDTRWAIT:
2109                 *(int *)data = com->dtr_wait * 100 / hz;
2110                 break;
2111         case TIOCTIMESTAMP:
2112                 com->do_timestamp = TRUE;
2113                 *(struct timeval *)data = com->timestamp;
2114                 break;
2115         case TIOCDCDTIMESTAMP:
2116                 com->do_dcd_timestamp = TRUE;
2117                 *(struct timeval *)data = com->dcd_timestamp;
2118                 break;
2119         default:
2120                 crit_exit();
2121                 error = pps_ioctl(ap->a_cmd, data, &com->pps);
2122                 if (error == ENODEV)
2123                         error = ENOTTY;
2124                 return (error);
2125         }
2126         crit_exit();
2127         return (0);
2128 }
2129
2130 static void
2131 siopoll(void *dummy, void *frame)
2132 {
2133         int             unit;
2134
2135         if (com_events == 0)
2136                 return;
2137 repeat:
2138         for (unit = 0; unit < sio_numunits; ++unit) {
2139                 struct com_s    *com;
2140                 int             incc;
2141                 struct tty      *tp;
2142
2143                 com = com_addr(unit);
2144                 if (com == NULL)
2145                         continue;
2146                 tp = com->tp;
2147                 if (tp == NULL || com->gone) {
2148                         /*
2149                          * Discard any events related to never-opened or
2150                          * going-away devices.
2151                          */
2152                         com_lock();
2153                         incc = com->iptr - com->ibuf;
2154                         com->iptr = com->ibuf;
2155                         if (com->state & CS_CHECKMSR) {
2156                                 incc += LOTS_OF_EVENTS;
2157                                 com->state &= ~CS_CHECKMSR;
2158                         }
2159                         com_events -= incc;
2160                         com_unlock();
2161                         continue;
2162                 }
2163                 if (com->iptr != com->ibuf) {
2164                         com_lock();
2165                         sioinput(com);
2166                         com_unlock();
2167                 }
2168                 if (com->state & CS_CHECKMSR) {
2169                         u_char  delta_modem_status;
2170
2171                         com_lock();
2172                         delta_modem_status = com->last_modem_status
2173                                              ^ com->prev_modem_status;
2174                         com->prev_modem_status = com->last_modem_status;
2175                         com_events -= LOTS_OF_EVENTS;
2176                         com->state &= ~CS_CHECKMSR;
2177                         com_unlock();
2178                         if (delta_modem_status & MSR_DCD)
2179                                 (*linesw[tp->t_line].l_modem)
2180                                         (tp, com->prev_modem_status & MSR_DCD);
2181                 }
2182                 if (com->state & CS_ODONE) {
2183                         com_lock();
2184                         com_events -= LOTS_OF_EVENTS;
2185                         com->state &= ~CS_ODONE;
2186                         com_unlock();
2187                         if (!(com->state & CS_BUSY)
2188                             && !(com->extra_state & CSE_BUSYCHECK)) {
2189                                 callout_reset(&com->busy_ch, hz / 100,
2190                                                 siobusycheck, com);
2191                                 com->extra_state |= CSE_BUSYCHECK;
2192                         }
2193                         (*linesw[tp->t_line].l_start)(tp);
2194                 }
2195                 if (com_events == 0)
2196                         break;
2197         }
2198         if (com_events >= LOTS_OF_EVENTS)
2199                 goto repeat;
2200 }
2201
2202 static int
2203 comparam(tp, t)
2204         struct tty      *tp;
2205         struct termios  *t;
2206 {
2207         u_int           cfcr;
2208         int             cflag;
2209         struct com_s    *com;
2210         u_int           divisor;
2211         u_char          dlbh;
2212         u_char          dlbl;
2213         int             unit;
2214
2215         unit = DEV_TO_UNIT(tp->t_dev);
2216         com = com_addr(unit);
2217         if (com == NULL)
2218                 return (ENODEV);
2219
2220         /* do historical conversions */
2221         if (t->c_ispeed == 0)
2222                 t->c_ispeed = t->c_ospeed;
2223
2224         /* check requested parameters */
2225         if (t->c_ospeed == 0)
2226                 divisor = 0;
2227         else {
2228                 if (t->c_ispeed != t->c_ospeed)
2229                         return (EINVAL);
2230                 divisor = siodivisor(com->rclk, t->c_ispeed);
2231                 if (divisor == 0)
2232                         return (EINVAL);
2233         }
2234
2235         /* parameters are OK, convert them to the com struct and the device */
2236         crit_enter();
2237         if (divisor == 0)
2238                 (void)commctl(com, TIOCM_DTR, DMBIC);   /* hang up line */
2239         else
2240                 (void)commctl(com, TIOCM_DTR, DMBIS);
2241         cflag = t->c_cflag;
2242         switch (cflag & CSIZE) {
2243         case CS5:
2244                 cfcr = CFCR_5BITS;
2245                 break;
2246         case CS6:
2247                 cfcr = CFCR_6BITS;
2248                 break;
2249         case CS7:
2250                 cfcr = CFCR_7BITS;
2251                 break;
2252         default:
2253                 cfcr = CFCR_8BITS;
2254                 break;
2255         }
2256         if (cflag & PARENB) {
2257                 cfcr |= CFCR_PENAB;
2258                 if (!(cflag & PARODD))
2259                         cfcr |= CFCR_PEVEN;
2260         }
2261         if (cflag & CSTOPB)
2262                 cfcr |= CFCR_STOPB;
2263
2264         if (com->hasfifo && divisor != 0) {
2265                 /*
2266                  * Use a fifo trigger level low enough so that the input
2267                  * latency from the fifo is less than about 16 msec and
2268                  * the total latency is less than about 30 msec.  These
2269                  * latencies are reasonable for humans.  Serial comms
2270                  * protocols shouldn't expect anything better since modem
2271                  * latencies are larger.
2272                  *
2273                  * Interrupts can be held up for long periods of time
2274                  * due to inefficiencies in other parts of the kernel,
2275                  * certain video cards, etc.  Setting the FIFO trigger
2276                  * point to MEDH instead of HIGH gives us 694uS of slop
2277                  * (8 character times) instead of 173uS (2 character times)
2278                  * @ 115200 bps.
2279                  */
2280                 com->fifo_image = t->c_ospeed <= 4800
2281                                   ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_MEDH;
2282 #ifdef COM_ESP
2283                 /*
2284                  * The Hayes ESP card needs the fifo DMA mode bit set
2285                  * in compatibility mode.  If not, it will interrupt
2286                  * for each character received.
2287                  */
2288                 if (com->esp)
2289                         com->fifo_image |= FIFO_DMA_MODE;
2290 #endif
2291                 sio_setreg(com, com_fifo, com->fifo_image);
2292         }
2293
2294         /*
2295          * This returns with interrupts disabled so that we can complete
2296          * the speed change atomically.  Keeping interrupts disabled is
2297          * especially important while com_data is hidden.
2298          */
2299         (void) siosetwater(com, t->c_ispeed);
2300
2301         if (divisor != 0) {
2302                 sio_setreg(com, com_cfcr, cfcr | CFCR_DLAB);
2303                 /*
2304                  * Only set the divisor registers if they would change,
2305                  * since on some 16550 incompatibles (UMC8669F), setting
2306                  * them while input is arriving them loses sync until
2307                  * data stops arriving.
2308                  */
2309                 dlbl = divisor & 0xFF;
2310                 if (sio_getreg(com, com_dlbl) != dlbl)
2311                         sio_setreg(com, com_dlbl, dlbl);
2312                 dlbh = divisor >> 8;
2313                 if (sio_getreg(com, com_dlbh) != dlbh)
2314                         sio_setreg(com, com_dlbh, dlbh);
2315         }
2316
2317         sio_setreg(com, com_cfcr, com->cfcr_image = cfcr);
2318
2319         if (!(tp->t_state & TS_TTSTOP))
2320                 com->state |= CS_TTGO;
2321
2322         if (cflag & CRTS_IFLOW) {
2323                 if (com->st16650a) {
2324                         sio_setreg(com, com_cfcr, 0xbf);
2325                         sio_setreg(com, com_fifo,
2326                                    sio_getreg(com, com_fifo) | 0x40);
2327                 }
2328                 com->state |= CS_RTS_IFLOW;
2329                 /*
2330                  * If CS_RTS_IFLOW just changed from off to on, the change
2331                  * needs to be propagated to MCR_RTS.  This isn't urgent,
2332                  * so do it later by calling comstart() instead of repeating
2333                  * a lot of code from comstart() here.
2334                  */
2335         } else if (com->state & CS_RTS_IFLOW) {
2336                 com->state &= ~CS_RTS_IFLOW;
2337                 /*
2338                  * CS_RTS_IFLOW just changed from on to off.  Force MCR_RTS
2339                  * on here, since comstart() won't do it later.
2340                  */
2341                 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2342                 if (com->st16650a) {
2343                         sio_setreg(com, com_cfcr, 0xbf);
2344                         sio_setreg(com, com_fifo,
2345                                    sio_getreg(com, com_fifo) & ~0x40);
2346                 }
2347         }
2348
2349
2350         /*
2351          * Set up state to handle output flow control.
2352          * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2353          * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2354          */
2355         com->state |= CS_ODEVREADY;
2356         com->state &= ~CS_CTS_OFLOW;
2357         if (cflag & CCTS_OFLOW) {
2358                 com->state |= CS_CTS_OFLOW;
2359                 if (!(com->last_modem_status & MSR_CTS))
2360                         com->state &= ~CS_ODEVREADY;
2361                 if (com->st16650a) {
2362                         sio_setreg(com, com_cfcr, 0xbf);
2363                         sio_setreg(com, com_fifo,
2364                                    sio_getreg(com, com_fifo) | 0x80);
2365                 }
2366         } else {
2367                 if (com->st16650a) {
2368                         sio_setreg(com, com_cfcr, 0xbf);
2369                         sio_setreg(com, com_fifo,
2370                                    sio_getreg(com, com_fifo) & ~0x80);
2371                 }
2372         }
2373
2374         sio_setreg(com, com_cfcr, com->cfcr_image);
2375
2376         /* XXX shouldn't call functions while intrs are disabled. */
2377         disc_optim(tp, t, com);
2378         /*
2379          * Recover from fiddling with CS_TTGO.  We used to call siointr1()
2380          * unconditionally, but that defeated the careful discarding of
2381          * stale input in sioopen().
2382          */
2383         if (com->state >= (CS_BUSY | CS_TTGO))
2384                 siointr1(com);
2385
2386         com_unlock();
2387         crit_exit();
2388         comstart(tp);
2389         if (com->ibufold != NULL) {
2390                 free(com->ibufold, M_DEVBUF);
2391                 com->ibufold = NULL;
2392         }
2393         return (0);
2394 }
2395
2396 static int
2397 siosetwater(com, speed)
2398         struct com_s    *com;
2399         speed_t         speed;
2400 {
2401         int             cp4ticks;
2402         u_char          *ibuf;
2403         int             ibufsize;
2404         struct tty      *tp;
2405
2406         /*
2407          * Make the buffer size large enough to handle a softtty interrupt
2408          * latency of about 2 ticks without loss of throughput or data
2409          * (about 3 ticks if input flow control is not used or not honoured,
2410          * but a bit less for CS5-CS7 modes).
2411          */
2412         cp4ticks = speed / 10 / hz * 4;
2413         for (ibufsize = 128; ibufsize < cp4ticks;)
2414                 ibufsize <<= 1;
2415         if (ibufsize == com->ibufsize) {
2416                 com_lock();
2417                 return (0);
2418         }
2419
2420         /*
2421          * Allocate input buffer.  The extra factor of 2 in the size is
2422          * to allow for an error byte for each input byte.
2423          */
2424         ibuf = malloc(2 * ibufsize, M_DEVBUF, M_WAITOK | M_ZERO);
2425
2426         /* Initialize non-critical variables. */
2427         com->ibufold = com->ibuf;
2428         com->ibufsize = ibufsize;
2429         tp = com->tp;
2430         if (tp != NULL) {
2431                 tp->t_ififosize = 2 * ibufsize;
2432                 tp->t_ispeedwat = (speed_t)-1;
2433                 tp->t_ospeedwat = (speed_t)-1;
2434         }
2435
2436         /*
2437          * Read current input buffer, if any.  Continue with interrupts
2438          * disabled.
2439          */
2440         com_lock();
2441         if (com->iptr != com->ibuf)
2442                 sioinput(com);
2443
2444         /*-
2445          * Initialize critical variables, including input buffer watermarks.
2446          * The external device is asked to stop sending when the buffer
2447          * exactly reaches high water, or when the high level requests it.
2448          * The high level is notified immediately (rather than at a later
2449          * clock tick) when this watermark is reached.
2450          * The buffer size is chosen so the watermark should almost never
2451          * be reached.
2452          * The low watermark is invisibly 0 since the buffer is always
2453          * emptied all at once.
2454          */
2455         com->iptr = com->ibuf = ibuf;
2456         com->ibufend = ibuf + ibufsize;
2457         com->ierroff = ibufsize;
2458         com->ihighwater = ibuf + 3 * ibufsize / 4;
2459         return (0);
2460 }
2461
2462 static void
2463 comstart(tp)
2464         struct tty      *tp;
2465 {
2466         struct com_s    *com;
2467         int             unit;
2468
2469         unit = DEV_TO_UNIT(tp->t_dev);
2470         com = com_addr(unit);
2471         if (com == NULL)
2472                 return;
2473         crit_enter();
2474         com_lock();
2475         if (tp->t_state & TS_TTSTOP)
2476                 com->state &= ~CS_TTGO;
2477         else
2478                 com->state |= CS_TTGO;
2479         if (tp->t_state & TS_TBLOCK) {
2480                 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2481                         outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2482         } else {
2483                 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2484                     && com->state & CS_RTS_IFLOW)
2485                         outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2486         }
2487         com_unlock();
2488         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2489                 ttwwakeup(tp);
2490                 crit_exit();
2491                 return;
2492         }
2493         if (tp->t_outq.c_cc != 0) {
2494                 struct lbq      *qp;
2495                 struct lbq      *next;
2496
2497                 if (!com->obufs[0].l_queued) {
2498                         com->obufs[0].l_tail
2499                             = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2500                                                   sizeof com->obuf1);
2501                         com->obufs[0].l_next = NULL;
2502                         com->obufs[0].l_queued = TRUE;
2503                         com_lock();
2504                         if (com->state & CS_BUSY) {
2505                                 qp = com->obufq.l_next;
2506                                 while ((next = qp->l_next) != NULL)
2507                                         qp = next;
2508                                 qp->l_next = &com->obufs[0];
2509                         } else {
2510                                 com->obufq.l_head = com->obufs[0].l_head;
2511                                 com->obufq.l_tail = com->obufs[0].l_tail;
2512                                 com->obufq.l_next = &com->obufs[0];
2513                                 com->state |= CS_BUSY;
2514                         }
2515                         com_unlock();
2516                 }
2517                 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2518                         com->obufs[1].l_tail
2519                             = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2520                                                   sizeof com->obuf2);
2521                         com->obufs[1].l_next = NULL;
2522                         com->obufs[1].l_queued = TRUE;
2523                         com_lock();
2524                         if (com->state & CS_BUSY) {
2525                                 qp = com->obufq.l_next;
2526                                 while ((next = qp->l_next) != NULL)
2527                                         qp = next;
2528                                 qp->l_next = &com->obufs[1];
2529                         } else {
2530                                 com->obufq.l_head = com->obufs[1].l_head;
2531                                 com->obufq.l_tail = com->obufs[1].l_tail;
2532                                 com->obufq.l_next = &com->obufs[1];
2533                                 com->state |= CS_BUSY;
2534                         }
2535                         com_unlock();
2536                 }
2537                 tp->t_state |= TS_BUSY;
2538         }
2539         com_lock();
2540         if (com->state >= (CS_BUSY | CS_TTGO))
2541                 siointr1(com);  /* fake interrupt to start output */
2542         com_unlock();
2543         ttwwakeup(tp);
2544         crit_exit();
2545 }
2546
2547 static void
2548 comstop(tp, rw)
2549         struct tty      *tp;
2550         int             rw;
2551 {
2552         struct com_s    *com;
2553
2554         com = com_addr(DEV_TO_UNIT(tp->t_dev));
2555         if (com == NULL || com->gone)
2556                 return;
2557         com_lock();
2558         if (rw & FWRITE) {
2559                 if (com->hasfifo)
2560 #ifdef COM_ESP
2561                     /* XXX avoid h/w bug. */
2562                     if (!com->esp)
2563 #endif
2564                         sio_setreg(com, com_fifo,
2565                                    FIFO_XMT_RST | com->fifo_image);
2566                 com->obufs[0].l_queued = FALSE;
2567                 com->obufs[1].l_queued = FALSE;
2568                 if (com->state & CS_ODONE)
2569                         com_events -= LOTS_OF_EVENTS;
2570                 com->state &= ~(CS_ODONE | CS_BUSY);
2571                 com->tp->t_state &= ~TS_BUSY;
2572         }
2573         if (rw & FREAD) {
2574                 if (com->hasfifo)
2575 #ifdef COM_ESP
2576                     /* XXX avoid h/w bug. */
2577                     if (!com->esp)
2578 #endif
2579                         sio_setreg(com, com_fifo,
2580                                    FIFO_RCV_RST | com->fifo_image);
2581                 com_events -= (com->iptr - com->ibuf);
2582                 com->iptr = com->ibuf;
2583         }
2584         com_unlock();
2585         comstart(tp);
2586 }
2587
2588 static int
2589 commctl(com, bits, how)
2590         struct com_s    *com;
2591         int             bits;
2592         int             how;
2593 {
2594         int     mcr;
2595         int     msr;
2596
2597         if (how == DMGET) {
2598                 bits = TIOCM_LE;        /* XXX - always enabled while open */
2599                 mcr = com->mcr_image;
2600                 if (mcr & MCR_DTR)
2601                         bits |= TIOCM_DTR;
2602                 if (mcr & MCR_RTS)
2603                         bits |= TIOCM_RTS;
2604                 msr = com->prev_modem_status;
2605                 if (msr & MSR_CTS)
2606                         bits |= TIOCM_CTS;
2607                 if (msr & MSR_DCD)
2608                         bits |= TIOCM_CD;
2609                 if (msr & MSR_DSR)
2610                         bits |= TIOCM_DSR;
2611                 /*
2612                  * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
2613                  * more volatile by reading the modem status a lot.  Perhaps
2614                  * we should latch both bits until the status is read here.
2615                  */
2616                 if (msr & (MSR_RI | MSR_TERI))
2617                         bits |= TIOCM_RI;
2618                 return (bits);
2619         }
2620         mcr = 0;
2621         if (bits & TIOCM_DTR)
2622                 mcr |= MCR_DTR;
2623         if (bits & TIOCM_RTS)
2624                 mcr |= MCR_RTS;
2625         if (com->gone)
2626                 return(0);
2627         com_lock();
2628         switch (how) {
2629         case DMSET:
2630                 outb(com->modem_ctl_port,
2631                      com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
2632                 break;
2633         case DMBIS:
2634                 outb(com->modem_ctl_port, com->mcr_image |= mcr);
2635                 break;
2636         case DMBIC:
2637                 outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
2638                 break;
2639         }
2640         com_unlock();
2641         return (0);
2642 }
2643
2644 static void
2645 siosettimeout()
2646 {
2647         struct com_s    *com;
2648         bool_t          someopen;
2649         int             unit;
2650
2651         /*
2652          * Set our timeout period to 1 second if no polled devices are open.
2653          * Otherwise set it to max(1/200, 1/hz).
2654          * Enable timeouts iff some device is open.
2655          */
2656         callout_stop(&sio_timeout_handle);
2657         sio_timeout = hz;
2658         someopen = FALSE;
2659         for (unit = 0; unit < sio_numunits; ++unit) {
2660                 com = com_addr(unit);
2661                 if (com != NULL && com->tp != NULL
2662                     && com->tp->t_state & TS_ISOPEN && !com->gone) {
2663                         someopen = TRUE;
2664                         if (com->poll || com->poll_output) {
2665                                 sio_timeout = hz > 200 ? hz / 200 : 1;
2666                                 break;
2667                         }
2668                 }
2669         }
2670         if (someopen) {
2671                 sio_timeouts_until_log = hz / sio_timeout;
2672                 callout_reset(&sio_timeout_handle, sio_timeout,
2673                                 comwakeup, NULL);
2674         } else {
2675                 /* Flush error messages, if any. */
2676                 sio_timeouts_until_log = 1;
2677                 comwakeup((void *)NULL);
2678                 callout_stop(&sio_timeout_handle);
2679         }
2680 }
2681
2682 static void
2683 comwakeup(chan)
2684         void    *chan;
2685 {
2686         struct com_s    *com;
2687         int             unit;
2688
2689         callout_reset(&sio_timeout_handle, sio_timeout, comwakeup, NULL);
2690
2691         /*
2692          * Recover from lost output interrupts.
2693          * Poll any lines that don't use interrupts.
2694          */
2695         for (unit = 0; unit < sio_numunits; ++unit) {
2696                 com = com_addr(unit);
2697                 if (com != NULL && !com->gone
2698                     && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2699                         com_lock();
2700                         siointr1(com);
2701                         com_unlock();
2702                 }
2703         }
2704
2705         /*
2706          * Check for and log errors, but not too often.
2707          */
2708         if (--sio_timeouts_until_log > 0)
2709                 return;
2710         sio_timeouts_until_log = hz / sio_timeout;
2711         for (unit = 0; unit < sio_numunits; ++unit) {
2712                 int     errnum;
2713
2714                 com = com_addr(unit);
2715                 if (com == NULL)
2716                         continue;
2717                 if (com->gone)
2718                         continue;
2719                 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2720                         u_int   delta;
2721                         u_long  total;
2722
2723                         com_lock();
2724                         delta = com->delta_error_counts[errnum];
2725                         com->delta_error_counts[errnum] = 0;
2726                         com_unlock();
2727                         if (delta == 0)
2728                                 continue;
2729                         total = com->error_counts[errnum] += delta;
2730                         log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
2731                             unit, delta, error_desc[errnum],
2732                             delta == 1 ? "" : "s", total);
2733                 }
2734         }
2735 }
2736
2737 static void
2738 disc_optim(tp, t, com)
2739         struct tty      *tp;
2740         struct termios  *t;
2741         struct com_s    *com;
2742 {
2743         if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2744             && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2745             && (!(t->c_iflag & PARMRK)
2746                 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2747             && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2748             && linesw[tp->t_line].l_rint == ttyinput)
2749                 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2750         else
2751                 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2752         com->hotchar = linesw[tp->t_line].l_hotchar;
2753 }
2754
2755 /*
2756  * Following are all routines needed for SIO to act as console
2757  */
2758 #include <sys/cons.h>
2759
2760 struct siocnstate {
2761         u_char  dlbl;
2762         u_char  dlbh;
2763         u_char  ier;
2764         u_char  cfcr;
2765         u_char  mcr;
2766 };
2767
2768 static speed_t siocngetspeed (Port_t, u_long rclk);
2769 static void siocnclose  (struct siocnstate *sp, Port_t iobase);
2770 static void siocnopen   (struct siocnstate *sp, Port_t iobase, int speed);
2771 static void siocntxwait (Port_t iobase);
2772
2773 static cn_probe_t siocnprobe;
2774 static cn_init_t siocninit;
2775 static cn_checkc_t siocncheckc;
2776 static cn_getc_t siocngetc;
2777 static cn_putc_t siocnputc;
2778
2779 #ifdef __i386__
2780 CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc,
2781             siocnputc, NULL);
2782 #endif
2783
2784 /* To get the GDB related variables */
2785 #if DDB > 0
2786 #include <ddb/ddb.h>
2787 #endif
2788
2789 static void
2790 siocntxwait(iobase)
2791         Port_t  iobase;
2792 {
2793         int     timo;
2794
2795         /*
2796          * Wait for any pending transmission to finish.  Required to avoid
2797          * the UART lockup bug when the speed is changed, and for normal
2798          * transmits.
2799          */
2800         timo = 100000;
2801         while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
2802                != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
2803                 ;
2804 }
2805
2806 /*
2807  * Read the serial port specified and try to figure out what speed
2808  * it's currently running at.  We're assuming the serial port has
2809  * been initialized and is basicly idle.  This routine is only intended
2810  * to be run at system startup.
2811  *
2812  * If the value read from the serial port doesn't make sense, return 0.
2813  */
2814
2815 static speed_t
2816 siocngetspeed(iobase, rclk)
2817         Port_t  iobase;
2818         u_long  rclk;
2819 {
2820         u_int   divisor;
2821         u_char  dlbh;
2822         u_char  dlbl;
2823         u_char  cfcr;
2824
2825         cfcr = inb(iobase + com_cfcr);
2826         outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
2827
2828         dlbl = inb(iobase + com_dlbl);
2829         dlbh = inb(iobase + com_dlbh);
2830
2831         outb(iobase + com_cfcr, cfcr);
2832
2833         divisor = dlbh << 8 | dlbl;
2834
2835         /* XXX there should be more sanity checking. */
2836         if (divisor == 0)
2837                 return (CONSPEED);
2838         return (rclk / (16UL * divisor));
2839 }
2840
2841 static void
2842 siocnopen(sp, iobase, speed)
2843         struct siocnstate       *sp;
2844         Port_t                  iobase;
2845         int                     speed;
2846 {
2847         u_int   divisor;
2848         u_char  dlbh;
2849         u_char  dlbl;
2850
2851         /*
2852          * Save all the device control registers except the fifo register
2853          * and set our default ones (cs8 -parenb speed=comdefaultrate).
2854          * We can't save the fifo register since it is read-only.
2855          */
2856         sp->ier = inb(iobase + com_ier);
2857         outb(iobase + com_ier, 0);      /* spltty() doesn't stop siointr() */
2858         siocntxwait(iobase);
2859         sp->cfcr = inb(iobase + com_cfcr);
2860         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2861         sp->dlbl = inb(iobase + com_dlbl);
2862         sp->dlbh = inb(iobase + com_dlbh);
2863         /*
2864          * Only set the divisor registers if they would change, since on
2865          * some 16550 incompatibles (Startech), setting them clears the
2866          * data input register.  This also reduces the effects of the
2867          * UMC8669F bug.
2868          */
2869         divisor = siodivisor(comdefaultrclk, speed);
2870         dlbl = divisor & 0xFF;
2871         if (sp->dlbl != dlbl)
2872                 outb(iobase + com_dlbl, dlbl);
2873         dlbh = divisor >> 8;
2874         if (sp->dlbh != dlbh)
2875                 outb(iobase + com_dlbh, dlbh);
2876         outb(iobase + com_cfcr, CFCR_8BITS);
2877         sp->mcr = inb(iobase + com_mcr);
2878         /*
2879          * We don't want interrupts, but must be careful not to "disable"
2880          * them by clearing the MCR_IENABLE bit, since that might cause
2881          * an interrupt by floating the IRQ line.
2882          */
2883         outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
2884 }
2885
2886 static void
2887 siocnclose(sp, iobase)
2888         struct siocnstate       *sp;
2889         Port_t                  iobase;
2890 {
2891         /*
2892          * Restore the device control registers.
2893          */
2894         siocntxwait(iobase);
2895         outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2896         if (sp->dlbl != inb(iobase + com_dlbl))
2897                 outb(iobase + com_dlbl, sp->dlbl);
2898         if (sp->dlbh != inb(iobase + com_dlbh))
2899                 outb(iobase + com_dlbh, sp->dlbh);
2900         outb(iobase + com_cfcr, sp->cfcr);
2901         /*
2902          * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
2903          */
2904         outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
2905         outb(iobase + com_ier, sp->ier);
2906 }
2907
2908 static void
2909 siocnprobe(cp)
2910         struct consdev  *cp;
2911 {
2912         speed_t                 boot_speed;
2913         u_char                  cfcr;
2914         u_int                   divisor;
2915         int                     unit;
2916         struct siocnstate       sp;
2917
2918         /*
2919          * Find our first enabled console, if any.  If it is a high-level
2920          * console device, then initialize it and return successfully.
2921          * If it is a low-level console device, then initialize it and
2922          * return unsuccessfully.  It must be initialized in both cases
2923          * for early use by console drivers and debuggers.  Initializing
2924          * the hardware is not necessary in all cases, since the i/o
2925          * routines initialize it on the fly, but it is necessary if
2926          * input might arrive while the hardware is switched back to an
2927          * uninitialized state.  We can't handle multiple console devices
2928          * yet because our low-level routines don't take a device arg.
2929          * We trust the user to set the console flags properly so that we
2930          * don't need to probe.
2931          */
2932         cp->cn_pri = CN_DEAD;
2933
2934         for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */
2935                 int flags;
2936                 int disabled;
2937                 if (resource_int_value("sio", unit, "disabled", &disabled) == 0) {
2938                         if (disabled)
2939                                 continue;
2940                 }
2941                 if (resource_int_value("sio", unit, "flags", &flags))
2942                         continue;
2943                 if (COM_CONSOLE(flags) || COM_DEBUGGER(flags)) {
2944                         int port;
2945                         Port_t iobase;
2946
2947                         if (resource_int_value("sio", unit, "port", &port))
2948                                 continue;
2949                         iobase = port;
2950                         crit_enter();
2951                         if (boothowto & RB_SERIAL) {
2952                                 boot_speed =
2953                                     siocngetspeed(iobase, comdefaultrclk);
2954                                 if (boot_speed)
2955                                         comdefaultrate = boot_speed;
2956                         }
2957
2958                         /*
2959                          * Initialize the divisor latch.  We can't rely on
2960                          * siocnopen() to do this the first time, since it 
2961                          * avoids writing to the latch if the latch appears
2962                          * to have the correct value.  Also, if we didn't
2963                          * just read the speed from the hardware, then we
2964                          * need to set the speed in hardware so that
2965                          * switching it later is null.
2966                          */
2967                         cfcr = inb(iobase + com_cfcr);
2968                         outb(iobase + com_cfcr, CFCR_DLAB | cfcr);
2969                         divisor = siodivisor(comdefaultrclk, comdefaultrate);
2970                         outb(iobase + com_dlbl, divisor & 0xff);
2971                         outb(iobase + com_dlbh, divisor >> 8);
2972                         outb(iobase + com_cfcr, cfcr);
2973
2974                         siocnopen(&sp, iobase, comdefaultrate);
2975
2976                         crit_exit();
2977                         if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) {
2978                                 cp->cn_dev = make_dev(&sio_ops, unit,
2979                                                 UID_ROOT, GID_WHEEL, 0600,
2980                                                 "ttyd%r", unit);
2981                                 cp->cn_pri = COM_FORCECONSOLE(flags)
2982                                              || boothowto & RB_SERIAL
2983                                              ? CN_REMOTE : CN_NORMAL;
2984                                 siocniobase = iobase;
2985                                 siocnunit = unit;
2986                         }
2987                         if (COM_DEBUGGER(flags)) {
2988                                 printf("sio%d: gdb debugging port\n", unit);
2989                                 siogdbiobase = iobase;
2990                                 siogdbunit = unit;
2991 #if DDB > 0
2992                                 gdbdev = make_dev(&sio_ops, unit,
2993                                                 UID_ROOT, GID_WHEEL, 0600,
2994                                                 "ttyd%r", unit);
2995                                 gdb_getc = siocngetc;
2996                                 gdb_putc = siocnputc;
2997 #endif
2998                         }
2999                 }
3000         }
3001 #ifdef  __i386__
3002 #if DDB > 0
3003         /*
3004          * XXX Ugly Compatability.
3005          * If no gdb port has been specified, set it to be the console
3006          * as some configuration files don't specify the gdb port.
3007          */
3008         if (gdbdev == NODEV && (boothowto & RB_GDB)) {
3009                 printf("Warning: no GDB port specified. Defaulting to sio%d.\n",
3010                         siocnunit);
3011                 printf("Set flag 0x80 on desired GDB port in your\n");
3012                 printf("configuration file (currently sio only).\n");
3013                 siogdbiobase = siocniobase;
3014                 siogdbunit = siocnunit;
3015                 gdbdev = make_dev(&sio_ops, siocnunit,
3016                                 UID_ROOT, GID_WHEEL, 0600,
3017                                 "ttyd%r", siocnunit);
3018                 gdb_getc = siocngetc;
3019                 gdb_putc = siocnputc;
3020         }
3021 #endif
3022 #endif
3023 }
3024
3025 static void
3026 siocninit(cp)
3027         struct consdev  *cp;
3028 {
3029         comconsole = DEV_TO_UNIT(cp->cn_dev);
3030 }
3031
3032 static int
3033 siocncheckc(dev)
3034         dev_t   dev;
3035 {
3036         int     c;
3037         Port_t  iobase;
3038         struct siocnstate       sp;
3039
3040         if (minor(dev) == siogdbunit)
3041                 iobase = siogdbiobase;
3042         else
3043                 iobase = siocniobase;
3044         crit_enter();
3045         siocnopen(&sp, iobase, comdefaultrate);
3046         if (inb(iobase + com_lsr) & LSR_RXRDY)
3047                 c = inb(iobase + com_data);
3048         else
3049                 c = -1;
3050         siocnclose(&sp, iobase);
3051         crit_exit();
3052         return (c);
3053 }
3054
3055
3056 int
3057 siocngetc(dev)
3058         dev_t   dev;
3059 {
3060         int     c;
3061         Port_t  iobase;
3062         struct siocnstate       sp;
3063
3064         if (minor(dev) == siogdbunit)
3065                 iobase = siogdbiobase;
3066         else
3067                 iobase = siocniobase;
3068         crit_enter();
3069         siocnopen(&sp, iobase, comdefaultrate);
3070         while (!(inb(iobase + com_lsr) & LSR_RXRDY))
3071                 ;
3072         c = inb(iobase + com_data);
3073         siocnclose(&sp, iobase);
3074         crit_exit();
3075         return (c);
3076 }
3077
3078 void
3079 siocnputc(dev, c)
3080         dev_t   dev;
3081         int     c;
3082 {
3083         struct siocnstate       sp;
3084         Port_t  iobase;
3085
3086         if (minor(dev) == siogdbunit)
3087                 iobase = siogdbiobase;
3088         else
3089                 iobase = siocniobase;
3090         crit_enter();
3091         siocnopen(&sp, iobase, comdefaultrate);
3092         siocntxwait(iobase);
3093         outb(iobase + com_data, c);
3094         siocnclose(&sp, iobase);
3095         crit_exit();
3096 }
3097
3098 DRIVER_MODULE(sio, isa, sio_isa_driver, sio_devclass, 0, 0);
3099 #if NPCI > 0
3100 DRIVER_MODULE(sio, pci, sio_pci_driver, sio_devclass, 0, 0);
3101 #endif
3102 #if NPUC > 0
3103 DRIVER_MODULE(sio, puc, sio_puc_driver, sio_devclass, 0, 0);
3104 #endif