sio.c revision 56793
1228753Smm/*- 2231200Smm * Copyright (c) 1991 The Regents of the University of California. 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 3. All advertising materials mentioning features or use of this software 14228753Smm * must display the following acknowledgement: 15228753Smm * This product includes software developed by the University of 16228753Smm * California, Berkeley and its contributors. 17228753Smm * 4. Neither the name of the University nor the names of its contributors 18228753Smm * may be used to endorse or promote products derived from this software 19228753Smm * without specific prior written permission. 20228753Smm * 21228753Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22228753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23228753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24228753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25228753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26228753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27228753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28228753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30228753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31228753Smm * SUCH DAMAGE. 32228753Smm * 33228753Smm * $FreeBSD: head/sys/pc98/cbus/sio.c 56793 2000-01-29 04:47:22Z kato $ 34228753Smm * from: @(#)com.c 7.5 (Berkeley) 5/16/91 35228753Smm * from: i386/isa sio.c,v 1.234 36228753Smm */ 37228753Smm 38228753Smm#include "opt_comconsole.h" 39228753Smm#include "opt_compat.h" 40228753Smm#include "opt_ddb.h" 41228753Smm#include "opt_sio.h" 42228753Smm#include "card.h" 43228753Smm#include "sio.h" 44228753Smm 45228753Smm/* 46228753Smm * Serial driver, based on 386BSD-0.1 com driver. 47228753Smm * Mostly rewritten to use pseudo-DMA. 48228753Smm * Works for National Semiconductor NS8250-NS16550AF UARTs. 49228753Smm * COM driver, based on HP dca driver. 50228753Smm * 51228753Smm * Changes for PC-Card integration: 52228753Smm * - Added PC-Card driver table and handlers 53228753Smm */ 54228753Smm/*=============================================================== 55228753Smm * 386BSD(98),FreeBSD-1.1x(98) com driver. 56228753Smm * ----- 57228753Smm * modified for PC9801 by M.Ishii 58228753Smm * Kyoto University Microcomputer Club (KMC) 59228753Smm * Chou "TEFUTEFU" Hirotomi 60228753Smm * Kyoto Univ. the faculty of medicine 61228753Smm *=============================================================== 62228753Smm * FreeBSD-2.0.1(98) sio driver. 63231200Smm * ----- 64231200Smm * modified for pc98 Internal i8251 and MICRO CORE MC16550II 65231200Smm * T.Koike(hfc01340@niftyserve.or.jp) 66231200Smm * implement kernel device configuration 67231200Smm * aizu@orient.center.nitech.ac.jp 68231200Smm * 69231200Smm * Notes. 70228753Smm * ----- 71228753Smm * PC98 localization based on 386BSD(98) com driver. Using its PC98 local 72231200Smm * functions. 73231200Smm * This driver is under debugging,has bugs. 74231200Smm * 75231200Smm * 1) config 76231200Smm * options COM_MULTIPORT #if using MC16550II 77231200Smm * device sio0 at nec? port 0x30 tty irq 4 #internal 78231200Smm * device sio1 at nec? port 0xd2 tty irq 5 flags 0x101 #mc1 79231200Smm * device sio2 at nec? port 0x8d2 tty flags 0x101 #mc2 80231200Smm * # ~~~~~iobase ~~multi port flag 81228753Smm * # ~ master device is sio1 82228753Smm * 2) device 83228753Smm * cd /dev; MAKEDEV ttyd0 ttyd1 .. 84228753Smm * 3) /etc/rc.serial 85228753Smm * 57600bps is too fast for sio0(internal8251) 86228753Smm * my ex. 87228753Smm * #set default speed 9600 88228753Smm * modem() 89228753Smm * : 90228753Smm * stty </dev/ttyid$i crtscts 9600 91228753Smm * : # ~~~~ default speed(can change after init.) 92228753Smm * modem 0 1 2 93228753Smm * 4) COMCONSOLE 94228753Smm * not changed. 95228753Smm * 5) PC9861K,PIO9032B,B98_01 96228753Smm * not tested. 97228753Smm */ 98228753Smm/* 99228753Smm * modified for AIWA B98-01 100228753Smm * by T.Hatanou <hatanou@yasuda.comm.waseda.ac.jp> last update: 15 Sep.1995 101228753Smm * 102228753Smm * How to configure... 103228753Smm * # options COM_MULTIPORT # support for MICROCORE MC16550II 104228753Smm * ... comment-out this line, which will conflict with B98_01. 105228753Smm * options "B98_01" # support for AIWA B98-01 106228753Smm * device sio1 at nec? port 0x00d1 tty irq ? 107228753Smm * device sio2 at nec? port 0x00d5 tty irq ? 108228753Smm * ... you can leave these lines `irq ?', irq will be autodetected. 109228753Smm */ 110228753Smm/* 111228753Smm * Modified by Y.Takahashi of Kogakuin University. 112231200Smm */ 113231200Smm/* 114231200Smm * modified for 8251(FIFO) by Seigo TANIMURA <tanimura@FreeBSD.org> 115231200Smm */ 116228753Smm 117231200Smm#ifdef PC98 118231200Smm#define COM_IF_INTERNAL 0x00 119228753Smm#define COM_IF_PC9861K_1 0x01 120231200Smm#define COM_IF_PC9861K_2 0x02 121228753Smm#define COM_IF_IND_SS_1 0x03 122231200Smm#define COM_IF_IND_SS_2 0x04 123231200Smm#define COM_IF_PIO9032B_1 0x05 124231200Smm#define COM_IF_PIO9032B_2 0x06 125231200Smm#define COM_IF_B98_01_1 0x07 126231200Smm#define COM_IF_B98_01_2 0x08 127231200Smm#define COM_IF_END1 COM_IF_B98_01_2 128231200Smm#define COM_IF_RSA98 0x10 /* same as COM_IF_NS16550 */ 129228753Smm#define COM_IF_NS16550 0x11 130231200Smm#define COM_IF_SECOND_CCU 0x12 /* same as COM_IF_NS16550 */ 131228753Smm#define COM_IF_MC16550II 0x13 132231200Smm#define COM_IF_MCRS98 0x14 /* same as COM_IF_MC16550II */ 133231200Smm#define COM_IF_RSB3000 0x15 134231200Smm#define COM_IF_RSB384 0x16 135231200Smm#define COM_IF_MODEM_CARD 0x17 /* same as COM_IF_NS16550 */ 136228753Smm#define COM_IF_RSA98III 0x18 137228753Smm#define COM_IF_ESP98 0x19 138228753Smm#define COM_IF_END2 COM_IF_ESP98 139228753Smm#endif /* PC98 */ 140228753Smm 141228753Smm#include <sys/param.h> 142228753Smm#include <sys/systm.h> 143228753Smm#include <sys/reboot.h> 144228753Smm#include <sys/malloc.h> 145228753Smm#include <sys/tty.h> 146228753Smm#include <sys/proc.h> 147228753Smm#include <sys/module.h> 148228753Smm#include <sys/conf.h> 149228753Smm#include <sys/dkstat.h> 150228753Smm#include <sys/fcntl.h> 151228753Smm#include <sys/interrupt.h> 152231200Smm#include <sys/kernel.h> 153228753Smm#include <sys/syslog.h> 154231200Smm#include <sys/sysctl.h> 155228753Smm#include <sys/bus.h> 156231200Smm#include <machine/bus.h> 157231200Smm#include <sys/rman.h> 158231200Smm#include <sys/timepps.h> 159231200Smm 160231200Smm#ifdef PC98 161231200Smm#include <pc98/pc98/pc98.h> 162231200Smm#include <pc98/pc98/pc98_machdep.h> 163228753Smm#include <i386/isa/ic/i8251.h> 164231200Smm#else 165228753Smm#include <isa/isareg.h> 166231200Smm#endif 167231200Smm#include <isa/isavar.h> 168231200Smm#include <machine/lock.h> 169231200Smm 170228753Smm#include <machine/clock.h> 171228753Smm#include <machine/ipl.h> 172228753Smm#ifndef SMP 173228753Smm#include <machine/lock.h> 174228753Smm#endif 175228753Smm#include <machine/resource.h> 176228753Smm 177228753Smm#include <isa/sioreg.h> 178228753Smm 179228753Smm#ifdef COM_ESP 180228753Smm#include <i386/isa/ic/esp.h> 181228753Smm#endif 182228753Smm#include <i386/isa/ic/ns16550.h> 183228753Smm#ifdef PC98 184228753Smm#include <i386/isa/ic/rsa.h> 185228753Smm#endif 186228753Smm 187228753Smm#ifndef __i386__ 188231200Smm#define disable_intr() 189231200Smm#define enable_intr() 190231200Smm#endif 191231200Smm 192231200Smm#ifdef SMP 193231200Smm#define disable_intr() COM_DISABLE_INTR() 194231200Smm#define enable_intr() COM_ENABLE_INTR() 195231200Smm#endif /* SMP */ 196231200Smm 197231200Smm#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ 198231200Smm 199231200Smm#define CALLOUT_MASK 0x80 200231200Smm#define CONTROL_MASK 0x60 201231200Smm#define CONTROL_INIT_STATE 0x20 202231200Smm#define CONTROL_LOCK_STATE 0x40 203231200Smm#define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev))) 204231200Smm#define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK) 205231200Smm#define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK) 206231200Smm 207231200Smm#ifdef COM_MULTIPORT 208231200Smm/* checks in flags for multiport and which is multiport "master chip" 209231200Smm * for a given card 210231200Smm */ 211231200Smm#define COM_ISMULTIPORT(flags) ((flags) & 0x01) 212231200Smm#define COM_MPMASTER(flags) (((flags) >> 8) & 0x0ff) 213231200Smm#define COM_NOTAST4(flags) ((flags) & 0x04) 214231200Smm#endif /* COM_MULTIPORT */ 215231200Smm 216231200Smm#define COM_CONSOLE(flags) ((flags) & 0x10) 217231200Smm#define COM_FORCECONSOLE(flags) ((flags) & 0x20) 218231200Smm#define COM_LLCONSOLE(flags) ((flags) & 0x40) 219231200Smm#define COM_DEBUGGER(flags) ((flags) & 0x80) 220231200Smm#define COM_LOSESOUTINTS(flags) ((flags) & 0x08) 221231200Smm#define COM_NOFIFO(flags) ((flags) & 0x02) 222231200Smm#define COM_ST16650A(flags) ((flags) & 0x20000) 223228753Smm#define COM_C_NOPROBE (0x40000) 224228753Smm#define COM_NOPROBE(flags) ((flags) & COM_C_NOPROBE) 225228753Smm#define COM_C_IIR_TXRDYBUG (0x80000) 226228753Smm#define COM_IIR_TXRDYBUG(flags) ((flags) & COM_C_IIR_TXRDYBUG) 227228753Smm#define COM_FIFOSIZE(flags) (((flags) & 0xff000000) >> 24) 228228753Smm 229228753Smm#ifdef PC98 230228753Smm#define com_emr com_msr /* Extension mode register for RSB-2000/3000 */ 231228753Smm#else 232228753Smm#define com_scr 7 /* scratch register for 16450-16550 (R/W) */ 233228753Smm#endif 234228753Smm 235228753Smm/* 236228753Smm * com state bits. 237228753Smm * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher 238228753Smm * than the other bits so that they can be tested as a group without masking 239228753Smm * off the low bits. 240228753Smm * 241228753Smm * The following com and tty flags correspond closely: 242231200Smm * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and 243228753Smm * comstop()) 244228753Smm * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart()) 245231200Smm * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam()) 246228753Smm * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam()) 247228753Smm * TS_FLUSH is not used. 248228753Smm * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON. 249228753Smm * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state). 250228753Smm */ 251228753Smm#define CS_BUSY 0x80 /* output in progress */ 252228753Smm#define CS_TTGO 0x40 /* output not stopped by XOFF */ 253228753Smm#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */ 254228753Smm#define CS_CHECKMSR 1 /* check of MSR scheduled */ 255228753Smm#define CS_CTS_OFLOW 2 /* use CTS output flow control */ 256228753Smm#define CS_DTR_OFF 0x10 /* DTR held off */ 257228753Smm#define CS_ODONE 4 /* output completed */ 258228753Smm#define CS_RTS_IFLOW 8 /* use RTS input flow control */ 259228753Smm#define CSE_BUSYCHECK 1 /* siobusycheck() scheduled */ 260228753Smm 261228753Smmstatic char const * const error_desc[] = { 262228753Smm#define CE_OVERRUN 0 263228753Smm "silo overflow", 264228753Smm#define CE_INTERRUPT_BUF_OVERFLOW 1 265228753Smm "interrupt-level buffer overflow", 266228753Smm#define CE_TTY_BUF_OVERFLOW 2 267228753Smm "tty-level buffer overflow", 268228753Smm}; 269228753Smm 270228753Smm#define CE_NTYPES 3 271228753Smm#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum]) 272228753Smm 273228753Smm/* types. XXX - should be elsewhere */ 274228753Smmtypedef u_int Port_t; /* hardware port */ 275228753Smmtypedef u_char bool_t; /* boolean */ 276228753Smm 277228753Smm/* queue of linear buffers */ 278228753Smmstruct lbq { 279228753Smm u_char *l_head; /* next char to process */ 280228753Smm u_char *l_tail; /* one past the last char to process */ 281228753Smm struct lbq *l_next; /* next in queue */ 282228753Smm bool_t l_queued; /* nonzero if queued */ 283228753Smm}; 284228753Smm 285228753Smm/* com device structure */ 286228753Smmstruct com_s { 287228753Smm u_int flags; /* Copy isa device flags */ 288228753Smm u_char state; /* miscellaneous flag bits */ 289228753Smm bool_t active_out; /* nonzero if the callout device is open */ 290228753Smm u_char cfcr_image; /* copy of value written to CFCR */ 291228753Smm#ifdef COM_ESP 292228753Smm bool_t esp; /* is this unit a hayes esp board? */ 293228753Smm#endif 294228753Smm u_char extra_state; /* more flag bits, separate for order trick */ 295228753Smm u_char fifo_image; /* copy of value written to FIFO */ 296228753Smm bool_t hasfifo; /* nonzero for 16550 UARTs */ 297228753Smm bool_t st16650a; /* Is a Startech 16650A or RTS/CTS compat */ 298228753Smm bool_t loses_outints; /* nonzero if device loses output interrupts */ 299228753Smm u_char mcr_image; /* copy of value written to MCR */ 300228753Smm#ifdef COM_MULTIPORT 301228753Smm bool_t multiport; /* is this unit part of a multiport device? */ 302228753Smm#endif /* COM_MULTIPORT */ 303228753Smm bool_t no_irq; /* nonzero if irq is not attached */ 304228753Smm bool_t gone; /* hardware disappeared */ 305228753Smm bool_t poll; /* nonzero if polling is required */ 306228753Smm bool_t poll_output; /* nonzero if polling for output is required */ 307228753Smm int unit; /* unit number */ 308228753Smm int dtr_wait; /* time to hold DTR down on close (* 1/hz) */ 309228753Smm u_int tx_fifo_size; 310228753Smm u_int wopeners; /* # processes waiting for DCD in open() */ 311228753Smm 312228753Smm /* 313228753Smm * The high level of the driver never reads status registers directly 314228753Smm * because there would be too many side effects to handle conveniently. 315228753Smm * Instead, it reads copies of the registers stored here by the 316228753Smm * interrupt handler. 317228753Smm */ 318228753Smm u_char last_modem_status; /* last MSR read by intr handler */ 319228753Smm u_char prev_modem_status; /* last MSR handled by high level */ 320228753Smm 321228753Smm u_char hotchar; /* ldisc-specific char to be handled ASAP */ 322228753Smm u_char *ibuf; /* start of input buffer */ 323228753Smm u_char *ibufend; /* end of input buffer */ 324228753Smm u_char *ibufold; /* old input buffer, to be freed */ 325228753Smm u_char *ihighwater; /* threshold in input buffer */ 326228753Smm u_char *iptr; /* next free spot in input buffer */ 327228753Smm int ibufsize; /* size of ibuf (not include error bytes) */ 328228753Smm int ierroff; /* offset of error bytes in ibuf */ 329228753Smm 330228753Smm struct lbq obufq; /* head of queue of output buffers */ 331228753Smm struct lbq obufs[2]; /* output buffers */ 332228753Smm 333228753Smm#ifdef PC98 334228753Smm Port_t cmd_port; 335228753Smm Port_t sts_port; 336228753Smm Port_t in_modem_port; 337228753Smm Port_t intr_ctrl_port; 338228753Smm int intr_enable; 339228753Smm int pc98_prev_modem_status; 340228753Smm int pc98_modem_delta; 341228753Smm int modem_car_chg_timer; 342228753Smm int pc98_prev_siocmd; 343228753Smm int pc98_prev_siomod; 344228753Smm int modem_checking; 345228753Smm int pc98_if_type; 346228753Smm 347228753Smm bool_t pc98_8251fifo; 348228753Smm bool_t pc98_8251fifo_enable; 349228753Smm#endif /* PC98 */ 350228753Smm Port_t data_port; /* i/o ports */ 351228753Smm#ifdef COM_ESP 352228753Smm Port_t esp_port; 353228753Smm#endif 354228753Smm Port_t int_id_port; 355228753Smm Port_t iobase; 356228753Smm#ifdef PC98 357228753Smm Port_t rsabase; /* iobase address of a I/O-DATA RSA board */ 358228753Smm#endif 359228753Smm Port_t modem_ctl_port; 360228753Smm Port_t line_status_port; 361228753Smm Port_t modem_status_port; 362228753Smm Port_t intr_ctl_port; /* Ports of IIR register */ 363228753Smm 364228753Smm struct tty *tp; /* cross reference */ 365228753Smm 366228753Smm /* Initial state. */ 367231200Smm struct termios it_in; /* should be in struct tty */ 368231200Smm struct termios it_out; 369231200Smm 370231200Smm /* Lock state. */ 371231200Smm struct termios lt_in; /* should be in struct tty */ 372231200Smm struct termios lt_out; 373231200Smm 374231200Smm bool_t do_timestamp; 375231200Smm bool_t do_dcd_timestamp; 376231200Smm struct timeval timestamp; 377231200Smm struct timeval dcd_timestamp; 378231200Smm struct pps_state pps; 379231200Smm 380231200Smm u_long bytes_in; /* statistics */ 381231200Smm u_long bytes_out; 382231200Smm u_int delta_error_counts[CE_NTYPES]; 383231200Smm u_long error_counts[CE_NTYPES]; 384231200Smm 385231200Smm struct resource *irqres; 386231200Smm struct resource *ioportres; 387231200Smm void *cookie; 388231200Smm 389231200Smm /* 390231200Smm * Data area for output buffers. Someday we should build the output 391231200Smm * buffer queue without copying data. 392231200Smm */ 393231200Smm#ifdef PC98 394231200Smm int obufsize; 395231200Smm u_char *obuf1; 396231200Smm u_char *obuf2; 397231200Smm#else 398231200Smm u_char obuf1[256]; 399231200Smm u_char obuf2[256]; 400231200Smm#endif 401231200Smm}; 402231200Smm 403231200Smm#ifdef COM_ESP 404231200Smmstatic int espattach __P((struct com_s *com, Port_t esp_port)); 405231200Smm#endif 406231200Smmstatic int sioattach __P((device_t dev)); 407231200Smmstatic int sio_isa_attach __P((device_t dev)); 408231200Smm 409231200Smmstatic timeout_t siobusycheck; 410228753Smmstatic timeout_t siodtrwakeup; 411228753Smmstatic void comhardclose __P((struct com_s *com)); 412228753Smmstatic void sioinput __P((struct com_s *com)); 413228753Smmstatic void siointr1 __P((struct com_s *com)); 414228753Smmstatic void siointr __P((void *arg)); 415228753Smmstatic int commctl __P((struct com_s *com, int bits, int how)); 416228753Smmstatic int comparam __P((struct tty *tp, struct termios *t)); 417228753Smmstatic swihand_t siopoll; 418228753Smmstatic int sioprobe __P((device_t dev)); 419228753Smmstatic int sio_isa_probe __P((device_t dev)); 420228753Smmstatic void siosettimeout __P((void)); 421228753Smmstatic int siosetwater __P((struct com_s *com, speed_t speed)); 422228753Smmstatic void comstart __P((struct tty *tp)); 423228753Smmstatic void comstop __P((struct tty *tp, int rw)); 424228753Smmstatic timeout_t comwakeup; 425228753Smmstatic void disc_optim __P((struct tty *tp, struct termios *t, 426228753Smm struct com_s *com)); 427228753Smm 428228753Smm#if NCARD > 0 429228753Smmstatic int sio_pccard_attach __P((device_t dev)); 430228753Smmstatic int sio_pccard_detach __P((device_t dev)); 431231200Smmstatic int sio_pccard_probe __P((device_t dev)); 432231200Smm#endif /* NCARD > 0 */ 433231200Smm 434231200Smmstatic char driver_name[] = "sio"; 435231200Smm 436231200Smm/* table and macro for fast conversion from a unit number to its com struct */ 437231200Smmstatic devclass_t sio_devclass; 438231200Smm#define com_addr(unit) ((struct com_s *) \ 439228753Smm devclass_get_softc(sio_devclass, unit)) 440231200Smm 441231200Smmstatic device_method_t sio_isa_methods[] = { 442231200Smm /* Device interface */ 443231200Smm DEVMETHOD(device_probe, sio_isa_probe), 444231200Smm DEVMETHOD(device_attach, sio_isa_attach), 445231200Smm 446231200Smm { 0, 0 } 447231200Smm}; 448231200Smm 449231200Smmstatic driver_t sio_isa_driver = { 450231200Smm driver_name, 451231200Smm sio_isa_methods, 452231200Smm sizeof(struct com_s), 453231200Smm}; 454231200Smm 455231200Smm#if NCARD > 0 456231200Smmstatic device_method_t sio_pccard_methods[] = { 457231200Smm /* Device interface */ 458231200Smm DEVMETHOD(device_probe, sio_pccard_probe), 459231200Smm DEVMETHOD(device_attach, sio_pccard_attach), 460231200Smm DEVMETHOD(device_detach, sio_pccard_detach), 461231200Smm 462231200Smm { 0, 0 } 463231200Smm}; 464231200Smm 465231200Smmstatic driver_t sio_pccard_driver = { 466231200Smm driver_name, 467231200Smm sio_pccard_methods, 468231200Smm sizeof(struct com_s), 469231200Smm}; 470231200Smm#endif (NCARD > 0) 471231200Smm 472231200Smmstatic d_open_t sioopen; 473231200Smmstatic d_close_t sioclose; 474231200Smmstatic d_read_t sioread; 475231200Smmstatic d_write_t siowrite; 476231200Smmstatic d_ioctl_t sioioctl; 477231200Smm 478231200Smm#define CDEV_MAJOR 28 479231200Smmstatic struct cdevsw sio_cdevsw = { 480231200Smm /* open */ sioopen, 481231200Smm /* close */ sioclose, 482231200Smm /* read */ sioread, 483231200Smm /* write */ siowrite, 484231200Smm /* ioctl */ sioioctl, 485231200Smm /* poll */ ttypoll, 486231200Smm /* mmap */ nommap, 487231200Smm /* strategy */ nostrategy, 488228753Smm /* name */ driver_name, 489228753Smm /* maj */ CDEV_MAJOR, 490228753Smm /* dump */ nodump, 491228753Smm /* psize */ nopsize, 492228753Smm /* flags */ D_TTY, 493228753Smm /* bmaj */ -1 494228753Smm}; 495228753Smm 496228753Smmint comconsole = -1; 497228753Smmstatic volatile speed_t comdefaultrate = CONSPEED; 498228753Smm#ifdef __alpha__ 499228753Smmstatic volatile speed_t gdbdefaultrate = CONSPEED; 500228753Smm#endif 501228753Smmstatic u_int com_events; /* input chars + weighted output completions */ 502228753Smmstatic Port_t siocniobase; 503228753Smmstatic int siocnunit; 504228753Smmstatic Port_t siogdbiobase; 505228753Smmstatic int siogdbunit = -1; 506228753Smmstatic bool_t sio_registered; 507228753Smmstatic int sio_timeout; 508228753Smmstatic int sio_timeouts_until_log; 509228753Smmstatic struct callout_handle sio_timeout_handle 510228753Smm = CALLOUT_HANDLE_INITIALIZER(&sio_timeout_handle); 511228753Smmstatic int sio_numunits; 512228753Smm 513228753Smm#ifdef PC98 514228753Smmstruct siodev { 515228753Smm short if_type; 516228753Smm short irq; 517228753Smm Port_t cmd, sts, ctrl, mod; 518228753Smm}; 519228753Smmstatic int sysclock; 520231200Smm 521231200Smm#define COM_INT_DISABLE {int previpri; previpri=spltty(); 522231200Smm#define COM_INT_ENABLE splx(previpri);} 523231200Smm#define IEN_TxFLAG IEN_Tx 524231200Smm 525231200Smm#define COM_CARRIER_DETECT_EMULATE 0 526231200Smm#define PC98_CHECK_MODEM_INTERVAL (hz/10) 527231200Smm#define DCD_OFF_TOLERANCE 2 528231200Smm#define DCD_ON_RECOGNITION 2 529231200Smm#define GET_IFTYPE(flags) ((flags >> 24) & 0x1f) 530231200Smm#define IS_8251(if_type) (!(if_type & 0x10)) 531231200Smm#define COM1_EXT_CLOCK 0x40000 532231200Smm 533228753Smmstatic void commint __P((dev_t dev)); 534228753Smmstatic void com_tiocm_set __P((struct com_s *com, int msr)); 535231200Smmstatic void com_tiocm_bis __P((struct com_s *com, int msr)); 536228753Smmstatic void com_tiocm_bic __P((struct com_s *com, int msr)); 537228753Smmstatic int com_tiocm_get __P((struct com_s *com)); 538228753Smmstatic int com_tiocm_get_delta __P((struct com_s *com)); 539231200Smmstatic void pc98_msrint_start __P((dev_t dev)); 540228753Smmstatic void com_cflag_and_speed_set __P((struct com_s *com, int cflag, int speed)); 541228753Smmstatic int pc98_ttspeedtab __P((struct com_s *com, int speed)); 542228753Smmstatic int pc98_get_modem_status __P((struct com_s *com)); 543228753Smmstatic timeout_t pc98_check_msr; 544228753Smmstatic void pc98_set_baud_rate __P((struct com_s *com, int count)); 545231200Smmstatic void pc98_i8251_reset __P((struct com_s *com, int mode, int command)); 546228753Smmstatic void pc98_disable_i8251_interrupt __P((struct com_s *com, int mod)); 547228753Smmstatic void pc98_enable_i8251_interrupt __P((struct com_s *com, int mod)); 548228753Smmstatic int pc98_check_i8251_interrupt __P((struct com_s *com)); 549228753Smmstatic int pc98_i8251_get_cmd __P((struct com_s *com)); 550228753Smmstatic int pc98_i8251_get_mod __P((struct com_s *com)); 551228753Smmstatic void pc98_i8251_set_cmd __P((struct com_s *com, int x)); 552228753Smmstatic void pc98_i8251_or_cmd __P((struct com_s *com, int x)); 553231200Smmstatic void pc98_i8251_clear_cmd __P((struct com_s *com, int x)); 554231200Smmstatic void pc98_i8251_clear_or_cmd __P((struct com_s *com, int clr, int x)); 555231200Smmstatic int pc98_check_if_type __P((device_t dev, struct siodev *iod)); 556231200Smmstatic int pc98_check_8251vfast __P((void)); 557231200Smmstatic int pc98_check_8251fifo __P((void)); 558231200Smmstatic void pc98_check_sysclock __P((void)); 559231200Smmstatic int pc98_set_ioport __P((struct com_s *com)); 560231200Smm 561231200Smm#define com_int_Tx_disable(com) \ 562231200Smm pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP) 563231200Smm#define com_int_Tx_enable(com) \ 564231200Smm pc98_enable_i8251_interrupt(com,IEN_TxFLAG) 565231200Smm#define com_int_Rx_disable(com) \ 566231200Smm pc98_disable_i8251_interrupt(com,IEN_Rx) 567231200Smm#define com_int_Rx_enable(com) \ 568231200Smm pc98_enable_i8251_interrupt(com,IEN_Rx) 569231200Smm#define com_int_TxRx_disable(com) \ 570231200Smm pc98_disable_i8251_interrupt(com,IEN_Tx|IEN_TxEMP|IEN_Rx) 571231200Smm#define com_int_TxRx_enable(com) \ 572231200Smm pc98_enable_i8251_interrupt(com,IEN_TxFLAG|IEN_Rx) 573231200Smm#define com_send_break_on(com) \ 574231200Smm pc98_i8251_or_cmd(com,CMD8251_SBRK) 575231200Smm#define com_send_break_off(com) \ 576231200Smm pc98_i8251_clear_cmd(com,CMD8251_SBRK) 577231200Smm 578231200Smmstatic struct speedtab pc98speedtab[] = { /* internal RS232C interface */ 579231200Smm { 0, 0, }, 580231200Smm { 50, 50, }, 581231200Smm { 75, 75, }, 582231200Smm { 150, 150, }, 583231200Smm { 200, 200, }, 584231200Smm { 300, 300, }, 585231200Smm { 600, 600, }, 586231200Smm { 1200, 1200, }, 587231200Smm { 2400, 2400, }, 588231200Smm { 4800, 4800, }, 589231200Smm { 9600, 9600, }, 590231200Smm { 19200, 19200, }, 591231200Smm { 38400, 38400, }, 592231200Smm { 51200, 51200, }, 593231200Smm { 76800, 76800, }, 594231200Smm { 20800, 20800, }, 595231200Smm { 31200, 31200, }, 596231200Smm { 41600, 41600, }, 597231200Smm { 62400, 62400, }, 598231200Smm { -1, -1 } 599231200Smm}; 600231200Smmstatic struct speedtab pc98fast_speedtab[] = { 601231200Smm { 9600, 0x80 | COMBRD(9600), }, 602231200Smm { 19200, 0x80 | COMBRD(19200), }, 603231200Smm { 38400, 0x80 | COMBRD(38400), }, 604231200Smm { 57600, 0x80 | COMBRD(57600), }, 605231200Smm { 115200, 0x80 | COMBRD(115200), }, 606231200Smm { -1, -1 } 607231200Smm}; 608231200Smmstatic struct speedtab comspeedtab_pio9032b[] = { 609231200Smm { 300, 6, }, 610231200Smm { 600, 5, }, 611231200Smm { 1200, 4, }, 612231200Smm { 2400, 3, }, 613231200Smm { 4800, 2, }, 614231200Smm { 9600, 1, }, 615231200Smm { 19200, 0, }, 616231200Smm { 38400, 7, }, 617231200Smm { -1, -1 } 618231200Smm}; 619231200Smmstatic struct speedtab comspeedtab_b98_01[] = { 620231200Smm { 75, 11, }, 621231200Smm { 150, 10, }, 622231200Smm { 300, 9, }, 623231200Smm { 600, 8, }, 624231200Smm { 1200, 7, }, 625231200Smm { 2400, 6, }, 626231200Smm { 4800, 5, }, 627231200Smm { 9600, 4, }, 628231200Smm { 19200, 3, }, 629231200Smm { 38400, 2, }, 630231200Smm { 76800, 1, }, 631231200Smm { 153600, 0, }, 632231200Smm { -1, -1 } 633231200Smm}; 634231200Smmstatic struct speedtab comspeedtab_mc16550[] = { 635231200Smm { 300, 1536, }, 636231200Smm { 600, 768, }, 637231200Smm { 1200, 384, }, 638231200Smm { 2400, 192, }, 639231200Smm { 4800, 96, }, 640231200Smm { 9600, 48, }, 641231200Smm { 19200, 24, }, 642231200Smm { 38400, 12, }, 643231200Smm { 57600, 8, }, 644231200Smm { 115200, 4, }, 645231200Smm { 153600, 3, }, 646231200Smm { 230400, 2, }, 647231200Smm { 460800, 1, }, 648231200Smm { -1, -1 } 649231200Smm}; 650231200Smmstatic struct speedtab comspeedtab_rsb384[] = { 651231200Smm { 300, 3840, }, 652231200Smm { 600, 1920, }, 653231200Smm { 1200, 960, }, 654231200Smm { 2400, 480, }, 655231200Smm { 4800, 240, }, 656231200Smm { 9600, 120, }, 657231200Smm { 19200, 60, }, 658231200Smm { 38400, 30, }, 659231200Smm { 57600, 20, }, 660231200Smm { 115200, 10, }, 661231200Smm { 128000, 9, }, 662231200Smm { 144000, 8, }, 663231200Smm { 192000, 6, }, 664231200Smm { 230400, 5, }, 665231200Smm { 288000, 4, }, 666231200Smm { 384000, 3, }, 667231200Smm { 576000, 2, }, 668231200Smm { 1152000, 1, }, 669228753Smm { -1, -1 } 670228753Smm}; 671228753Smmstatic struct speedtab comspeedtab_rsa[] = { 672228753Smm { 0, 0 }, 673228753Smm { 50, COMBRD_RSA(50) }, 674228753Smm { 75, COMBRD_RSA(75) }, 675228753Smm { 110, COMBRD_RSA(110) }, 676228753Smm { 134, COMBRD_RSA(134) }, 677228753Smm { 150, COMBRD_RSA(150) }, 678228753Smm { 200, COMBRD_RSA(200) }, 679228753Smm { 300, COMBRD_RSA(300) }, 680228753Smm { 600, COMBRD_RSA(600) }, 681228753Smm { 1200, COMBRD_RSA(1200) }, 682228753Smm { 1800, COMBRD_RSA(1800) }, 683228753Smm { 2400, COMBRD_RSA(2400) }, 684228753Smm { 4800, COMBRD_RSA(4800) }, 685228753Smm { 9600, COMBRD_RSA(9600) }, 686228753Smm { 19200, COMBRD_RSA(19200) }, 687228753Smm { 38400, COMBRD_RSA(38400) }, 688231200Smm { 57600, COMBRD_RSA(57600) }, 689231200Smm { 115200, COMBRD_RSA(115200) }, 690231200Smm { 230400, COMBRD_RSA(230400) }, 691231200Smm { 460800, COMBRD_RSA(460800) }, 692231200Smm { 921600, COMBRD_RSA(921600) }, 693231200Smm { -1, -1 } 694231200Smm}; 695231200Smm#endif /* PC98 */ 696231200Smm 697228753Smmstatic struct speedtab comspeedtab[] = { 698228753Smm { 0, 0 }, 699231200Smm { 50, COMBRD(50) }, 700231200Smm { 75, COMBRD(75) }, 701231200Smm { 110, COMBRD(110) }, 702231200Smm { 134, COMBRD(134) }, 703228753Smm { 150, COMBRD(150) }, 704231200Smm { 200, COMBRD(200) }, 705228753Smm { 300, COMBRD(300) }, 706228753Smm { 600, COMBRD(600) }, 707228753Smm { 1200, COMBRD(1200) }, 708228753Smm { 1800, COMBRD(1800) }, 709228753Smm { 2400, COMBRD(2400) }, 710228753Smm { 4800, COMBRD(4800) }, 711228753Smm { 9600, COMBRD(9600) }, 712228753Smm { 19200, COMBRD(19200) }, 713228753Smm { 38400, COMBRD(38400) }, 714228753Smm { 57600, COMBRD(57600) }, 715228753Smm { 115200, COMBRD(115200) }, 716228753Smm { -1, -1 } 717231200Smm}; 718231200Smm 719228753Smm#ifdef PC98 720228753Smmstruct { 721231200Smm char *name; 722228753Smm short port_table[7]; 723228753Smm short irr_mask; 724228753Smm struct speedtab *speedtab; 725228753Smm short check_irq; 726228753Smm} if_8251_type[] = { 727228753Smm /* COM_IF_INTERNAL */ 728231200Smm { " (internal)", {0x30, 0x32, 0x32, 0x33, 0x35, -1, -1}, 729228753Smm -1, pc98speedtab, 1 }, 730228753Smm /* COM_IF_PC9861K_1 */ 731231200Smm { " (PC9861K)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, -1, -1}, 732228753Smm 3, NULL, 1 }, 733231200Smm /* COM_IF_PC9861K_2 */ 734231200Smm { " (PC9861K)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, -1, -1}, 735231200Smm 3, NULL, 1 }, 736231200Smm /* COM_IF_IND_SS_1 */ 737231200Smm { " (IND-SS)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb3, -1}, 738231200Smm 3, comspeedtab_mc16550, 1 }, 739231200Smm /* COM_IF_IND_SS_2 */ 740231200Smm { " (IND-SS)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xbb, -1}, 741231200Smm 3, comspeedtab_mc16550, 1 }, 742231200Smm /* COM_IF_PIO9032B_1 */ 743228753Smm { " (PIO9032B)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xb8, -1}, 744228753Smm 7, comspeedtab_pio9032b, 1 }, 745228753Smm /* COM_IF_PIO9032B_2 */ 746228753Smm { " (PIO9032B)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xba, -1}, 747228753Smm 7, comspeedtab_pio9032b, 1 }, 748228753Smm /* COM_IF_B98_01_1 */ 749228753Smm { " (B98-01)", {0xb1, 0xb3, 0xb3, 0xb0, 0xb0, 0xd1, 0xd3}, 750228753Smm 7, comspeedtab_b98_01, 0 }, 751228753Smm /* COM_IF_B98_01_2 */ 752228753Smm { " (B98-01)", {0xb9, 0xbb, 0xbb, 0xb2, 0xb2, 0xd5, 0xd7}, 753228753Smm 7, comspeedtab_b98_01, 0 }, 754228753Smm}; 755228753Smm#define PC98SIO_data_port(type) (if_8251_type[type].port_table[0]) 756228753Smm#define PC98SIO_cmd_port(type) (if_8251_type[type].port_table[1]) 757228753Smm#define PC98SIO_sts_port(type) (if_8251_type[type].port_table[2]) 758228753Smm#define PC98SIO_in_modem_port(type) (if_8251_type[type].port_table[3]) 759228753Smm#define PC98SIO_intr_ctrl_port(type) (if_8251_type[type].port_table[4]) 760228753Smm#define PC98SIO_baud_rate_port(type) (if_8251_type[type].port_table[5]) 761228753Smm#define PC98SIO_func_port(type) (if_8251_type[type].port_table[6]) 762228753Smm 763228753Smm#define I8251F_data 0x130 764228753Smm#define I8251F_lsr 0x132 765228753Smm#define I8251F_msr 0x134 766228753Smm#define I8251F_iir 0x136 767228753Smm#define I8251F_fcr 0x138 768228753Smm#define I8251F_div 0x13a 769228753Smm 770228753Smm 771228753Smmstruct { 772228753Smm char *name; 773228753Smm short irr_read; 774228753Smm short irr_write; 775228753Smm short port_shift; 776228753Smm short io_size; 777228753Smm struct speedtab *speedtab; 778228753Smm} if_16550a_type[] = { 779228753Smm /* COM_IF_RSA98 */ 780228753Smm { " (RSA-98)", -1, -1, 0, IO_COMSIZE, comspeedtab }, 781228753Smm /* COM_IF_NS16550 */ 782228753Smm { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 783228753Smm /* COM_IF_SECOND_CCU */ 784228753Smm { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 785228753Smm /* COM_IF_MC16550II */ 786228753Smm { " (MC16550II)", -1, 0x1000, 8, 1, comspeedtab_mc16550 }, 787228753Smm /* COM_IF_MCRS98 */ 788228753Smm { " (MC-RS98)", -1, 0x1000, 8, 1, comspeedtab_mc16550 }, 789228753Smm /* COM_IF_RSB3000 */ 790228753Smm { " (RSB-3000)", 0xbf, -1, 1, 1, comspeedtab_rsb384 }, 791228753Smm /* COM_IF_RSB384 */ 792228753Smm { " (RSB-384)", 0xbf, -1, 1, 1, comspeedtab_rsb384 }, 793228753Smm /* COM_IF_MODEM_CARD */ 794228753Smm { "", -1, -1, 0, IO_COMSIZE, comspeedtab }, 795228753Smm /* COM_IF_RSA98III */ 796228753Smm { " (RSA-98III)", -1, -1, 0, 16, comspeedtab_rsa }, 797228753Smm /* COM_IF_ESP98 */ 798228753Smm { " (ESP98)", -1, -1, 1, 1, comspeedtab_mc16550 }, 799228753Smm}; 800228753Smm#endif /* PC98 */ 801228753Smm 802228753Smm#ifdef COM_ESP 803228753Smm#ifdef PC98 804228753Smm 805228753Smm/* XXX configure this properly. */ 806228753Smmstatic Port_t likely_com_ports[] = { 0, 0xb0, 0xb1, 0 }; 807228753Smmstatic Port_t likely_esp_ports[] = { 0xc0d0, 0 }; 808228753Smm 809228753Smm#define ESP98_CMD1 (ESP_CMD1 * 0x100) 810228753Smm#define ESP98_CMD2 (ESP_CMD2 * 0x100) 811228753Smm#define ESP98_STATUS1 (ESP_STATUS1 * 0x100) 812228753Smm#define ESP98_STATUS2 (ESP_STATUS2 * 0x100) 813228753Smm 814228753Smm#else /* PC98 */ 815228753Smm 816228753Smm/* XXX configure this properly. */ 817228753Smmstatic Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, }; 818228753Smmstatic Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 }; 819228753Smm 820228753Smm#endif /* PC98 */ 821228753Smm#endif 822228753Smm 823228753Smm/* 824228753Smm * handle sysctl read/write requests for console speed 825228753Smm * 826228753Smm * In addition to setting comdefaultrate for I/O through /dev/console, 827228753Smm * also set the initial and lock values for the /dev/ttyXX device 828228753Smm * if there is one associated with the console. Finally, if the /dev/tty 829228753Smm * device has already been open, change the speed on the open running port 830228753Smm * itself. 831228753Smm */ 832228753Smm 833228753Smmstatic int 834228753Smmsysctl_machdep_comdefaultrate SYSCTL_HANDLER_ARGS 835228753Smm{ 836228753Smm int error, s; 837228753Smm speed_t newspeed; 838228753Smm struct com_s *com; 839228753Smm struct tty *tp; 840228753Smm 841228753Smm newspeed = comdefaultrate; 842228753Smm 843228753Smm error = sysctl_handle_opaque(oidp, &newspeed, sizeof newspeed, req); 844228753Smm if (error || !req->newptr) 845228753Smm return (error); 846228753Smm 847228753Smm comdefaultrate = newspeed; 848228753Smm 849228753Smm if (comconsole < 0) /* serial console not selected? */ 850228753Smm return (0); 851228753Smm 852228753Smm com = com_addr(comconsole); 853228753Smm if (!com) 854228753Smm return (ENXIO); 855228753Smm 856228753Smm /* 857228753Smm * set the initial and lock rates for /dev/ttydXX and /dev/cuaXX 858228753Smm * (note, the lock rates really are boolean -- if non-zero, disallow 859228753Smm * speed changes) 860228753Smm */ 861228753Smm com->it_in.c_ispeed = com->it_in.c_ospeed = 862231200Smm com->lt_in.c_ispeed = com->lt_in.c_ospeed = 863231200Smm com->it_out.c_ispeed = com->it_out.c_ospeed = 864231200Smm com->lt_out.c_ispeed = com->lt_out.c_ospeed = comdefaultrate; 865231200Smm 866228753Smm /* 867231200Smm * if we're open, change the running rate too 868228753Smm */ 869228753Smm tp = com->tp; 870228753Smm if (tp && (tp->t_state & TS_ISOPEN)) { 871228753Smm tp->t_termios.c_ispeed = 872228753Smm tp->t_termios.c_ospeed = comdefaultrate; 873228753Smm s = spltty(); 874228753Smm error = comparam(tp, &tp->t_termios); 875228753Smm splx(s); 876228753Smm } 877228753Smm return error; 878228753Smm} 879228753Smm 880228753SmmSYSCTL_PROC(_machdep, OID_AUTO, conspeed, CTLTYPE_INT | CTLFLAG_RW, 881228753Smm 0, 0, sysctl_machdep_comdefaultrate, "I", ""); 882228753Smm 883228753Smm#define SET_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) | (bit)) 884228753Smm#define CLR_FLAG(dev, bit) device_set_flags(dev, device_get_flags(dev) & ~(bit)) 885228753Smm 886228753Smm#if NCARD > 0 887228753Smmstatic int 888228753Smmsio_pccard_probe(dev) 889228753Smm device_t dev; 890228753Smm{ 891228753Smm /* Do not probe IRQ - pccard doesn't turn on the interrupt line */ 892228753Smm /* until bus_setup_intr */ 893228753Smm SET_FLAG(dev, COM_C_NOPROBE); 894228753Smm 895228753Smm return (sioprobe(dev)); 896228753Smm} 897228753Smm 898228753Smmstatic int 899228753Smmsio_pccard_attach(dev) 900228753Smm device_t dev; 901228753Smm{ 902228753Smm return (sioattach(dev)); 903228753Smm} 904228753Smm 905228753Smm/* 906228753Smm * sio_detach - unload the driver and clear the table. 907228753Smm * XXX TODO: 908228753Smm * This is usually called when the card is ejected, but 909228753Smm * can be caused by a modunload of a controller driver. 910228753Smm * The idea is to reset the driver's view of the device 911228753Smm * and ensure that any driver entry points such as 912228753Smm * read and write do not hang. 913228753Smm */ 914228753Smmstatic int 915228753Smmsio_pccard_detach(dev) 916228753Smm device_t dev; 917228753Smm{ 918228753Smm struct com_s *com; 919228753Smm 920228753Smm com = (struct com_s *) device_get_softc(dev); 921228753Smm if (!com) { 922228753Smm device_printf(dev, "NULL com in siounload\n"); 923228753Smm return (0); 924228753Smm } 925228753Smm if (!com->iobase) { 926228753Smm device_printf(dev, "already unloaded!\n"); 927228753Smm return (0); 928228753Smm } 929228753Smm com->gone = 1; 930228753Smm if (com->irqres) { 931228753Smm bus_teardown_intr(dev, com->irqres, com->cookie); 932228753Smm bus_release_resource(dev, SYS_RES_IRQ, 0, com->irqres); 933228753Smm } 934228753Smm if (com->ioportres) 935228753Smm bus_release_resource(dev, SYS_RES_IOPORT, 0, com->ioportres); 936228753Smm if (com->tp && (com->tp->t_state & TS_ISOPEN)) { 937228753Smm device_printf(dev, "unload\n"); 938228753Smm com->tp->t_gen++; 939228753Smm ttyclose(com->tp); 940228753Smm ttwakeup(com->tp); 941228753Smm ttwwakeup(com->tp); 942228753Smm device_printf(dev, "Was busy, so crash likely\n"); 943228753Smm } else { 944228753Smm if (com->ibuf != NULL) 945228753Smm free(com->ibuf, M_DEVBUF); 946228753Smm device_printf(dev, "unload, gone\n"); 947228753Smm } 948228753Smm return (0); 949228753Smm} 950228753Smm#endif /* NCARD > 0 */ 951228753Smm 952228753Smm 953228753Smmstatic struct isa_pnp_id sio_ids[] = { 954228753Smm {0x0005d041, "Standard PC COM port"}, /* PNP0500 */ 955228753Smm {0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */ 956228753Smm {0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */ 957228753Smm {0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */ 958228753Smm {0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */ 959228753Smm /* Devices that do not have a compatid */ 960228753Smm {0x7602a904, NULL}, /* AEI0276 - 56K v.90 Fax Modem (LKT) */ 961228753Smm {0x00007905, NULL}, /* AKY0000 - 56K Plug&Play Modem */ 962228753Smm {0x01405407, NULL}, /* AZT4001 - AZT3000 PnP SOUND DEVICE, MODEM */ 963228753Smm {0x56039008, NULL}, /* BDP0356 - Best Data 56x2 */ 964228753Smm {0x36339008, NULL}, /* BDP3336 - Best Data Prods. 336F */ 965228753Smm {0x0014490a, NULL}, /* BRI1400 - Boca 33.6 PnP */ 966228753Smm {0x0015490a, NULL}, /* BRI1500 - Internal Fax Data */ 967228753Smm {0x0034490a, NULL}, /* BRI3400 - Internal ACF Modem */ 968228753Smm {0x00b4490a, NULL}, /* BRIB400 - Boca 56k PnP */ 969228753Smm {0x0030320d, NULL}, /* CIR3000 - Cirrus Logic V43 */ 970231200Smm {0x0100440e, NULL}, /* CRD0001 - Cardinal MVP288IV ? */ 971231200Smm {0x1200c31e, NULL}, /* GVC0012 - VF1128HV-R9 (win modem?) */ 972231200Smm {0x0303c31e, NULL}, /* GVC0303 - MaxTech 33.6 PnP D/F/V */ 973231200Smm {0x0505c31e, NULL}, /* GVC0505 - GVC 56k Faxmodem */ 974228753Smm {0x0050c31e, NULL}, /* GVC5000 - some GVC modem */ 975231200Smm {0x3800f91e, NULL}, /* GWY0038 - Telepath with v.90 */ 976231200Smm {0x9062f91e, NULL}, /* GWY6290 - Telepath with x2 Technology */ 977231200Smm {0x0000f435, NULL}, /* MOT0000 - Motorola ModemSURFR 33.6 Intern */ 978231200Smm {0x5015f435, NULL}, /* MOT1550 - Motorola ModemSURFR 56K Modem */ 979231200Smm {0xf015f435, NULL}, /* MOT15F0 - Motorola VoiceSURFR 56K Modem */ 980231200Smm {0x6045f435, NULL}, /* MOT4560 - Motorola ? */ 981231200Smm {0x61e7a338, NULL}, /* NECE761 - 33.6Modem */ 982231200Smm {0x39804f3f, NULL}, /* OZO8039 - Zoom 56k flex */ 983231200Smm {0x1000eb49, NULL}, /* ROK0010 - Rockwell ? */ 984231200Smm {0x5002734a, NULL}, /* RSS0250 - 5614Jx3(G) Internal Modem */ 985228753Smm {0xc100ad4d, NULL}, /* SMM00C1 - Leopard 56k PnP */ 986 {0x9012b04e, NULL}, /* SUP1290 - Supra ? */ 987 {0x1013b04e, NULL}, /* SUP1310 - SupraExpress 336i PnP */ 988 {0x8013b04e, NULL}, /* SUP1380 - SupraExpress 288i PnP Voice */ 989 {0x8113b04e, NULL}, /* SUP1381 - SupraExpress 336i PnP Voice */ 990 {0x5016b04e, NULL}, /* SUP1650 - Supra 336i Sp Intl */ 991 {0x7420b04e, NULL}, /* SUP2070 - Supra ? */ 992 {0x8020b04e, NULL}, /* SUP2080 - Supra ? */ 993 {0x8420b04e, NULL}, /* SUP2084 - SupraExpress 56i PnP */ 994 {0x7121b04e, NULL}, /* SUP2171 - SupraExpress 56i Sp? */ 995 {0x8024b04e, NULL}, /* SUP2480 - Supra ? */ 996 {0x01007256, NULL}, /* USR0001 - U.S. Robotics Inc., Sportster W */ 997 {0x02007256, NULL}, /* USR0002 - U.S. Robotics Inc. Sportster 33. */ 998 {0x04007256, NULL}, /* USR0004 - USR Sportster 14.4k */ 999 {0x06007256, NULL}, /* USR0006 - USR Sportster 33.6k */ 1000 {0x11007256, NULL}, /* USR0011 - USR ? */ 1001 {0x01017256, NULL}, /* USR0101 - USR ? */ 1002 {0x30207256, NULL}, /* USR2030 - U.S.Robotics Inc. Sportster 560 */ 1003 {0x50207256, NULL}, /* USR2050 - U.S.Robotics Inc. Sportster 33. */ 1004 {0x70207256, NULL}, /* USR2070 - U.S.Robotics Inc. Sportster 560 */ 1005 {0x30307256, NULL}, /* USR3030 - U.S. Robotics 56K FAX INT */ 1006 {0x31307256, NULL}, /* USR3031 - U.S. Robotics 56K FAX INT */ 1007 {0x70307256, NULL}, /* USR3070 - U.S. Robotics 56K Voice INT */ 1008 {0x90307256, NULL}, /* USR3090 - USR ? */ 1009 {0x90917256, NULL}, /* USR9190 - USR 56k Voice INT */ 1010 {0x0300695c, NULL}, /* WCI0003 - Fax/Voice/Modem/Speakphone/Asvd */ 1011 {0x61f7896a, NULL}, /* ZTIF761 - Zoom ComStar 33.6 */ 1012#ifdef PC98 1013 {0x0100e4a5, "RSA-98III"}, 1014#endif 1015 {0} 1016}; 1017 1018 1019 1020static int 1021sio_isa_probe(dev) 1022 device_t dev; 1023{ 1024#ifdef PC98 1025 int logical_id; 1026#endif 1027 /* Check isapnp ids */ 1028 if (ISA_PNP_PROBE(device_get_parent(dev), dev, sio_ids) == ENXIO) 1029 return (ENXIO); 1030#ifdef PC98 1031 logical_id = isa_get_logicalid(dev); 1032 if (logical_id == 0x0100e4a5) /* RSA-98III */ 1033 device_set_flags(dev, COM_IF_RSA98III << 24); 1034#endif 1035 return (sioprobe(dev)); 1036} 1037 1038static int 1039sioprobe(dev) 1040 device_t dev; 1041{ 1042#if 0 1043 static bool_t already_init; 1044 device_t xdev; 1045#endif 1046 bool_t failures[10]; 1047 int fn; 1048 device_t idev; 1049 Port_t iobase; 1050 intrmask_t irqmap[4]; 1051 intrmask_t irqs; 1052 u_char mcr_image; 1053 int result; 1054 u_long xirq; 1055 u_int flags = device_get_flags(dev); 1056 int rid; 1057 struct resource *port; 1058#ifdef PC98 1059 int irqout=0; 1060 int tmp; 1061 int port_shift = 0; 1062 struct siodev iod; 1063 Port_t rsabase; 1064#endif 1065 1066 rid = 0; 1067#ifdef PC98 1068 port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 1069 0, ~0, 1, RF_ACTIVE); /* XXX */ 1070#else 1071 port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 1072 0, ~0, IO_COMSIZE, RF_ACTIVE); 1073#endif 1074 if (!port) 1075 return ENXIO; 1076 1077#if 0 1078 /* 1079 * XXX this is broken - when we are first called, there are no 1080 * previously configured IO ports. We could hard code 1081 * 0x3f8, 0x2f8, 0x3e8, 0x2e8 etc but that's probably worse. 1082 * This code has been doing nothing since the conversion since 1083 * "count" is zero the first time around. 1084 */ 1085 if (!already_init) { 1086 /* 1087 * Turn off MCR_IENABLE for all likely serial ports. An unused 1088 * port with its MCR_IENABLE gate open will inhibit interrupts 1089 * from any used port that shares the interrupt vector. 1090 * XXX the gate enable is elsewhere for some multiports. 1091 */ 1092 device_t *devs; 1093 int count, i, xioport; 1094#ifdef PC98 1095 int xiftype; 1096#endif 1097 1098 devclass_get_devices(sio_devclass, &devs, &count); 1099#ifdef PC98 1100 for (i = 0; i < count; i++) { 1101 xdev = devs[i]; 1102 xioport = bus_get_resource_start(xdev, SYS_RES_IOPORT, 0); 1103 xiftype = GET_IFTYPE(device_get_flags(xdev)); 1104 if (device_is_enabled(xdev) && xioport > 0) { 1105 if (IS_8251(xiftype)) 1106 outb(xioport & 0xff00) | PC98SIO_cmd_port(xiftype & 0x0f), 0xf2); 1107 else { 1108 if (xiftype == COM_IF_RSA98III) 1109 xioport += 8; 1110 outb(xioport + (com_mcr << if_16550a_type[xiftype & 0x0f].port_shift), 0); 1111 } 1112 } 1113 } 1114#else 1115 for (i = 0; i < count; i++) { 1116 xdev = devs[i]; 1117 if (device_is_enabled(xdev) && 1118 bus_get_resource(xdev, SYS_RES_IOPORT, 0, &xioport, 1119 NULL) == 0) 1120 outb(xioport + com_mcr, 0); 1121 } 1122#endif 1123 free(devs, M_TEMP); 1124 already_init = TRUE; 1125 } 1126#endif 1127 1128 if (COM_LLCONSOLE(flags)) { 1129 printf("sio%d: reserved for low-level i/o\n", 1130 device_get_unit(dev)); 1131 bus_release_resource(dev, SYS_RES_IOPORT, rid, port); 1132 return (ENXIO); 1133 } 1134 1135#ifdef PC98 1136 DELAY(10); 1137 1138 /* 1139 * If the port is i8251 UART (internal, B98_01) 1140 */ 1141 if (pc98_check_if_type(dev, &iod) == -1) 1142 return ENXIO; 1143 if (iod.irq > 0) 1144 bus_set_resource(dev, SYS_RES_IRQ, 0, iod.irq, 1); 1145 if (IS_8251(iod.if_type)) { 1146 outb(iod.cmd, 0); 1147 DELAY(10); 1148 outb(iod.cmd, 0); 1149 DELAY(10); 1150 outb(iod.cmd, 0); 1151 DELAY(10); 1152 outb(iod.cmd, CMD8251_RESET); 1153 DELAY(1000); /* for a while...*/ 1154 outb(iod.cmd, 0xf2); /* MODE (dummy) */ 1155 DELAY(10); 1156 outb(iod.cmd, 0x01); /* CMD (dummy) */ 1157 DELAY(1000); /* for a while...*/ 1158 if (( inb(iod.sts) & STS8251_TxEMP ) == 0 ) { 1159 result = ENXIO; 1160 } 1161 if (if_8251_type[iod.if_type & 0x0f].check_irq) { 1162 COM_INT_DISABLE 1163 tmp = ( inb( iod.ctrl ) & ~(IEN_Rx|IEN_TxEMP|IEN_Tx)); 1164 outb( iod.ctrl, tmp|IEN_TxEMP ); 1165 DELAY(10); 1166 result = isa_irq_pending() ? 0 : ENXIO; 1167 outb( iod.ctrl, tmp ); 1168 COM_INT_ENABLE 1169 } else { 1170 /* 1171 * B98_01 doesn't activate TxEMP interrupt line 1172 * when being reset, so we can't check irq pending. 1173 */ 1174 result = 0; 1175 } 1176 if (epson_machine_id==0x20) { /* XXX */ 1177 result = 0; 1178 } 1179 bus_release_resource(dev, SYS_RES_IOPORT, rid, port); 1180 return result; 1181 } 1182#endif /* PC98 */ 1183 /* 1184 * If the device is on a multiport card and has an AST/4 1185 * compatible interrupt control register, initialize this 1186 * register and prepare to leave MCR_IENABLE clear in the mcr. 1187 * Otherwise, prepare to set MCR_IENABLE in the mcr. 1188 * Point idev to the device struct giving the correct id_irq. 1189 * This is the struct for the master device if there is one. 1190 */ 1191 idev = dev; 1192 mcr_image = MCR_IENABLE; 1193#ifdef COM_MULTIPORT 1194 if (COM_ISMULTIPORT(flags) && !COM_NOTAST4(flags)) { 1195 Port_t xiobase; 1196 u_long io; 1197 1198 idev = devclass_get_device(sio_devclass, COM_MPMASTER(flags)); 1199 if (idev == NULL) { 1200 printf("sio%d: master device %d not configured\n", 1201 device_get_unit(dev), COM_MPMASTER(flags)); 1202 idev = dev; 1203 } 1204#ifndef PC98 1205 if (bus_get_resource(idev, SYS_RES_IOPORT, 0, &io, NULL) == 0) { 1206 xiobase = io; 1207 if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL)) 1208 outb(xiobase + com_scr, 0x80); /* no irq */ 1209 else 1210 outb(xiobase + com_scr, 0); 1211 } 1212 mcr_image = 0; 1213#endif 1214 } 1215#endif /* COM_MULTIPORT */ 1216 if (bus_get_resource(idev, SYS_RES_IRQ, 0, NULL, NULL) != 0) 1217 mcr_image = 0; 1218 1219 bzero(failures, sizeof failures); 1220 iobase = rman_get_start(port); 1221 1222#ifdef PC98 1223 if (iod.if_type == COM_IF_RSA98III) { 1224 mcr_image = 0; 1225 1226 rsabase = iobase & 0xfff0; 1227 if (rsabase != iobase) 1228 return(0); 1229 iobase += 8; 1230 1231 outb(rsabase + rsa_msr, 0x04); 1232 outb(rsabase + rsa_frr, 0x00); 1233 if ((inb(rsabase + rsa_srr) & 0x36) != 0x36) 1234 return (0); 1235 outb(rsabase + rsa_ier, 0x00); 1236 outb(rsabase + rsa_frr, 0x00); 1237 outb(rsabase + rsa_tivsr, 0x00); 1238 outb(rsabase + rsa_tcr, 0x00); 1239 } 1240 1241 tmp = if_16550a_type[iod.if_type & 0x0f].irr_write; 1242 if (tmp != -1) { 1243 /* MC16550II */ 1244 switch (isa_get_irq(idev)) { 1245 case 3: irqout = 4; break; 1246 case 5: irqout = 5; break; 1247 case 6: irqout = 6; break; 1248 case 12: irqout = 7; break; 1249 default: 1250 printf("sio%d: irq configuration error\n", 1251 device_get_unit(dev)); 1252 return (0); 1253 } 1254 outb((isa_get_port(dev) & 0x00ff) | tmp, irqout); 1255 } 1256 port_shift = if_16550a_type[iod.if_type & 0x0f].port_shift; 1257#endif 1258 1259 /* 1260 * We don't want to get actual interrupts, just masked ones. 1261 * Interrupts from this line should already be masked in the ICU, 1262 * but mask them in the processor as well in case there are some 1263 * (misconfigured) shared interrupts. 1264 */ 1265 disable_intr(); 1266/* EXTRA DELAY? */ 1267 1268 /* 1269 * Initialize the speed and the word size and wait long enough to 1270 * drain the maximum of 16 bytes of junk in device output queues. 1271 * The speed is undefined after a master reset and must be set 1272 * before relying on anything related to output. There may be 1273 * junk after a (very fast) soft reboot and (apparently) after 1274 * master reset. 1275 * XXX what about the UART bug avoided by waiting in comparam()? 1276 * We don't want to to wait long enough to drain at 2 bps. 1277 */ 1278 if (iobase == siocniobase) 1279 DELAY((16 + 1) * 1000000 / (comdefaultrate / 10)); 1280 else { 1281#ifdef PC98 1282 tmp = ttspeedtab(SIO_TEST_SPEED, 1283 if_16550a_type[iod.if_type & 0x0f].speedtab); 1284 outb(iobase + (com_cfcr << port_shift), CFCR_DLAB|CFCR_8BITS); 1285 outb(iobase + (com_dlbl << port_shift), tmp & 0xff); 1286 outb(iobase + (com_dlbh << port_shift), (tmp >> 8) & 0xff); 1287 outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1288#else 1289 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 1290 outb(iobase + com_dlbl, COMBRD(SIO_TEST_SPEED) & 0xff); 1291 outb(iobase + com_dlbh, (u_int) COMBRD(SIO_TEST_SPEED) >> 8); 1292 outb(iobase + com_cfcr, CFCR_8BITS); 1293#endif 1294 DELAY((16 + 1) * 1000000 / (SIO_TEST_SPEED / 10)); 1295 } 1296 1297 /* 1298 * Enable the interrupt gate and disable device interupts. This 1299 * should leave the device driving the interrupt line low and 1300 * guarantee an edge trigger if an interrupt can be generated. 1301 */ 1302/* EXTRA DELAY? */ 1303#ifdef PC98 1304 outb(iobase + (com_mcr << port_shift), mcr_image); 1305 outb(iobase + (com_ier << port_shift), 0); 1306#else 1307 outb(iobase + com_mcr, mcr_image); 1308 outb(iobase + com_ier, 0); 1309#endif 1310 DELAY(1000); /* XXX */ 1311 irqmap[0] = isa_irq_pending(); 1312 1313 /* 1314 * Attempt to set loopback mode so that we can send a null byte 1315 * without annoying any external device. 1316 */ 1317/* EXTRA DELAY? */ 1318#ifdef PC98 1319 outb(iobase + (com_mcr << port_shift), mcr_image | MCR_LOOPBACK); 1320#else 1321 outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK); 1322#endif 1323 1324 /* 1325 * Attempt to generate an output interrupt. On 8250's, setting 1326 * IER_ETXRDY generates an interrupt independent of the current 1327 * setting and independent of whether the THR is empty. On 16450's, 1328 * setting IER_ETXRDY generates an interrupt independent of the 1329 * current setting. On 16550A's, setting IER_ETXRDY only 1330 * generates an interrupt when IER_ETXRDY is not already set. 1331 */ 1332#ifdef PC98 1333 outb(iobase + (com_ier << port_shift), IER_ETXRDY); 1334 if (iod.if_type == COM_IF_RSA98III) 1335 outb(rsabase + rsa_ier, 0x04); 1336#else 1337 outb(iobase + com_ier, IER_ETXRDY); 1338#endif /* PC98 */ 1339 1340 /* 1341 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate 1342 * an interrupt. They'd better generate one for actually doing 1343 * output. Loopback may be broken on the same incompatibles but 1344 * it's unlikely to do more than allow the null byte out. 1345 */ 1346#ifdef PC98 1347 outb(iobase + (com_data << port_shift), 0); 1348#else 1349 outb(iobase + com_data, 0); 1350#endif 1351 DELAY((1 + 2) * 1000000 / (SIO_TEST_SPEED / 10)); 1352 1353 /* 1354 * Turn off loopback mode so that the interrupt gate works again 1355 * (MCR_IENABLE was hidden). This should leave the device driving 1356 * an interrupt line high. It doesn't matter if the interrupt 1357 * line oscillates while we are not looking at it, since interrupts 1358 * are disabled. 1359 */ 1360/* EXTRA DELAY? */ 1361#ifdef PC98 1362 outb(iobase + (com_mcr << port_shift), mcr_image); 1363#else 1364 outb(iobase + com_mcr, mcr_image); 1365#endif /* PC98 */ 1366 1367 /* 1368 * Some pcmcia cards have the "TXRDY bug", so we check everyone 1369 * for IIR_TXRDY implementation ( Palido 321s, DC-1S... ) 1370 */ 1371 if (COM_NOPROBE(flags)) { 1372 /* Reading IIR register twice */ 1373 for (fn = 0; fn < 2; fn ++) { 1374 DELAY(10000); 1375#ifdef PC98 1376 failures[6] = inb(iobase + (com_iir << port_shift)); 1377#else 1378 failures[6] = inb(iobase + com_iir); 1379#endif 1380 } 1381 /* Check IIR_TXRDY clear ? */ 1382 result = 0; 1383 if (failures[6] & IIR_TXRDY) { 1384 /* Nop, Double check with clearing IER */ 1385#ifdef PC98 1386 outb(iobase + (com_ier << port_shift), 0); 1387 if (inb(iobase + (com_iir << port_shift)) 1388 & IIR_NOPEND) { 1389#else 1390 outb(iobase + com_ier, 0); 1391 if (inb(iobase + com_iir) & IIR_NOPEND) { 1392#endif 1393 /* Ok. we're familia this gang */ 1394 SET_FLAG(dev, COM_C_IIR_TXRDYBUG); 1395 } else { 1396 /* Unknown, Just omit this chip.. XXX */ 1397 result = ENXIO; 1398 } 1399 } else { 1400 /* OK. this is well-known guys */ 1401 CLR_FLAG(dev, COM_C_IIR_TXRDYBUG); 1402 } 1403#ifdef PC98 1404 outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1405#else 1406 outb(iobase + com_cfcr, CFCR_8BITS); 1407#endif 1408 enable_intr(); 1409 bus_release_resource(dev, SYS_RES_IOPORT, rid, port); 1410 return (iobase == siocniobase ? 0 : result); 1411 } 1412 1413 /* 1414 * Check that 1415 * o the CFCR, IER and MCR in UART hold the values written to them 1416 * (the values happen to be all distinct - this is good for 1417 * avoiding false positive tests from bus echoes). 1418 * o an output interrupt is generated and its vector is correct. 1419 * o the interrupt goes away when the IIR in the UART is read. 1420 */ 1421/* EXTRA DELAY? */ 1422#ifdef PC98 1423 failures[0] = inb(iobase + (com_cfcr << port_shift)) - CFCR_8BITS; 1424 failures[1] = inb(iobase + (com_ier << port_shift)) - IER_ETXRDY; 1425 failures[2] = inb(iobase + (com_mcr << port_shift)) - mcr_image; 1426#else 1427 failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS; 1428 failures[1] = inb(iobase + com_ier) - IER_ETXRDY; 1429 failures[2] = inb(iobase + com_mcr) - mcr_image; 1430#endif 1431 DELAY(10000); /* Some internal modems need this time */ 1432 irqmap[1] = isa_irq_pending(); 1433#ifdef PC98 1434 failures[4] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1435 - IIR_TXRDY; 1436 if (iod.if_type == COM_IF_RSA98III) 1437 inb(rsabase + rsa_srr); 1438#else 1439 failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY; 1440#endif 1441 DELAY(1000); /* XXX */ 1442 irqmap[2] = isa_irq_pending(); 1443#ifdef PC98 1444 failures[6] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1445 - IIR_NOPEND; 1446 if (iod.if_type == COM_IF_RSA98III) 1447 inb(rsabase + rsa_srr); 1448#else 1449 failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1450#endif 1451 1452 /* 1453 * Turn off all device interrupts and check that they go off properly. 1454 * Leave MCR_IENABLE alone. For ports without a master port, it gates 1455 * the OUT2 output of the UART to 1456 * the ICU input. Closing the gate would give a floating ICU input 1457 * (unless there is another device driving it) and spurious interrupts. 1458 * (On the system that this was first tested on, the input floats high 1459 * and gives a (masked) interrupt as soon as the gate is closed.) 1460 */ 1461#ifdef PC98 1462 outb(iobase + (com_ier << port_shift), 0); 1463 outb(iobase + (com_cfcr << port_shift), CFCR_8BITS); 1464 failures[7] = inb(iobase + (com_ier << port_shift)); 1465 if (iod.if_type == COM_IF_RSA98III) 1466 outb(rsabase + rsa_ier, 0x00); 1467#else 1468 outb(iobase + com_ier, 0); 1469 outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */ 1470 failures[7] = inb(iobase + com_ier); 1471#endif 1472 DELAY(1000); /* XXX */ 1473 irqmap[3] = isa_irq_pending(); 1474#ifdef PC98 1475 failures[9] = (inb(iobase + (com_iir << port_shift)) & IIR_IMASK) 1476 - IIR_NOPEND; 1477 if (iod.if_type == COM_IF_RSA98III) { 1478 inb(rsabase + rsa_srr); 1479 outb(rsabase + rsa_frr, 0x00); 1480 } 1481#else 1482 failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND; 1483#endif 1484 1485 enable_intr(); 1486 1487 irqs = irqmap[1] & ~irqmap[0]; 1488 if (bus_get_resource(idev, SYS_RES_IRQ, 0, &xirq, NULL) == 0 && 1489 ((1 << xirq) & irqs) == 0) 1490 printf( 1491 "sio%d: configured irq %ld not in bitmap of probed irqs %#x\n", 1492 device_get_unit(dev), xirq, irqs); 1493 if (bootverbose) 1494 printf("sio%d: irq maps: %#x %#x %#x %#x\n", 1495 device_get_unit(dev), 1496 irqmap[0], irqmap[1], irqmap[2], irqmap[3]); 1497 1498 result = 0; 1499 for (fn = 0; fn < sizeof failures; ++fn) 1500 if (failures[fn]) { 1501#ifdef PC98 1502 outb(iobase + (com_mcr << port_shift), 0); 1503#else 1504 outb(iobase + com_mcr, 0); 1505#endif 1506 result = ENXIO; 1507 if (bootverbose) { 1508 printf("sio%d: probe failed test(s):", 1509 device_get_unit(dev)); 1510 for (fn = 0; fn < sizeof failures; ++fn) 1511 if (failures[fn]) 1512 printf(" %d", fn); 1513 printf("\n"); 1514 } 1515 break; 1516 } 1517 bus_release_resource(dev, SYS_RES_IOPORT, rid, port); 1518 return (iobase == siocniobase ? 0 : result); 1519} 1520 1521#ifdef COM_ESP 1522static int 1523espattach(com, esp_port) 1524 struct com_s *com; 1525 Port_t esp_port; 1526{ 1527 u_char dips; 1528 u_char val; 1529 1530 /* 1531 * Check the ESP-specific I/O port to see if we're an ESP 1532 * card. If not, return failure immediately. 1533 */ 1534 if ((inb(esp_port) & 0xf3) == 0) { 1535 printf(" port 0x%x is not an ESP board?\n", esp_port); 1536 return (0); 1537 } 1538 1539 /* 1540 * We've got something that claims to be a Hayes ESP card. 1541 * Let's hope so. 1542 */ 1543 1544 /* Get the dip-switch configuration */ 1545#ifdef PC98 1546 outb(esp_port + ESP98_CMD1, ESP_GETDIPS); 1547 dips = inb(esp_port + ESP98_STATUS1); 1548#else 1549 outb(esp_port + ESP_CMD1, ESP_GETDIPS); 1550 dips = inb(esp_port + ESP_STATUS1); 1551#endif 1552 1553 /* 1554 * Bits 0,1 of dips say which COM port we are. 1555 */ 1556#ifdef PC98 1557 if ((com->iobase & 0xff) == likely_com_ports[dips & 0x03]) 1558#else 1559 if (com->iobase == likely_com_ports[dips & 0x03]) 1560#endif 1561 printf(" : ESP"); 1562 else { 1563 printf(" esp_port has com %d\n", dips & 0x03); 1564 return (0); 1565 } 1566 1567 /* 1568 * Check for ESP version 2.0 or later: bits 4,5,6 = 010. 1569 */ 1570#ifdef PC98 1571 outb(esp_port + ESP98_CMD1, ESP_GETTEST); 1572 val = inb(esp_port + ESP98_STATUS1); /* clear reg 1 */ 1573 val = inb(esp_port + ESP98_STATUS2); 1574#else 1575 outb(esp_port + ESP_CMD1, ESP_GETTEST); 1576 val = inb(esp_port + ESP_STATUS1); /* clear reg 1 */ 1577 val = inb(esp_port + ESP_STATUS2); 1578#endif 1579 if ((val & 0x70) < 0x20) { 1580 printf("-old (%o)", val & 0x70); 1581 return (0); 1582 } 1583 1584 /* 1585 * Check for ability to emulate 16550: bit 7 == 1 1586 */ 1587 if ((dips & 0x80) == 0) { 1588 printf(" slave"); 1589 return (0); 1590 } 1591 1592 /* 1593 * Okay, we seem to be a Hayes ESP card. Whee. 1594 */ 1595 com->esp = TRUE; 1596 com->esp_port = esp_port; 1597 return (1); 1598} 1599#endif /* COM_ESP */ 1600 1601static int 1602sio_isa_attach(dev) 1603 device_t dev; 1604{ 1605 return (sioattach(dev)); 1606} 1607 1608static int 1609sioattach(dev) 1610 device_t dev; 1611{ 1612 struct com_s *com; 1613#ifdef COM_ESP 1614 Port_t *espp; 1615#endif 1616 Port_t iobase; 1617 int unit; 1618 u_int flags; 1619 int rid; 1620 struct resource *port; 1621 int ret; 1622#ifdef PC98 1623 int port_shift = 0; 1624 u_char *obuf; 1625 u_long obufsize; 1626#endif 1627 1628 rid = 0; 1629#ifdef PC98 1630 port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 1631 0, ~0, 1, RF_ACTIVE); /* XXX */ 1632#else 1633 port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 1634 0, ~0, IO_COMSIZE, RF_ACTIVE); 1635#endif 1636 if (!port) 1637 return ENXIO; 1638 1639 iobase = rman_get_start(port); 1640 unit = device_get_unit(dev); 1641 com = device_get_softc(dev); 1642 flags = device_get_flags(dev); 1643 1644 if (unit >= sio_numunits) 1645 sio_numunits = unit + 1; 1646 1647#ifdef PC98 1648 obufsize = 256; 1649 if (GET_IFTYPE(flags) == COM_IF_RSA98III) { 1650 iobase += 8; 1651 obufsize = 2048; 1652 } 1653 if ((obuf = malloc(obufsize * 2, M_DEVBUF, M_NOWAIT)) == NULL) 1654 return ENXIO; 1655 bzero(obuf, obufsize * 2); 1656#endif 1657 1658 /* 1659 * sioprobe() has initialized the device registers as follows: 1660 * o cfcr = CFCR_8BITS. 1661 * It is most important that CFCR_DLAB is off, so that the 1662 * data port is not hidden when we enable interrupts. 1663 * o ier = 0. 1664 * Interrupts are only enabled when the line is open. 1665 * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible 1666 * interrupt control register or the config specifies no irq. 1667 * Keeping MCR_DTR and MCR_RTS off might stop the external 1668 * device from sending before we are ready. 1669 */ 1670 bzero(com, sizeof *com); 1671#ifdef PC98 1672 com->obufsize = obufsize; 1673 com->obuf1 = obuf; 1674 com->obuf2 = obuf + obufsize; 1675#endif 1676 com->unit = unit; 1677 com->ioportres = port; 1678 com->cfcr_image = CFCR_8BITS; 1679 com->dtr_wait = 3 * hz; 1680 com->loses_outints = COM_LOSESOUTINTS(flags) != 0; 1681 com->no_irq = bus_get_resource(dev, SYS_RES_IRQ, 0, NULL, NULL); 1682 com->tx_fifo_size = 1; 1683 com->obufs[0].l_head = com->obuf1; 1684 com->obufs[1].l_head = com->obuf2; 1685 1686 com->iobase = iobase; 1687#ifdef PC98 1688 com->pc98_if_type = GET_IFTYPE(flags); 1689 1690 if (pc98_set_ioport(com) == -1) { 1691 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 1692 1693 com->data_port = iobase + (com_data << port_shift); 1694 com->int_id_port = iobase + (com_iir << port_shift); 1695 com->modem_ctl_port = iobase + (com_mcr << port_shift); 1696 com->mcr_image = inb(com->modem_ctl_port); 1697 com->line_status_port = iobase + (com_lsr << port_shift); 1698 com->modem_status_port = iobase + (com_msr << port_shift); 1699 com->intr_ctl_port = iobase + (com_ier << port_shift); 1700 } 1701 if (com->pc98_if_type == COM_IF_INTERNAL && pc98_check_8251fifo()) { 1702 com->pc98_8251fifo = 1; 1703 com->pc98_8251fifo_enable = 0; 1704 } 1705#else /* not PC98 */ 1706 com->data_port = iobase + com_data; 1707 com->int_id_port = iobase + com_iir; 1708 com->modem_ctl_port = iobase + com_mcr; 1709 com->mcr_image = inb(com->modem_ctl_port); 1710 com->line_status_port = iobase + com_lsr; 1711 com->modem_status_port = iobase + com_msr; 1712 com->intr_ctl_port = iobase + com_ier; 1713#endif 1714 1715 /* 1716 * We don't use all the flags from <sys/ttydefaults.h> since they 1717 * are only relevant for logins. It's important to have echo off 1718 * initially so that the line doesn't start blathering before the 1719 * echo flag can be turned off. 1720 */ 1721 com->it_in.c_iflag = 0; 1722 com->it_in.c_oflag = 0; 1723 com->it_in.c_cflag = TTYDEF_CFLAG; 1724 com->it_in.c_lflag = 0; 1725 if (unit == comconsole) { 1726#ifdef PC98 1727 if (IS_8251(com->pc98_if_type)) 1728 DELAY(100000); 1729#endif 1730 com->it_in.c_iflag = TTYDEF_IFLAG; 1731 com->it_in.c_oflag = TTYDEF_OFLAG; 1732 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL; 1733 com->it_in.c_lflag = TTYDEF_LFLAG; 1734 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL; 1735 com->lt_out.c_ispeed = com->lt_out.c_ospeed = 1736 com->lt_in.c_ispeed = com->lt_in.c_ospeed = 1737 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate; 1738 } else 1739 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED; 1740 if (siosetwater(com, com->it_in.c_ispeed) != 0) { 1741 enable_intr(); 1742 free(com, M_DEVBUF); 1743 /* 1744 * Leave i/o resources allocated if this is a `cn'-level 1745 * console, so that other devices can't snarf them. 1746 */ 1747 if (iobase != siocniobase) 1748 bus_release_resource(dev, SYS_RES_IOPORT, rid, port); 1749 return (ENOMEM); 1750 } 1751 enable_intr(); 1752 termioschars(&com->it_in); 1753 com->it_out = com->it_in; 1754 1755 /* attempt to determine UART type */ 1756 printf("sio%d: type", unit); 1757 1758 1759#ifndef PC98 1760#ifdef COM_MULTIPORT 1761 if (!COM_ISMULTIPORT(flags) && !COM_IIR_TXRDYBUG(flags)) 1762#else 1763 if (!COM_IIR_TXRDYBUG(flags)) 1764#endif 1765 { 1766 u_char scr; 1767 u_char scr1; 1768 u_char scr2; 1769 1770 scr = inb(iobase + com_scr); 1771 outb(iobase + com_scr, 0xa5); 1772 scr1 = inb(iobase + com_scr); 1773 outb(iobase + com_scr, 0x5a); 1774 scr2 = inb(iobase + com_scr); 1775 outb(iobase + com_scr, scr); 1776 if (scr1 != 0xa5 || scr2 != 0x5a) { 1777 printf(" 8250"); 1778 goto determined_type; 1779 } 1780 } 1781#endif /* !PC98 */ 1782#ifdef PC98 1783 if (IS_8251(com->pc98_if_type)) { 1784 if (com->pc98_8251fifo && !COM_NOFIFO(flags)) 1785 com->tx_fifo_size = 16; 1786 com_int_TxRx_disable( com ); 1787 com_cflag_and_speed_set( com, com->it_in.c_cflag, comdefaultrate ); 1788 com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 1789 com_send_break_off( com ); 1790 1791 if (com->pc98_if_type == COM_IF_INTERNAL) { 1792 printf(" (internal%s%s)", 1793 com->pc98_8251fifo ? " fifo" : "", 1794 PC98SIO_baud_rate_port(com->pc98_if_type) != -1 ? 1795 " v-fast" : ""); 1796 } else { 1797 printf(" 8251%s", if_8251_type[com->pc98_if_type & 0x0f].name); 1798 } 1799 } else { 1800 outb(iobase + (com_fifo << port_shift), FIFO_ENABLE | FIFO_RX_HIGH); 1801#else 1802 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH); 1803#endif /* PC98 */ 1804 DELAY(100); 1805 com->st16650a = 0; 1806 switch (inb(com->int_id_port) & IIR_FIFO_MASK) { 1807 case FIFO_RX_LOW: 1808 printf(" 16450"); 1809 break; 1810 case FIFO_RX_MEDL: 1811 printf(" 16450?"); 1812 break; 1813 case FIFO_RX_MEDH: 1814 printf(" 16550?"); 1815 break; 1816 case FIFO_RX_HIGH: 1817 if (COM_NOFIFO(flags)) { 1818 printf(" 16550A fifo disabled"); 1819 } else { 1820 com->hasfifo = TRUE; 1821#ifdef PC98 1822 com->tx_fifo_size = 0; /* XXX flag conflicts. */ 1823 printf(" 16550A"); 1824#else 1825 if (COM_ST16650A(flags)) { 1826 com->st16650a = 1; 1827 com->tx_fifo_size = 32; 1828 printf(" ST16650A"); 1829 } else { 1830 com->tx_fifo_size = COM_FIFOSIZE(flags); 1831 printf(" 16550A"); 1832 } 1833#endif 1834 } 1835#ifdef PC98 1836 if (com->pc98_if_type == COM_IF_RSA98III) { 1837 com->tx_fifo_size = 2048; 1838 com->rsabase = isa_get_port(dev); 1839 outb(com->rsabase + rsa_ier, 0x00); 1840 outb(com->rsabase + rsa_frr, 0x00); 1841 } 1842#endif 1843 1844#ifdef COM_ESP 1845#ifdef PC98 1846 if (com->pc98_if_type == COM_IF_ESP98) 1847#endif 1848 for (espp = likely_esp_ports; *espp != 0; espp++) 1849 if (espattach(com, *espp)) { 1850 com->tx_fifo_size = 1024; 1851 break; 1852 } 1853#endif 1854 if (!com->st16650a) { 1855 if (!com->tx_fifo_size) 1856 com->tx_fifo_size = 16; 1857 else 1858 printf(" lookalike with %d bytes FIFO", 1859 com->tx_fifo_size); 1860 } 1861 1862 break; 1863 } 1864 1865#ifdef PC98 1866 if (com->pc98_if_type == COM_IF_RSB3000) { 1867 /* Set RSB-2000/3000 Extended Buffer mode. */ 1868 u_char lcr; 1869 lcr = inb(iobase + (com_cfcr << port_shift)); 1870 outb(iobase + (com_cfcr << port_shift), lcr | CFCR_DLAB); 1871 outb(iobase + (com_emr << port_shift), EMR_EXBUFF | EMR_EFMODE); 1872 outb(iobase + (com_cfcr << port_shift), lcr); 1873 } 1874#endif 1875 1876#ifdef COM_ESP 1877 if (com->esp) { 1878 /* 1879 * Set 16550 compatibility mode. 1880 * We don't use the ESP_MODE_SCALE bit to increase the 1881 * fifo trigger levels because we can't handle large 1882 * bursts of input. 1883 * XXX flow control should be set in comparam(), not here. 1884 */ 1885#ifdef PC98 1886 outb(com->esp_port + ESP98_CMD1, ESP_SETMODE); 1887 outb(com->esp_port + ESP98_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO); 1888#else 1889 outb(com->esp_port + ESP_CMD1, ESP_SETMODE); 1890 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO); 1891#endif 1892 1893 /* Set RTS/CTS flow control. */ 1894#ifdef PC98 1895 outb(com->esp_port + ESP98_CMD1, ESP_SETFLOWTYPE); 1896 outb(com->esp_port + ESP98_CMD2, ESP_FLOW_RTS); 1897 outb(com->esp_port + ESP98_CMD2, ESP_FLOW_CTS); 1898#else 1899 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE); 1900 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS); 1901 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS); 1902#endif 1903 1904 /* Set flow-control levels. */ 1905#ifdef PC98 1906 outb(com->esp_port + ESP98_CMD1, ESP_SETRXFLOW); 1907 outb(com->esp_port + ESP98_CMD2, HIBYTE(768)); 1908 outb(com->esp_port + ESP98_CMD2, LOBYTE(768)); 1909 outb(com->esp_port + ESP98_CMD2, HIBYTE(512)); 1910 outb(com->esp_port + ESP98_CMD2, LOBYTE(512)); 1911#else 1912 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW); 1913 outb(com->esp_port + ESP_CMD2, HIBYTE(768)); 1914 outb(com->esp_port + ESP_CMD2, LOBYTE(768)); 1915 outb(com->esp_port + ESP_CMD2, HIBYTE(512)); 1916 outb(com->esp_port + ESP_CMD2, LOBYTE(512)); 1917#endif 1918 1919#ifdef PC98 1920 /* Set UART clock prescaler. */ 1921 outb(com->esp_port + ESP98_CMD1, ESP_SETCLOCK); 1922 outb(com->esp_port + ESP98_CMD2, 2); /* 4 times */ 1923#endif 1924 } 1925#endif /* COM_ESP */ 1926#ifdef PC98 1927 printf("%s", if_16550a_type[com->pc98_if_type & 0x0f].name); 1928 outb(iobase + (com_fifo << port_shift), 0); 1929#else 1930 outb(iobase + com_fifo, 0); 1931determined_type: ; 1932#endif 1933 1934#ifdef COM_MULTIPORT 1935 if (COM_ISMULTIPORT(flags)) { 1936 device_t masterdev; 1937 1938 com->multiport = TRUE; 1939 printf(" (multiport"); 1940 masterdev = devclass_get_device(sio_devclass, 1941 COM_MPMASTER(flags)); 1942 com->no_irq = bus_get_resource(masterdev, SYS_RES_IRQ, 0, NULL, 1943 NULL); 1944 if (unit == COM_MPMASTER(flags)) 1945 printf(" master"); 1946 printf(")"); 1947 } 1948#endif /* COM_MULTIPORT */ 1949#ifdef PC98 1950 } 1951#endif 1952 if (unit == comconsole) 1953 printf(", console"); 1954 if (COM_IIR_TXRDYBUG(flags)) 1955 printf(" with a bogus IIR_TXRDY register"); 1956 printf("\n"); 1957 1958 if (!sio_registered) { 1959 register_swi(SWI_TTY, siopoll); 1960 sio_registered = TRUE; 1961 } 1962 make_dev(&sio_cdevsw, unit, 1963 UID_ROOT, GID_WHEEL, 0600, "ttyd%r", unit); 1964 make_dev(&sio_cdevsw, unit | CONTROL_INIT_STATE, 1965 UID_ROOT, GID_WHEEL, 0600, "ttyid%r", unit); 1966 make_dev(&sio_cdevsw, unit | CONTROL_LOCK_STATE, 1967 UID_ROOT, GID_WHEEL, 0600, "ttyld%r", unit); 1968 make_dev(&sio_cdevsw, unit | CALLOUT_MASK, 1969 UID_UUCP, GID_DIALER, 0660, "cuaa%r", unit); 1970 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_INIT_STATE, 1971 UID_UUCP, GID_DIALER, 0660, "cuaia%r", unit); 1972 make_dev(&sio_cdevsw, unit | CALLOUT_MASK | CONTROL_LOCK_STATE, 1973 UID_UUCP, GID_DIALER, 0660, "cuala%r", unit); 1974 com->flags = flags; 1975 com->pps.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; 1976 pps_init(&com->pps); 1977 1978 rid = 0; 1979 com->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0ul, ~0ul, 1, 1980 RF_ACTIVE); 1981 if (com->irqres) { 1982 ret = BUS_SETUP_INTR(device_get_parent(dev), dev, com->irqres, 1983 INTR_TYPE_TTY | INTR_TYPE_FAST, 1984 siointr, com, &com->cookie); 1985 if (ret) { 1986 ret = BUS_SETUP_INTR(device_get_parent(dev), dev, 1987 com->irqres, INTR_TYPE_TTY, 1988 siointr, com, &com->cookie); 1989 if (ret == 0) 1990 device_printf(dev, "unable to activate interrupt in fast mode - using normal mode"); 1991 } 1992 if (ret) 1993 device_printf(dev, "could not activate interrupt\n"); 1994 } 1995 1996 return (0); 1997} 1998 1999static int 2000sioopen(dev, flag, mode, p) 2001 dev_t dev; 2002 int flag; 2003 int mode; 2004 struct proc *p; 2005{ 2006 struct com_s *com; 2007 int error; 2008 Port_t iobase; 2009 int mynor; 2010 int s; 2011 struct tty *tp; 2012 int unit; 2013#ifdef PC98 2014 int port_shift = 0; 2015#endif 2016 2017 mynor = minor(dev); 2018 unit = MINOR_TO_UNIT(mynor); 2019 com = com_addr(unit); 2020 if (com == NULL) 2021 return (ENXIO); 2022 if (com->gone) 2023 return (ENXIO); 2024 if (mynor & CONTROL_MASK) 2025 return (0); 2026 tp = dev->si_tty = com->tp = ttymalloc(com->tp); 2027 s = spltty(); 2028 2029#ifdef PC98 2030 if (!IS_8251(com->pc98_if_type)) 2031 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 2032#endif 2033 /* 2034 * We jump to this label after all non-interrupted sleeps to pick 2035 * up any changes of the device state. 2036 */ 2037open_top: 2038 while (com->state & CS_DTR_OFF) { 2039 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0); 2040 if (com_addr(unit) == NULL) 2041 return (ENXIO); 2042 if (error != 0 || com->gone) 2043 goto out; 2044 } 2045 if (tp->t_state & TS_ISOPEN) { 2046 /* 2047 * The device is open, so everything has been initialized. 2048 * Handle conflicts. 2049 */ 2050 if (mynor & CALLOUT_MASK) { 2051 if (!com->active_out) { 2052 error = EBUSY; 2053 goto out; 2054 } 2055 } else { 2056 if (com->active_out) { 2057 if (flag & O_NONBLOCK) { 2058 error = EBUSY; 2059 goto out; 2060 } 2061 error = tsleep(&com->active_out, 2062 TTIPRI | PCATCH, "siobi", 0); 2063 if (com_addr(unit) == NULL) 2064 return (ENXIO); 2065 if (error != 0 || com->gone) 2066 goto out; 2067 goto open_top; 2068 } 2069 } 2070 if (tp->t_state & TS_XCLUDE && 2071 suser(p)) { 2072 error = EBUSY; 2073 goto out; 2074 } 2075 } else { 2076 /* 2077 * The device isn't open, so there are no conflicts. 2078 * Initialize it. Initialization is done twice in many 2079 * cases: to preempt sleeping callin opens if we are 2080 * callout, and to complete a callin open after DCD rises. 2081 */ 2082 tp->t_oproc = comstart; 2083 tp->t_param = comparam; 2084 tp->t_stop = comstop; 2085 tp->t_dev = dev; 2086 tp->t_termios = mynor & CALLOUT_MASK 2087 ? com->it_out : com->it_in; 2088#ifdef PC98 2089 if (!IS_8251(com->pc98_if_type)) 2090#endif 2091 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET); 2092 com->poll = com->no_irq; 2093 com->poll_output = com->loses_outints; 2094 ++com->wopeners; 2095 error = comparam(tp, &tp->t_termios); 2096 --com->wopeners; 2097 if (error != 0) 2098 goto out; 2099#ifdef PC98 2100 if (IS_8251(com->pc98_if_type)) { 2101 com_tiocm_bis(com, TIOCM_DTR|TIOCM_RTS); 2102 pc98_msrint_start(dev); 2103 if (com->pc98_8251fifo) { 2104 com->pc98_8251fifo_enable = 1; 2105 outb(I8251F_fcr, CTRL8251F_ENABLE | 2106 CTRL8251F_XMT_RST | CTRL8251F_RCV_RST); 2107 } 2108 } 2109#endif 2110 /* 2111 * XXX we should goto open_top if comparam() slept. 2112 */ 2113 iobase = com->iobase; 2114 if (com->hasfifo) { 2115 /* 2116 * (Re)enable and drain fifos. 2117 * 2118 * Certain SMC chips cause problems if the fifos 2119 * are enabled while input is ready. Turn off the 2120 * fifo if necessary to clear the input. We test 2121 * the input ready bit after enabling the fifos 2122 * since we've already enabled them in comparam() 2123 * and to handle races between enabling and fresh 2124 * input. 2125 */ 2126 while (TRUE) { 2127#ifdef PC98 2128 outb(iobase + (com_fifo << port_shift), 2129 FIFO_RCV_RST | FIFO_XMT_RST 2130 | com->fifo_image); 2131 if (com->pc98_if_type == COM_IF_RSA98III) 2132 outb(com->rsabase + rsa_frr , 0x00); 2133#else 2134 outb(iobase + com_fifo, 2135 FIFO_RCV_RST | FIFO_XMT_RST 2136 | com->fifo_image); 2137#endif 2138 /* 2139 * XXX the delays are for superstitious 2140 * historical reasons. It must be less than 2141 * the character time at the maximum 2142 * supported speed (87 usec at 115200 bps 2143 * 8N1). Otherwise we might loop endlessly 2144 * if data is streaming in. We used to use 2145 * delays of 100. That usually worked 2146 * because DELAY(100) used to usually delay 2147 * for about 85 usec instead of 100. 2148 */ 2149 DELAY(50); 2150#ifndef PC98 2151 if (!(inb(com->line_status_port) & LSR_RXRDY)) 2152#else 2153 if (com->pc98_if_type == COM_IF_RSA98III 2154 ? !(inb(com->rsabase + rsa_srr) & 0x08) 2155 : !(inb(com->line_status_port) & LSR_RXRDY)) 2156#endif 2157 break; 2158#ifdef PC98 2159 outb(iobase + (com_fifo << port_shift), 0); 2160#else 2161 outb(iobase + com_fifo, 0); 2162#endif 2163 DELAY(50); 2164 (void) inb(com->data_port); 2165 } 2166 } 2167 2168 disable_intr(); 2169#ifdef PC98 2170 if (IS_8251(com->pc98_if_type)) { 2171 com_tiocm_bis(com, TIOCM_LE); 2172 com->pc98_prev_modem_status = pc98_get_modem_status(com); 2173 com_int_Rx_enable(com); 2174 } else { 2175#endif 2176 (void) inb(com->line_status_port); 2177 (void) inb(com->data_port); 2178 com->prev_modem_status = com->last_modem_status 2179 = inb(com->modem_status_port); 2180 if (COM_IIR_TXRDYBUG(com->flags)) { 2181 outb(com->intr_ctl_port, IER_ERXRDY | IER_ERLS 2182 | IER_EMSC); 2183 } else { 2184 outb(com->intr_ctl_port, IER_ERXRDY | IER_ETXRDY 2185 | IER_ERLS | IER_EMSC); 2186 } 2187#ifdef PC98 2188 if (com->pc98_if_type == COM_IF_RSA98III) { 2189 outb(com->rsabase + rsa_ier, 0x1d); 2190 outb(com->intr_ctl_port, IER_ERLS | IER_EMSC); 2191 } 2192#endif 2193#ifdef PC98 2194 } 2195#endif 2196 enable_intr(); 2197 /* 2198 * Handle initial DCD. Callout devices get a fake initial 2199 * DCD (trapdoor DCD). If we are callout, then any sleeping 2200 * callin opens get woken up and resume sleeping on "siobi" 2201 * instead of "siodcd". 2202 */ 2203 /* 2204 * XXX `mynor & CALLOUT_MASK' should be 2205 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where 2206 * TRAPDOOR_CARRIER is the default initial state for callout 2207 * devices and SOFT_CARRIER is like CLOCAL except it hides 2208 * the true carrier. 2209 */ 2210#ifdef PC98 2211 if ((IS_8251(com->pc98_if_type) && 2212 (pc98_get_modem_status(com) & TIOCM_CAR)) || 2213 (!IS_8251(com->pc98_if_type) && 2214 (com->prev_modem_status & MSR_DCD)) || 2215 mynor & CALLOUT_MASK) 2216#else 2217 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK) 2218#endif 2219 (*linesw[tp->t_line].l_modem)(tp, 1); 2220 } 2221 /* 2222 * Wait for DCD if necessary. 2223 */ 2224 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK) 2225 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) { 2226 ++com->wopeners; 2227 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0); 2228 if (com_addr(unit) == NULL) 2229 return (ENXIO); 2230 --com->wopeners; 2231 if (error != 0 || com->gone) 2232 goto out; 2233 goto open_top; 2234 } 2235 error = (*linesw[tp->t_line].l_open)(dev, tp); 2236 disc_optim(tp, &tp->t_termios, com); 2237 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK) 2238 com->active_out = TRUE; 2239 siosettimeout(); 2240out: 2241 splx(s); 2242 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0) 2243 comhardclose(com); 2244 return (error); 2245} 2246 2247static int 2248sioclose(dev, flag, mode, p) 2249 dev_t dev; 2250 int flag; 2251 int mode; 2252 struct proc *p; 2253{ 2254 struct com_s *com; 2255 int mynor; 2256 int s; 2257 struct tty *tp; 2258 2259 mynor = minor(dev); 2260 if (mynor & CONTROL_MASK) 2261 return (0); 2262 com = com_addr(MINOR_TO_UNIT(mynor)); 2263 tp = com->tp; 2264 s = spltty(); 2265 (*linesw[tp->t_line].l_close)(tp, flag); 2266#ifdef PC98 2267 com->modem_checking = 0; 2268#endif 2269 disc_optim(tp, &tp->t_termios, com); 2270 comstop(tp, FREAD | FWRITE); 2271 comhardclose(com); 2272 ttyclose(tp); 2273 siosettimeout(); 2274 splx(s); 2275 if (com->gone) { 2276 printf("sio%d: gone\n", com->unit); 2277 s = spltty(); 2278 if (com->ibuf != NULL) 2279 free(com->ibuf, M_DEVBUF); 2280 bzero(tp, sizeof *tp); 2281 free(com, M_DEVBUF); 2282 splx(s); 2283 } 2284 return (0); 2285} 2286 2287static void 2288comhardclose(com) 2289 struct com_s *com; 2290{ 2291 Port_t iobase; 2292 int s; 2293 struct tty *tp; 2294 int unit; 2295#ifdef PC98 2296 int port_shift = 0; 2297#endif 2298 2299 unit = com->unit; 2300 iobase = com->iobase; 2301 s = spltty(); 2302 com->poll = FALSE; 2303 com->poll_output = FALSE; 2304 com->do_timestamp = FALSE; 2305 com->do_dcd_timestamp = FALSE; 2306 com->pps.ppsparam.mode = 0; 2307#ifdef PC98 2308 if (IS_8251(com->pc98_if_type)) 2309 com_send_break_off(com); 2310 else { 2311 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 2312 outb(iobase + (com_cfcr << port_shift), 2313 com->cfcr_image &= ~CFCR_SBREAK); 2314 } 2315#else 2316 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 2317#endif 2318 { 2319#ifdef PC98 2320 int tmp; 2321 if (IS_8251(com->pc98_if_type)) 2322 com_int_TxRx_disable(com); 2323 else 2324 outb(iobase + (com_ier << port_shift), 0); 2325 if (com->pc98_if_type == COM_IF_RSA98III) { 2326 outb(com->rsabase + rsa_ier, 0x00); 2327 } 2328#else 2329 outb(iobase + com_ier, 0); 2330#endif 2331 tp = com->tp; 2332#ifdef PC98 2333 if (IS_8251(com->pc98_if_type)) 2334 tmp = pc98_get_modem_status(com) & TIOCM_CAR; 2335 else 2336 tmp = com->prev_modem_status & MSR_DCD; 2337#endif 2338 if (tp->t_cflag & HUPCL 2339 /* 2340 * XXX we will miss any carrier drop between here and the 2341 * next open. Perhaps we should watch DCD even when the 2342 * port is closed; it is not sufficient to check it at 2343 * the next open because it might go up and down while 2344 * we're not watching. 2345 */ 2346 || (!com->active_out 2347#ifdef PC98 2348 && !(tmp) 2349#else 2350 && !(com->prev_modem_status & MSR_DCD) 2351#endif 2352 && !(com->it_in.c_cflag & CLOCAL)) 2353 || !(tp->t_state & TS_ISOPEN)) { 2354#ifdef PC98 2355 if (IS_8251(com->pc98_if_type)) 2356 com_tiocm_bic(com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE); 2357 else 2358#endif 2359 (void)commctl(com, TIOCM_DTR, DMBIC); 2360 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) { 2361 timeout(siodtrwakeup, com, com->dtr_wait); 2362 com->state |= CS_DTR_OFF; 2363 } 2364 } 2365#ifdef PC98 2366 else { 2367 if (IS_8251(com->pc98_if_type)) 2368 com_tiocm_bic(com, TIOCM_LE ); 2369 } 2370#endif 2371 } 2372#ifdef PC98 2373 if (com->pc98_8251fifo) { 2374 if (com->pc98_8251fifo_enable) 2375 outb(I8251F_fcr, CTRL8251F_XMT_RST | CTRL8251F_RCV_RST); 2376 com->pc98_8251fifo_enable = 0; 2377 } 2378#endif 2379 if (com->hasfifo) { 2380 /* 2381 * Disable fifos so that they are off after controlled 2382 * reboots. Some BIOSes fail to detect 16550s when the 2383 * fifos are enabled. 2384 */ 2385#ifdef PC98 2386 outb(iobase + (com_fifo << port_shift), 0); 2387#else 2388 outb(iobase + com_fifo, 0); 2389#endif 2390 } 2391 com->active_out = FALSE; 2392 wakeup(&com->active_out); 2393 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */ 2394 splx(s); 2395} 2396 2397static int 2398sioread(dev, uio, flag) 2399 dev_t dev; 2400 struct uio *uio; 2401 int flag; 2402{ 2403 int mynor; 2404 struct com_s *com; 2405 2406 mynor = minor(dev); 2407 if (mynor & CONTROL_MASK) 2408 return (ENODEV); 2409 com = com_addr(MINOR_TO_UNIT(mynor)); 2410 if (com->gone) 2411 return (ENODEV); 2412 return ((*linesw[com->tp->t_line].l_read)(com->tp, uio, flag)); 2413} 2414 2415static int 2416siowrite(dev, uio, flag) 2417 dev_t dev; 2418 struct uio *uio; 2419 int flag; 2420{ 2421 int mynor; 2422 struct com_s *com; 2423 int unit; 2424 2425 mynor = minor(dev); 2426 if (mynor & CONTROL_MASK) 2427 return (ENODEV); 2428 2429 unit = MINOR_TO_UNIT(mynor); 2430 com = com_addr(unit); 2431 if (com->gone) 2432 return (ENODEV); 2433 /* 2434 * (XXX) We disallow virtual consoles if the physical console is 2435 * a serial port. This is in case there is a display attached that 2436 * is not the console. In that situation we don't need/want the X 2437 * server taking over the console. 2438 */ 2439 if (constty != NULL && unit == comconsole) 2440 constty = NULL; 2441 return ((*linesw[com->tp->t_line].l_write)(com->tp, uio, flag)); 2442} 2443 2444static void 2445siobusycheck(chan) 2446 void *chan; 2447{ 2448 struct com_s *com; 2449 int s; 2450 2451 com = (struct com_s *)chan; 2452 2453 /* 2454 * Clear TS_BUSY if low-level output is complete. 2455 * spl locking is sufficient because siointr1() does not set CS_BUSY. 2456 * If siointr1() clears CS_BUSY after we look at it, then we'll get 2457 * called again. Reading the line status port outside of siointr1() 2458 * is safe because CS_BUSY is clear so there are no output interrupts 2459 * to lose. 2460 */ 2461 s = spltty(); 2462 if (com->state & CS_BUSY) 2463 com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */ 2464#ifdef PC98 2465 else if ((IS_8251(com->pc98_if_type) && 2466 ((com->pc98_8251fifo_enable && 2467 (inb(I8251F_lsr) & (STS8251F_TxRDY | STS8251F_TxEMP)) 2468 == (STS8251F_TxRDY | STS8251F_TxEMP)) || 2469 (!com->pc98_8251fifo_enable && 2470 (inb(com->sts_port) & (STS8251_TxRDY | STS8251_TxEMP)) 2471 == (STS8251_TxRDY | STS8251_TxEMP)))) || 2472 ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2473 == (LSR_TSRE | LSR_TXRDY))) { 2474#else 2475 else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY)) 2476 == (LSR_TSRE | LSR_TXRDY)) { 2477#endif 2478 com->tp->t_state &= ~TS_BUSY; 2479 ttwwakeup(com->tp); 2480 com->extra_state &= ~CSE_BUSYCHECK; 2481 } else 2482 timeout(siobusycheck, com, hz / 100); 2483 splx(s); 2484} 2485 2486static void 2487siodtrwakeup(chan) 2488 void *chan; 2489{ 2490 struct com_s *com; 2491 2492 com = (struct com_s *)chan; 2493 com->state &= ~CS_DTR_OFF; 2494 wakeup(&com->dtr_wait); 2495} 2496 2497static void 2498sioinput(com) 2499 struct com_s *com; 2500{ 2501 u_char *buf; 2502 int incc; 2503 u_char line_status; 2504 int recv_data; 2505 struct tty *tp; 2506 2507 buf = com->ibuf; 2508 tp = com->tp; 2509 if (!(tp->t_state & TS_ISOPEN) || !(tp->t_cflag & CREAD)) { 2510 com_events -= (com->iptr - com->ibuf); 2511 com->iptr = com->ibuf; 2512 return; 2513 } 2514 if (tp->t_state & TS_CAN_BYPASS_L_RINT) { 2515 /* 2516 * Avoid the grotesquely inefficient lineswitch routine 2517 * (ttyinput) in "raw" mode. It usually takes about 450 2518 * instructions (that's without canonical processing or echo!). 2519 * slinput is reasonably fast (usually 40 instructions plus 2520 * call overhead). 2521 */ 2522 do { 2523 enable_intr(); 2524 incc = com->iptr - buf; 2525 if (tp->t_rawq.c_cc + incc > tp->t_ihiwat 2526 && (com->state & CS_RTS_IFLOW 2527 || tp->t_iflag & IXOFF) 2528 && !(tp->t_state & TS_TBLOCK)) 2529 ttyblock(tp); 2530 com->delta_error_counts[CE_TTY_BUF_OVERFLOW] 2531 += b_to_q((char *)buf, incc, &tp->t_rawq); 2532 buf += incc; 2533 tk_nin += incc; 2534 tk_rawcc += incc; 2535 tp->t_rawcc += incc; 2536 ttwakeup(tp); 2537 if (tp->t_state & TS_TTSTOP 2538 && (tp->t_iflag & IXANY 2539 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { 2540 tp->t_state &= ~TS_TTSTOP; 2541 tp->t_lflag &= ~FLUSHO; 2542 comstart(tp); 2543 } 2544 disable_intr(); 2545 } while (buf < com->iptr); 2546 } else { 2547 do { 2548 enable_intr(); 2549 line_status = buf[com->ierroff]; 2550 recv_data = *buf++; 2551 if (line_status 2552 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) { 2553 if (line_status & LSR_BI) 2554 recv_data |= TTY_BI; 2555 if (line_status & LSR_FE) 2556 recv_data |= TTY_FE; 2557 if (line_status & LSR_OE) 2558 recv_data |= TTY_OE; 2559 if (line_status & LSR_PE) 2560 recv_data |= TTY_PE; 2561 } 2562 (*linesw[tp->t_line].l_rint)(recv_data, tp); 2563 disable_intr(); 2564 } while (buf < com->iptr); 2565 } 2566 com_events -= (com->iptr - com->ibuf); 2567 com->iptr = com->ibuf; 2568 2569 /* 2570 * There is now room for another low-level buffer full of input, 2571 * so enable RTS if it is now disabled and there is room in the 2572 * high-level buffer. 2573 */ 2574#ifdef PC98 2575 if (IS_8251(com->pc98_if_type)) { 2576 if ((com->state & CS_RTS_IFLOW) && 2577 !(com_tiocm_get(com) & TIOCM_RTS) && 2578 !(tp->t_state & TS_TBLOCK)) 2579 com_tiocm_bis(com, TIOCM_RTS); 2580 } else { 2581 if ((com->state & CS_RTS_IFLOW) && 2582 !(com->mcr_image & MCR_RTS) && 2583 !(tp->t_state & TS_TBLOCK)) 2584 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2585 } 2586#else 2587 if ((com->state & CS_RTS_IFLOW) && !(com->mcr_image & MCR_RTS) && 2588 !(tp->t_state & TS_TBLOCK)) 2589 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 2590#endif 2591} 2592 2593void 2594siointr(arg) 2595 void *arg; 2596{ 2597#ifndef COM_MULTIPORT 2598 COM_LOCK(); 2599 siointr1((struct com_s *) arg); 2600 COM_UNLOCK(); 2601#else /* COM_MULTIPORT */ 2602 bool_t possibly_more_intrs; 2603 int unit; 2604 struct com_s *com; 2605#ifdef PC98 2606 u_char rsa_buf_status; 2607#endif 2608 2609 /* 2610 * Loop until there is no activity on any port. This is necessary 2611 * to get an interrupt edge more than to avoid another interrupt. 2612 * If the IRQ signal is just an OR of the IRQ signals from several 2613 * devices, then the edge from one may be lost because another is 2614 * on. 2615 */ 2616 COM_LOCK(); 2617 do { 2618 possibly_more_intrs = FALSE; 2619 for (unit = 0; unit < sio_numunits; ++unit) { 2620 com = com_addr(unit); 2621 /* 2622 * XXX COM_LOCK(); 2623 * would it work here, or be counter-productive? 2624 */ 2625#ifdef PC98 2626 if (com != NULL 2627 && !com->gone 2628 && IS_8251(com->pc98_if_type)){ 2629 siointr1(com); 2630 } else 2631#endif /* PC98 */ 2632#ifdef PC98 2633 if (com != NULL 2634 && !com->gone 2635 && com->pc98_if_type == COM_IF_RSA98III) { 2636 rsa_buf_status = inb(com->rsabase + rsa_srr) & 0xc9; 2637 if ((rsa_buf_status & 0xc8) 2638 || !(rsa_buf_status & 0x01)) { 2639 siointr1(com); 2640 if(rsa_buf_status 2641 != (inb(com->rsabase + rsa_srr) & 0xc9)) 2642 possibly_more_intrs = TRUE; 2643 } 2644 } else 2645#endif 2646 if (com != NULL 2647 && !com->gone 2648 && (inb(com->int_id_port) & IIR_IMASK) 2649 != IIR_NOPEND) { 2650 siointr1(com); 2651 possibly_more_intrs = TRUE; 2652 } 2653 /* XXX COM_UNLOCK(); */ 2654 } 2655 } while (possibly_more_intrs); 2656 COM_UNLOCK(); 2657#endif /* COM_MULTIPORT */ 2658} 2659 2660static void 2661siointr1(com) 2662 struct com_s *com; 2663{ 2664 u_char line_status; 2665 u_char modem_status; 2666 u_char *ioptr; 2667 u_char recv_data; 2668 u_char int_ctl; 2669 u_char int_ctl_new; 2670 struct timecounter *tc; 2671 u_int count; 2672 2673#ifdef PC98 2674 u_char tmp=0; 2675 u_char rsa_buf_status = 0; 2676 int rsa_tx_fifo_size=0; 2677 recv_data=0; 2678#endif /* PC98 */ 2679 2680 int_ctl = inb(com->intr_ctl_port); 2681 int_ctl_new = int_ctl; 2682 2683 while (!com->gone) { 2684#ifdef PC98 2685status_read:; 2686 if (IS_8251(com->pc98_if_type)) { 2687 if (com->pc98_8251fifo_enable) 2688 tmp = inb(I8251F_lsr); 2689 else 2690 tmp = inb(com->sts_port); 2691more_intr: 2692 line_status = 0; 2693 if (com->pc98_8251fifo_enable) { 2694 if (tmp & STS8251F_TxRDY) line_status |= LSR_TXRDY; 2695 if (tmp & STS8251F_RxRDY) line_status |= LSR_RXRDY; 2696 if (tmp & STS8251F_TxEMP) line_status |= LSR_TSRE; 2697 if (tmp & STS8251F_PE) line_status |= LSR_PE; 2698 if (tmp & STS8251F_OE) line_status |= LSR_OE; 2699 if (tmp & STS8251F_BD_SD) line_status |= LSR_BI; 2700 } else { 2701 if (tmp & STS8251_TxRDY) line_status |= LSR_TXRDY; 2702 if (tmp & STS8251_RxRDY) line_status |= LSR_RXRDY; 2703 if (tmp & STS8251_TxEMP) line_status |= LSR_TSRE; 2704 if (tmp & STS8251_PE) line_status |= LSR_PE; 2705 if (tmp & STS8251_OE) line_status |= LSR_OE; 2706 if (tmp & STS8251_FE) line_status |= LSR_FE; 2707 if (tmp & STS8251_BD_SD) line_status |= LSR_BI; 2708 } 2709 } else { 2710#endif /* PC98 */ 2711 if (com->pps.ppsparam.mode & PPS_CAPTUREBOTH) { 2712 modem_status = inb(com->modem_status_port); 2713 if ((modem_status ^ com->last_modem_status) & MSR_DCD) { 2714 tc = timecounter; 2715 count = tc->tc_get_timecount(tc); 2716 pps_event(&com->pps, tc, count, 2717 (modem_status & MSR_DCD) ? 2718 PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); 2719 } 2720 } 2721 line_status = inb(com->line_status_port); 2722#ifdef PC98 2723 } 2724 if (com->pc98_if_type == COM_IF_RSA98III) 2725 rsa_buf_status = inb(com->rsabase + rsa_srr); 2726#endif /* PC98 */ 2727 2728 /* input event? (check first to help avoid overruns) */ 2729#ifndef PC98 2730 while (line_status & LSR_RCV_MASK) { 2731#else 2732 while ((line_status & LSR_RCV_MASK) 2733 || (com->pc98_if_type == COM_IF_RSA98III 2734 && (rsa_buf_status & 0x08))) { 2735#endif /* PC98 */ 2736 /* break/unnattached error bits or real input? */ 2737#ifdef PC98 2738 if (IS_8251(com->pc98_if_type)) { 2739 if (com->pc98_8251fifo_enable) { 2740 recv_data = inb(I8251F_data); 2741 if (tmp & (STS8251F_PE | STS8251F_OE | 2742 STS8251F_BD_SD)) { 2743 pc98_i8251_or_cmd(com, CMD8251_ER); 2744 recv_data = 0; 2745 } 2746 } else { 2747 recv_data = inb(com->data_port); 2748 if (tmp & (STS8251_PE | STS8251_OE | 2749 STS8251_FE | STS8251_BD_SD)) { 2750 pc98_i8251_or_cmd(com, CMD8251_ER); 2751 recv_data = 0; 2752 } 2753 } 2754 } else { 2755#endif /* PC98 */ 2756#ifdef PC98 2757 if (com->pc98_if_type == COM_IF_RSA98III) { 2758 if (!(rsa_buf_status & 0x08)) 2759 recv_data = 0; 2760 else 2761 recv_data = inb(com->data_port); 2762 } else 2763#endif 2764 if (!(line_status & LSR_RXRDY)) 2765 recv_data = 0; 2766 else 2767 recv_data = inb(com->data_port); 2768#ifdef PC98 2769 } 2770#endif 2771 if (line_status & (LSR_BI | LSR_FE | LSR_PE)) { 2772 /* 2773 * Don't store BI if IGNBRK or FE/PE if IGNPAR. 2774 * Otherwise, push the work to a higher level 2775 * (to handle PARMRK) if we're bypassing. 2776 * Otherwise, convert BI/FE and PE+INPCK to 0. 2777 * 2778 * This makes bypassing work right in the 2779 * usual "raw" case (IGNBRK set, and IGNPAR 2780 * and INPCK clear). 2781 * 2782 * Note: BI together with FE/PE means just BI. 2783 */ 2784 if (line_status & LSR_BI) { 2785#if defined(DDB) && defined(BREAK_TO_DEBUGGER) 2786 if (com->unit == comconsole) { 2787 breakpoint(); 2788 goto cont; 2789 } 2790#endif 2791 if (com->tp == NULL 2792 || com->tp->t_iflag & IGNBRK) 2793 goto cont; 2794 } else { 2795 if (com->tp == NULL 2796 || com->tp->t_iflag & IGNPAR) 2797 goto cont; 2798 } 2799 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT 2800 && (line_status & (LSR_BI | LSR_FE) 2801 || com->tp->t_iflag & INPCK)) 2802 recv_data = 0; 2803 } 2804 ++com->bytes_in; 2805 if (com->hotchar != 0 && recv_data == com->hotchar) 2806 setsofttty(); 2807 ioptr = com->iptr; 2808 if (ioptr >= com->ibufend) 2809 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW); 2810 else { 2811 if (com->do_timestamp) 2812 microtime(&com->timestamp); 2813 ++com_events; 2814 schedsofttty(); 2815#if 0 /* for testing input latency vs efficiency */ 2816if (com->iptr - com->ibuf == 8) 2817 setsofttty(); 2818#endif 2819 ioptr[0] = recv_data; 2820 ioptr[com->ierroff] = line_status; 2821 com->iptr = ++ioptr; 2822 if (ioptr == com->ihighwater 2823 && com->state & CS_RTS_IFLOW) 2824#ifdef PC98 2825 IS_8251(com->pc98_if_type) ? 2826 com_tiocm_bic(com, TIOCM_RTS) : 2827#endif 2828 outb(com->modem_ctl_port, 2829 com->mcr_image &= ~MCR_RTS); 2830 if (line_status & LSR_OE) 2831 CE_RECORD(com, CE_OVERRUN); 2832 } 2833cont: 2834 /* 2835 * "& 0x7F" is to avoid the gcc-1.40 generating a slow 2836 * jump from the top of the loop to here 2837 */ 2838#ifdef PC98 2839 if (IS_8251(com->pc98_if_type)) 2840 goto status_read; 2841 else 2842#endif 2843 line_status = inb(com->line_status_port) & 0x7F; 2844#ifdef PC98 2845 if (com->pc98_if_type == COM_IF_RSA98III) 2846 rsa_buf_status = inb(com->rsabase + rsa_srr); 2847#endif /* PC98 */ 2848 } 2849 2850 /* modem status change? (always check before doing output) */ 2851#ifdef PC98 2852 if (!IS_8251(com->pc98_if_type)) { 2853#endif 2854 modem_status = inb(com->modem_status_port); 2855 if (modem_status != com->last_modem_status) { 2856 if (com->do_dcd_timestamp 2857 && !(com->last_modem_status & MSR_DCD) 2858 && modem_status & MSR_DCD) 2859 microtime(&com->dcd_timestamp); 2860 2861 /* 2862 * Schedule high level to handle DCD changes. Note 2863 * that we don't use the delta bits anywhere. Some 2864 * UARTs mess them up, and it's easy to remember the 2865 * previous bits and calculate the delta. 2866 */ 2867 com->last_modem_status = modem_status; 2868 if (!(com->state & CS_CHECKMSR)) { 2869 com_events += LOTS_OF_EVENTS; 2870 com->state |= CS_CHECKMSR; 2871 setsofttty(); 2872 } 2873 2874 /* handle CTS change immediately for crisp flow ctl */ 2875 if (com->state & CS_CTS_OFLOW) { 2876 if (modem_status & MSR_CTS) 2877 com->state |= CS_ODEVREADY; 2878 else 2879 com->state &= ~CS_ODEVREADY; 2880 } 2881 } 2882#ifdef PC98 2883 } 2884#endif 2885 2886 /* output queued and everything ready? */ 2887#ifndef PC98 2888 if (line_status & LSR_TXRDY 2889 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2890#else 2891 if (((com->pc98_if_type == COM_IF_RSA98III) 2892 ? (rsa_buf_status & 0x02) 2893 : (line_status & LSR_TXRDY)) 2894 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) { 2895#endif 2896#ifdef PC98 2897 Port_t tmp_data_port; 2898 2899 if (IS_8251(com->pc98_if_type) && 2900 com->pc98_8251fifo_enable) 2901 tmp_data_port = I8251F_data; 2902 else 2903 tmp_data_port = com->data_port; 2904#endif 2905 2906 ioptr = com->obufq.l_head; 2907 if (com->tx_fifo_size > 1) { 2908 u_int ocount; 2909 2910 ocount = com->obufq.l_tail - ioptr; 2911#ifdef PC98 2912 if (com->pc98_if_type == COM_IF_RSA98III) { 2913 rsa_buf_status = inb(com->rsabase + rsa_srr); 2914 rsa_tx_fifo_size = 1024; 2915 if (!(rsa_buf_status & 0x01)) 2916 rsa_tx_fifo_size = 2048; 2917 if (ocount > rsa_tx_fifo_size) 2918 ocount = rsa_tx_fifo_size; 2919 } else 2920#endif 2921 if (ocount > com->tx_fifo_size) 2922 ocount = com->tx_fifo_size; 2923 com->bytes_out += ocount; 2924 do 2925#ifdef PC98 2926 outb(tmp_data_port, *ioptr++); 2927#else 2928 outb(com->data_port, *ioptr++); 2929#endif 2930 while (--ocount != 0); 2931 } else { 2932#ifdef PC98 2933 outb(tmp_data_port, *ioptr++); 2934#else 2935 outb(com->data_port, *ioptr++); 2936#endif 2937 ++com->bytes_out; 2938 } 2939#ifdef PC98 2940 if (IS_8251(com->pc98_if_type)) 2941 if (!(pc98_check_i8251_interrupt(com) & IEN_TxFLAG)) 2942 com_int_Tx_enable(com); 2943#endif 2944 com->obufq.l_head = ioptr; 2945 if (COM_IIR_TXRDYBUG(com->flags)) { 2946 int_ctl_new = int_ctl | IER_ETXRDY; 2947 } 2948 if (ioptr >= com->obufq.l_tail) { 2949 struct lbq *qp; 2950 2951 qp = com->obufq.l_next; 2952 qp->l_queued = FALSE; 2953 qp = qp->l_next; 2954 if (qp != NULL) { 2955 com->obufq.l_head = qp->l_head; 2956 com->obufq.l_tail = qp->l_tail; 2957 com->obufq.l_next = qp; 2958 } else { 2959 /* output just completed */ 2960 if (COM_IIR_TXRDYBUG(com->flags)) { 2961 int_ctl_new = int_ctl & ~IER_ETXRDY; 2962 } 2963 com->state &= ~CS_BUSY; 2964#if defined(PC98) 2965 if (IS_8251(com->pc98_if_type)) 2966 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2967 com_int_Tx_disable(com); 2968#endif 2969 } 2970 if (!(com->state & CS_ODONE)) { 2971 com_events += LOTS_OF_EVENTS; 2972 com->state |= CS_ODONE; 2973 setsofttty(); /* handle at high level ASAP */ 2974 } 2975 } 2976 if (COM_IIR_TXRDYBUG(com->flags) && (int_ctl != int_ctl_new)) { 2977#ifdef PC98 2978 if (com->pc98_if_type == COM_IF_RSA98III) { 2979 int_ctl_new &= ~(IER_ETXRDY | IER_ERXRDY); 2980 outb(com->intr_ctl_port, int_ctl_new); 2981 outb(com->rsabase + rsa_ier, 0x1d); 2982 } else 2983#endif 2984 outb(com->intr_ctl_port, int_ctl_new); 2985 } 2986 } 2987#ifdef PC98 2988 else if (line_status & LSR_TXRDY) { 2989 if (IS_8251(com->pc98_if_type)) 2990 if ( pc98_check_i8251_interrupt(com) & IEN_TxFLAG ) 2991 com_int_Tx_disable(com); 2992 } 2993 if (IS_8251(com->pc98_if_type)) { 2994 if (com->pc98_8251fifo_enable) { 2995 if ((tmp = inb(I8251F_lsr)) & STS8251F_RxRDY) 2996 goto more_intr; 2997 } else { 2998 if ((tmp = inb(com->sts_port)) & STS8251_RxRDY) 2999 goto more_intr; 3000 } 3001 } 3002#endif 3003 3004 /* finished? */ 3005#ifndef COM_MULTIPORT 3006#ifdef PC98 3007 if (IS_8251(com->pc98_if_type)) 3008 return; 3009#endif 3010 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND) 3011#endif /* COM_MULTIPORT */ 3012 return; 3013 } 3014} 3015 3016static int 3017sioioctl(dev, cmd, data, flag, p) 3018 dev_t dev; 3019 u_long cmd; 3020 caddr_t data; 3021 int flag; 3022 struct proc *p; 3023{ 3024 struct com_s *com; 3025 int error; 3026 Port_t iobase; 3027 int mynor; 3028 int s; 3029 struct tty *tp; 3030#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 3031 u_long oldcmd; 3032 struct termios term; 3033#endif 3034 3035 mynor = minor(dev); 3036 com = com_addr(MINOR_TO_UNIT(mynor)); 3037 if (com->gone) 3038 return (ENODEV); 3039 iobase = com->iobase; 3040 if (mynor & CONTROL_MASK) { 3041 struct termios *ct; 3042 3043 switch (mynor & CONTROL_MASK) { 3044 case CONTROL_INIT_STATE: 3045 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in; 3046 break; 3047 case CONTROL_LOCK_STATE: 3048 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in; 3049 break; 3050 default: 3051 return (ENODEV); /* /dev/nodev */ 3052 } 3053 switch (cmd) { 3054 case TIOCSETA: 3055 error = suser(p); 3056 if (error != 0) 3057 return (error); 3058 *ct = *(struct termios *)data; 3059 return (0); 3060 case TIOCGETA: 3061 *(struct termios *)data = *ct; 3062 return (0); 3063 case TIOCGETD: 3064 *(int *)data = TTYDISC; 3065 return (0); 3066 case TIOCGWINSZ: 3067 bzero(data, sizeof(struct winsize)); 3068 return (0); 3069 default: 3070 return (ENOTTY); 3071 } 3072 } 3073 tp = com->tp; 3074#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 3075 term = tp->t_termios; 3076 oldcmd = cmd; 3077 error = ttsetcompat(tp, &cmd, data, &term); 3078 if (error != 0) 3079 return (error); 3080 if (cmd != oldcmd) 3081 data = (caddr_t)&term; 3082#endif 3083 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) { 3084 int cc; 3085 struct termios *dt = (struct termios *)data; 3086 struct termios *lt = mynor & CALLOUT_MASK 3087 ? &com->lt_out : &com->lt_in; 3088 3089 dt->c_iflag = (tp->t_iflag & lt->c_iflag) 3090 | (dt->c_iflag & ~lt->c_iflag); 3091 dt->c_oflag = (tp->t_oflag & lt->c_oflag) 3092 | (dt->c_oflag & ~lt->c_oflag); 3093 dt->c_cflag = (tp->t_cflag & lt->c_cflag) 3094 | (dt->c_cflag & ~lt->c_cflag); 3095 dt->c_lflag = (tp->t_lflag & lt->c_lflag) 3096 | (dt->c_lflag & ~lt->c_lflag); 3097 for (cc = 0; cc < NCCS; ++cc) 3098 if (lt->c_cc[cc] != 0) 3099 dt->c_cc[cc] = tp->t_cc[cc]; 3100 if (lt->c_ispeed != 0) 3101 dt->c_ispeed = tp->t_ispeed; 3102 if (lt->c_ospeed != 0) 3103 dt->c_ospeed = tp->t_ospeed; 3104 } 3105 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 3106 if (error != ENOIOCTL) 3107 return (error); 3108 s = spltty(); 3109 error = ttioctl(tp, cmd, data, flag); 3110 disc_optim(tp, &tp->t_termios, com); 3111 if (error != ENOIOCTL) { 3112 splx(s); 3113 return (error); 3114 } 3115#ifdef PC98 3116 if (IS_8251(com->pc98_if_type)) { 3117 switch (cmd) { 3118 case TIOCSBRK: 3119 com_send_break_on( com ); 3120 break; 3121 case TIOCCBRK: 3122 com_send_break_off( com ); 3123 break; 3124 case TIOCSDTR: 3125 com_tiocm_bis(com, TIOCM_DTR | TIOCM_RTS ); 3126 break; 3127 case TIOCCDTR: 3128 com_tiocm_bic(com, TIOCM_DTR); 3129 break; 3130 /* 3131 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 3132 * changes get undone on the next call to comparam(). 3133 */ 3134 case TIOCMSET: 3135 com_tiocm_set( com, *(int *)data ); 3136 break; 3137 case TIOCMBIS: 3138 com_tiocm_bis( com, *(int *)data ); 3139 break; 3140 case TIOCMBIC: 3141 com_tiocm_bic( com, *(int *)data ); 3142 break; 3143 case TIOCMGET: 3144 *(int *)data = com_tiocm_get(com); 3145 break; 3146 case TIOCMSDTRWAIT: 3147 /* must be root since the wait applies to following logins */ 3148 error = suser(p); 3149 if (error != 0) { 3150 splx(s); 3151 return (error); 3152 } 3153 com->dtr_wait = *(int *)data * hz / 100; 3154 break; 3155 case TIOCMGDTRWAIT: 3156 *(int *)data = com->dtr_wait * 100 / hz; 3157 break; 3158 case TIOCTIMESTAMP: 3159 com->do_timestamp = TRUE; 3160 *(struct timeval *)data = com->timestamp; 3161 break; 3162 case TIOCDCDTIMESTAMP: 3163 com->do_dcd_timestamp = TRUE; 3164 *(struct timeval *)data = com->dcd_timestamp; 3165 break; 3166 default: 3167 splx(s); 3168 return (ENOTTY); 3169 } 3170 } else { 3171 int port_shift; 3172 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 3173#endif 3174 switch (cmd) { 3175 case TIOCSBRK: 3176#ifdef PC98 3177 outb(iobase + (com_cfcr << port_shift), 3178 com->cfcr_image |= CFCR_SBREAK); 3179#else 3180 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK); 3181#endif 3182 break; 3183 case TIOCCBRK: 3184#ifdef PC98 3185 outb(iobase + (com_cfcr << port_shift), 3186 com->cfcr_image &= ~CFCR_SBREAK); 3187#else 3188 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK); 3189#endif 3190 break; 3191 case TIOCSDTR: 3192 (void)commctl(com, TIOCM_DTR, DMBIS); 3193 break; 3194 case TIOCCDTR: 3195 (void)commctl(com, TIOCM_DTR, DMBIC); 3196 break; 3197 /* 3198 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The 3199 * changes get undone on the next call to comparam(). 3200 */ 3201 case TIOCMSET: 3202 (void)commctl(com, *(int *)data, DMSET); 3203 break; 3204 case TIOCMBIS: 3205 (void)commctl(com, *(int *)data, DMBIS); 3206 break; 3207 case TIOCMBIC: 3208 (void)commctl(com, *(int *)data, DMBIC); 3209 break; 3210 case TIOCMGET: 3211 *(int *)data = commctl(com, 0, DMGET); 3212 break; 3213 case TIOCMSDTRWAIT: 3214 /* must be root since the wait applies to following logins */ 3215 error = suser(p); 3216 if (error != 0) { 3217 splx(s); 3218 return (error); 3219 } 3220 com->dtr_wait = *(int *)data * hz / 100; 3221 break; 3222 case TIOCMGDTRWAIT: 3223 *(int *)data = com->dtr_wait * 100 / hz; 3224 break; 3225 case TIOCTIMESTAMP: 3226 com->do_timestamp = TRUE; 3227 *(struct timeval *)data = com->timestamp; 3228 break; 3229 case TIOCDCDTIMESTAMP: 3230 com->do_dcd_timestamp = TRUE; 3231 *(struct timeval *)data = com->dcd_timestamp; 3232 break; 3233 default: 3234 splx(s); 3235 error = pps_ioctl(cmd, data, &com->pps); 3236 if (error == ENODEV) 3237 error = ENOTTY; 3238 return (error); 3239 } 3240#ifdef PC98 3241 } 3242#endif 3243 splx(s); 3244 return (0); 3245} 3246 3247static void 3248siopoll() 3249{ 3250 int unit; 3251 3252 if (com_events == 0) 3253 return; 3254repeat: 3255 for (unit = 0; unit < sio_numunits; ++unit) { 3256 struct com_s *com; 3257 int incc; 3258 struct tty *tp; 3259 3260 com = com_addr(unit); 3261 if (com == NULL) 3262 continue; 3263 tp = com->tp; 3264 if (tp == NULL || com->gone) { 3265 /* 3266 * Discard any events related to never-opened or 3267 * going-away devices. 3268 */ 3269 disable_intr(); 3270 incc = com->iptr - com->ibuf; 3271 com->iptr = com->ibuf; 3272 if (com->state & CS_CHECKMSR) { 3273 incc += LOTS_OF_EVENTS; 3274 com->state &= ~CS_CHECKMSR; 3275 } 3276 com_events -= incc; 3277 enable_intr(); 3278 continue; 3279 } 3280 if (com->iptr != com->ibuf) { 3281 disable_intr(); 3282 sioinput(com); 3283 enable_intr(); 3284 } 3285 if (com->state & CS_CHECKMSR) { 3286 u_char delta_modem_status; 3287 3288#ifdef PC98 3289 if (!IS_8251(com->pc98_if_type)) { 3290#endif 3291 disable_intr(); 3292 delta_modem_status = com->last_modem_status 3293 ^ com->prev_modem_status; 3294 com->prev_modem_status = com->last_modem_status; 3295 com_events -= LOTS_OF_EVENTS; 3296 com->state &= ~CS_CHECKMSR; 3297 enable_intr(); 3298 if (delta_modem_status & MSR_DCD) 3299 (*linesw[tp->t_line].l_modem) 3300 (tp, com->prev_modem_status & MSR_DCD); 3301#ifdef PC98 3302 } 3303#endif 3304 } 3305 if (com->state & CS_ODONE) { 3306 disable_intr(); 3307 com_events -= LOTS_OF_EVENTS; 3308 com->state &= ~CS_ODONE; 3309 enable_intr(); 3310 if (!(com->state & CS_BUSY) 3311 && !(com->extra_state & CSE_BUSYCHECK)) { 3312 timeout(siobusycheck, com, hz / 100); 3313 com->extra_state |= CSE_BUSYCHECK; 3314 } 3315 (*linesw[tp->t_line].l_start)(tp); 3316 } 3317 if (com_events == 0) 3318 break; 3319 } 3320 if (com_events >= LOTS_OF_EVENTS) 3321 goto repeat; 3322} 3323 3324static int 3325comparam(tp, t) 3326 struct tty *tp; 3327 struct termios *t; 3328{ 3329 u_int cfcr; 3330 int cflag; 3331 struct com_s *com; 3332 int divisor; 3333 u_char dlbh; 3334 u_char dlbl; 3335 Port_t iobase; 3336 int s; 3337 int unit; 3338#ifdef PC98 3339 int port_shift = 0; 3340 u_char param = 0; 3341#endif 3342 3343#ifdef PC98 3344 cfcr = 0; 3345 unit = DEV_TO_UNIT(tp->t_dev); 3346 com = com_addr(unit); 3347 iobase = com->iobase; 3348 if (IS_8251(com->pc98_if_type)) { 3349 divisor = pc98_ttspeedtab(com, t->c_ospeed); 3350 } else { 3351 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 3352 3353 /* do historical conversions */ 3354 if (t->c_ispeed == 0) 3355 t->c_ispeed = t->c_ospeed; 3356 3357 /* check requested parameters */ 3358 divisor = ttspeedtab(t->c_ospeed, 3359 if_16550a_type[com->pc98_if_type & 0x0f].speedtab); 3360 } 3361#else 3362 /* do historical conversions */ 3363 if (t->c_ispeed == 0) 3364 t->c_ispeed = t->c_ospeed; 3365 3366 /* check requested parameters */ 3367 divisor = ttspeedtab(t->c_ospeed, comspeedtab); 3368#endif 3369 if (divisor < 0 || (divisor > 0 && t->c_ispeed != t->c_ospeed)) 3370 return (EINVAL); 3371 3372 /* parameters are OK, convert them to the com struct and the device */ 3373#ifndef PC98 3374 unit = DEV_TO_UNIT(tp->t_dev); 3375 com = com_addr(unit); 3376 iobase = com->iobase; 3377#endif 3378 s = spltty(); 3379#ifdef PC98 3380 if (IS_8251(com->pc98_if_type)) { 3381 if (divisor == 0) 3382 com_tiocm_bic( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 3383 else 3384 com_tiocm_bis( com, TIOCM_DTR|TIOCM_RTS|TIOCM_LE ); 3385 } else { 3386#endif 3387 if (divisor == 0) 3388 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */ 3389 else 3390 (void)commctl(com, TIOCM_DTR, DMBIS); 3391#ifdef PC98 3392 } 3393#endif 3394 cflag = t->c_cflag; 3395#ifdef PC98 3396 if (!IS_8251(com->pc98_if_type)) { 3397#endif 3398 switch (cflag & CSIZE) { 3399 case CS5: 3400 cfcr = CFCR_5BITS; 3401 break; 3402 case CS6: 3403 cfcr = CFCR_6BITS; 3404 break; 3405 case CS7: 3406 cfcr = CFCR_7BITS; 3407 break; 3408 default: 3409 cfcr = CFCR_8BITS; 3410 break; 3411 } 3412 if (cflag & PARENB) { 3413 cfcr |= CFCR_PENAB; 3414 if (!(cflag & PARODD)) 3415 cfcr |= CFCR_PEVEN; 3416 } 3417 if (cflag & CSTOPB) 3418 cfcr |= CFCR_STOPB; 3419 3420 if (com->hasfifo && divisor != 0) { 3421 /* 3422 * Use a fifo trigger level low enough so that the input 3423 * latency from the fifo is less than about 16 msec and 3424 * the total latency is less than about 30 msec. These 3425 * latencies are reasonable for humans. Serial comms 3426 * protocols shouldn't expect anything better since modem 3427 * latencies are larger. 3428 */ 3429 com->fifo_image = t->c_ospeed <= 4800 3430 ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH; 3431#ifdef COM_ESP 3432 /* 3433 * The Hayes ESP card needs the fifo DMA mode bit set 3434 * in compatibility mode. If not, it will interrupt 3435 * for each character received. 3436 */ 3437 if (com->esp) 3438 com->fifo_image |= FIFO_DMA_MODE; 3439#endif 3440#ifdef PC98 3441 outb(iobase + (com_fifo << port_shift), com->fifo_image); 3442#else 3443 outb(iobase + com_fifo, com->fifo_image); 3444#endif 3445 } 3446#ifdef PC98 3447 } 3448#endif 3449 3450 /* 3451 * This returns with interrupts disabled so that we can complete 3452 * the speed change atomically. Keeping interrupts disabled is 3453 * especially important while com_data is hidden. 3454 */ 3455 (void) siosetwater(com, t->c_ispeed); 3456 3457#ifdef PC98 3458 if (IS_8251(com->pc98_if_type)) 3459 com_cflag_and_speed_set(com, cflag, t->c_ospeed); 3460 else { 3461#endif 3462 if (divisor != 0) { 3463#ifdef PC98 3464 outb(iobase + (com_cfcr << port_shift), cfcr | CFCR_DLAB); 3465#else 3466 outb(iobase + com_cfcr, cfcr | CFCR_DLAB); 3467#endif 3468 /* 3469 * Only set the divisor registers if they would change, 3470 * since on some 16550 incompatibles (UMC8669F), setting 3471 * them while input is arriving them loses sync until 3472 * data stops arriving. 3473 */ 3474 dlbl = divisor & 0xFF; 3475#ifdef PC98 3476 if (inb(iobase + (com_dlbl << port_shift)) != dlbl) 3477 outb(iobase + (com_dlbl << port_shift), dlbl); 3478 dlbh = (u_int) divisor >> 8; 3479 if (inb(iobase + (com_dlbh << port_shift)) != dlbh) 3480 outb(iobase + (com_dlbh << port_shift), dlbh); 3481#else 3482 if (inb(iobase + com_dlbl) != dlbl) 3483 outb(iobase + com_dlbl, dlbl); 3484 dlbh = (u_int) divisor >> 8; 3485 if (inb(iobase + com_dlbh) != dlbh) 3486 outb(iobase + com_dlbh, dlbh); 3487#endif 3488 } 3489 3490 3491#ifdef PC98 3492 } 3493 outb(iobase + (com_cfcr << port_shift), com->cfcr_image = cfcr); 3494#else 3495 outb(iobase + com_cfcr, com->cfcr_image = cfcr); 3496#endif 3497 3498 if (!(tp->t_state & TS_TTSTOP)) 3499 com->state |= CS_TTGO; 3500 3501 if (cflag & CRTS_IFLOW) { 3502 if (com->st16650a) { 3503 outb(iobase + com_cfcr, 0xbf); 3504 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x40); 3505 } 3506 com->state |= CS_RTS_IFLOW; 3507 /* 3508 * If CS_RTS_IFLOW just changed from off to on, the change 3509 * needs to be propagated to MCR_RTS. This isn't urgent, 3510 * so do it later by calling comstart() instead of repeating 3511 * a lot of code from comstart() here. 3512 */ 3513 } else if (com->state & CS_RTS_IFLOW) { 3514 com->state &= ~CS_RTS_IFLOW; 3515 /* 3516 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS 3517 * on here, since comstart() won't do it later. 3518 */ 3519#ifdef PC98 3520 if (IS_8251(com->pc98_if_type)) 3521 com_tiocm_bis(com, TIOCM_RTS); 3522 else 3523#endif 3524 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 3525 if (com->st16650a) { 3526 outb(iobase + com_cfcr, 0xbf); 3527 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x40); 3528 } 3529 } 3530 3531 3532 /* 3533 * Set up state to handle output flow control. 3534 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level? 3535 * Now has 10+ msec latency, while CTS flow has 50- usec latency. 3536 */ 3537 com->state |= CS_ODEVREADY; 3538 com->state &= ~CS_CTS_OFLOW; 3539#ifdef PC98 3540 if (com->pc98_if_type == COM_IF_RSA98III) { 3541 param = inb(com->rsabase + rsa_msr); 3542 outb(com->rsabase + rsa_msr, param & 0x14); 3543 } 3544#endif 3545 if (cflag & CCTS_OFLOW) { 3546 com->state |= CS_CTS_OFLOW; 3547#ifdef PC98 3548 if (IS_8251(com->pc98_if_type)) { 3549 if (!(pc98_get_modem_status(com) & TIOCM_CTS)) 3550 com->state &= ~CS_ODEVREADY; 3551 } else { 3552#endif 3553#ifdef PC98 3554 if (com->pc98_if_type == COM_IF_RSA98III) { 3555 /* Set automatic flow control mode */ 3556 outb(com->rsabase + rsa_msr, param | 0x08); 3557 } else 3558#endif 3559 if (!(com->last_modem_status & MSR_CTS)) 3560 com->state &= ~CS_ODEVREADY; 3561 if (com->st16650a) { 3562 outb(iobase + com_cfcr, 0xbf); 3563 outb(iobase + com_fifo, inb(iobase + com_fifo) | 0x80); 3564 } 3565#ifdef PC98 3566 } 3567#endif 3568 } else { 3569 if (com->st16650a) { 3570 outb(iobase + com_cfcr, 0xbf); 3571 outb(iobase + com_fifo, inb(iobase + com_fifo) & ~0x80); 3572 } 3573 } 3574 3575 3576#ifdef PC98 3577 outb(iobase + (com_cfcr << port_shift), com->cfcr_image); 3578#else 3579 outb(iobase + com_cfcr, com->cfcr_image); 3580#endif 3581 3582 3583 /* XXX shouldn't call functions while intrs are disabled. */ 3584 disc_optim(tp, t, com); 3585 /* 3586 * Recover from fiddling with CS_TTGO. We used to call siointr1() 3587 * unconditionally, but that defeated the careful discarding of 3588 * stale input in sioopen(). 3589 */ 3590 if (com->state >= (CS_BUSY | CS_TTGO)) 3591 siointr1(com); 3592 3593 enable_intr(); 3594 splx(s); 3595 comstart(tp); 3596 if (com->ibufold != NULL) { 3597 free(com->ibufold, M_DEVBUF); 3598 com->ibufold = NULL; 3599 } 3600 return (0); 3601} 3602 3603static int 3604siosetwater(com, speed) 3605 struct com_s *com; 3606 speed_t speed; 3607{ 3608 int cp4ticks; 3609 u_char *ibuf; 3610 int ibufsize; 3611 struct tty *tp; 3612 3613 /* 3614 * Make the buffer size large enough to handle a softtty interrupt 3615 * latency of about 2 ticks without loss of throughput or data 3616 * (about 3 ticks if input flow control is not used or not honoured, 3617 * but a bit less for CS5-CS7 modes). 3618 */ 3619 cp4ticks = speed / 10 / hz * 4; 3620 for (ibufsize = 128; ibufsize < cp4ticks;) 3621 ibufsize <<= 1; 3622#ifdef PC98 3623 if (com->pc98_if_type == COM_IF_RSA98III) 3624 ibufsize = 2048; 3625#endif 3626 if (ibufsize == com->ibufsize) { 3627 disable_intr(); 3628 return (0); 3629 } 3630 3631 /* 3632 * Allocate input buffer. The extra factor of 2 in the size is 3633 * to allow for an error byte for each input byte. 3634 */ 3635 ibuf = malloc(2 * ibufsize, M_DEVBUF, M_NOWAIT); 3636 if (ibuf == NULL) { 3637 disable_intr(); 3638 return (ENOMEM); 3639 } 3640 3641 /* Initialize non-critical variables. */ 3642 com->ibufold = com->ibuf; 3643 com->ibufsize = ibufsize; 3644 tp = com->tp; 3645 if (tp != NULL) { 3646 tp->t_ififosize = 2 * ibufsize; 3647 tp->t_ispeedwat = (speed_t)-1; 3648 tp->t_ospeedwat = (speed_t)-1; 3649 } 3650 3651 /* 3652 * Read current input buffer, if any. Continue with interrupts 3653 * disabled. 3654 */ 3655 disable_intr(); 3656 if (com->iptr != com->ibuf) 3657 sioinput(com); 3658 3659 /*- 3660 * Initialize critical variables, including input buffer watermarks. 3661 * The external device is asked to stop sending when the buffer 3662 * exactly reaches high water, or when the high level requests it. 3663 * The high level is notified immediately (rather than at a later 3664 * clock tick) when this watermark is reached. 3665 * The buffer size is chosen so the watermark should almost never 3666 * be reached. 3667 * The low watermark is invisibly 0 since the buffer is always 3668 * emptied all at once. 3669 */ 3670 com->iptr = com->ibuf = ibuf; 3671 com->ibufend = ibuf + ibufsize; 3672 com->ierroff = ibufsize; 3673 com->ihighwater = ibuf + 3 * ibufsize / 4; 3674 return (0); 3675} 3676 3677static void 3678comstart(tp) 3679 struct tty *tp; 3680{ 3681 struct com_s *com; 3682 int s; 3683 int unit; 3684 3685 unit = DEV_TO_UNIT(tp->t_dev); 3686 com = com_addr(unit); 3687 s = spltty(); 3688 disable_intr(); 3689 if (tp->t_state & TS_TTSTOP) 3690 com->state &= ~CS_TTGO; 3691 else 3692 com->state |= CS_TTGO; 3693 if (tp->t_state & TS_TBLOCK) { 3694#ifdef PC98 3695 if (IS_8251(com->pc98_if_type)) { 3696 if ((com_tiocm_get(com) & TIOCM_RTS) && 3697 (com->state & CS_RTS_IFLOW)) 3698 com_tiocm_bic(com, TIOCM_RTS); 3699 } else { 3700 if ((com->mcr_image & MCR_RTS) && 3701 (com->state & CS_RTS_IFLOW)) 3702 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 3703 } 3704#else 3705 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW) 3706 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS); 3707#endif 3708 } else { 3709#ifdef PC98 3710 if (IS_8251(com->pc98_if_type)) { 3711 if (!(com_tiocm_get(com) & TIOCM_RTS) && 3712 com->iptr < com->ihighwater && 3713 com->state & CS_RTS_IFLOW) 3714 com_tiocm_bis(com, TIOCM_RTS); 3715 } else { 3716 if (!(com->mcr_image & MCR_RTS) && 3717 com->iptr < com->ihighwater && 3718 com->state & CS_RTS_IFLOW) 3719 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 3720 } 3721#else 3722 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater 3723 && com->state & CS_RTS_IFLOW) 3724 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS); 3725#endif 3726 } 3727 enable_intr(); 3728 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 3729 ttwwakeup(tp); 3730#ifdef PC98 3731/* if(IS_8251(com->pc98_if_type)) 3732 com_int_Tx_enable(com); */ 3733#endif 3734 splx(s); 3735 return; 3736 } 3737 if (tp->t_outq.c_cc != 0) { 3738 struct lbq *qp; 3739 struct lbq *next; 3740 3741 if (!com->obufs[0].l_queued) { 3742 com->obufs[0].l_tail 3743 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1, 3744#ifndef PC98 3745 sizeof com->obuf1); 3746#else 3747 com->obufsize); 3748#endif 3749 com->obufs[0].l_next = NULL; 3750 com->obufs[0].l_queued = TRUE; 3751 disable_intr(); 3752 if (com->state & CS_BUSY) { 3753 qp = com->obufq.l_next; 3754 while ((next = qp->l_next) != NULL) 3755 qp = next; 3756 qp->l_next = &com->obufs[0]; 3757 } else { 3758 com->obufq.l_head = com->obufs[0].l_head; 3759 com->obufq.l_tail = com->obufs[0].l_tail; 3760 com->obufq.l_next = &com->obufs[0]; 3761 com->state |= CS_BUSY; 3762 } 3763 enable_intr(); 3764 } 3765 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) { 3766 com->obufs[1].l_tail 3767 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2, 3768#ifndef PC98 3769 sizeof com->obuf2); 3770#else 3771 com->obufsize); 3772#endif 3773 com->obufs[1].l_next = NULL; 3774 com->obufs[1].l_queued = TRUE; 3775 disable_intr(); 3776 if (com->state & CS_BUSY) { 3777 qp = com->obufq.l_next; 3778 while ((next = qp->l_next) != NULL) 3779 qp = next; 3780 qp->l_next = &com->obufs[1]; 3781 } else { 3782 com->obufq.l_head = com->obufs[1].l_head; 3783 com->obufq.l_tail = com->obufs[1].l_tail; 3784 com->obufq.l_next = &com->obufs[1]; 3785 com->state |= CS_BUSY; 3786 } 3787 enable_intr(); 3788 } 3789 tp->t_state |= TS_BUSY; 3790 } 3791 disable_intr(); 3792 if (com->state >= (CS_BUSY | CS_TTGO)) 3793 siointr1(com); /* fake interrupt to start output */ 3794 enable_intr(); 3795#ifdef PC98 3796/* if(IS_8251(com->pc98_if_type)) 3797 com_int_Tx_enable(com); */ 3798#endif 3799 ttwwakeup(tp); 3800 splx(s); 3801} 3802 3803static void 3804comstop(tp, rw) 3805 struct tty *tp; 3806 int rw; 3807{ 3808 struct com_s *com; 3809#ifdef PC98 3810 int port_shift = 0; 3811 int rsa98_tmp = 0; 3812#endif 3813 3814 com = com_addr(DEV_TO_UNIT(tp->t_dev)); 3815 if (com->gone) 3816 return; 3817#ifdef PC98 3818 if (!IS_8251(com->pc98_if_type)) 3819 port_shift = if_16550a_type[com->pc98_if_type & 0x0f].port_shift; 3820#endif 3821 disable_intr(); 3822 if (rw & FWRITE) { 3823 if (com->hasfifo) 3824#ifdef COM_ESP 3825 /* XXX avoid h/w bug. */ 3826 if (!com->esp) 3827#endif 3828#ifdef PC98 3829 outb(com->iobase + (com_fifo << port_shift), 3830 FIFO_XMT_RST | com->fifo_image); 3831 if (com->pc98_if_type == COM_IF_RSA98III) 3832 for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++) 3833 outb(com->iobase + (com_fifo << port_shift), 3834 FIFO_XMT_RST | com->fifo_image); 3835#else 3836 outb(com->iobase + com_fifo, 3837 FIFO_XMT_RST | com->fifo_image); 3838#endif 3839 com->obufs[0].l_queued = FALSE; 3840 com->obufs[1].l_queued = FALSE; 3841 if (com->state & CS_ODONE) 3842 com_events -= LOTS_OF_EVENTS; 3843 com->state &= ~(CS_ODONE | CS_BUSY); 3844 com->tp->t_state &= ~TS_BUSY; 3845 } 3846 if (rw & FREAD) { 3847 if (com->hasfifo) 3848#ifdef COM_ESP 3849 /* XXX avoid h/w bug. */ 3850 if (!com->esp) 3851#endif 3852#ifdef PC98 3853 if (com->pc98_if_type == COM_IF_RSA98III) { 3854 for(rsa98_tmp = 0; rsa98_tmp < 2048; rsa98_tmp++) 3855 inb(com->data_port); 3856 } 3857 outb(com->iobase + (com_fifo << port_shift), 3858 FIFO_RCV_RST | com->fifo_image); 3859#else 3860 outb(com->iobase + com_fifo, 3861 FIFO_RCV_RST | com->fifo_image); 3862#endif 3863 com_events -= (com->iptr - com->ibuf); 3864 com->iptr = com->ibuf; 3865 } 3866 enable_intr(); 3867 comstart(tp); 3868} 3869 3870static int 3871commctl(com, bits, how) 3872 struct com_s *com; 3873 int bits; 3874 int how; 3875{ 3876 int mcr; 3877 int msr; 3878 3879 if (how == DMGET) { 3880 bits = TIOCM_LE; /* XXX - always enabled while open */ 3881 mcr = com->mcr_image; 3882 if (mcr & MCR_DTR) 3883 bits |= TIOCM_DTR; 3884 if (mcr & MCR_RTS) 3885 bits |= TIOCM_RTS; 3886 msr = com->prev_modem_status; 3887 if (msr & MSR_CTS) 3888 bits |= TIOCM_CTS; 3889 if (msr & MSR_DCD) 3890 bits |= TIOCM_CD; 3891 if (msr & MSR_DSR) 3892 bits |= TIOCM_DSR; 3893 /* 3894 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI 3895 * more volatile by reading the modem status a lot. Perhaps 3896 * we should latch both bits until the status is read here. 3897 */ 3898 if (msr & (MSR_RI | MSR_TERI)) 3899 bits |= TIOCM_RI; 3900 return (bits); 3901 } 3902 mcr = 0; 3903 if (bits & TIOCM_DTR) 3904 mcr |= MCR_DTR; 3905 if (bits & TIOCM_RTS) 3906 mcr |= MCR_RTS; 3907 if (com->gone) 3908 return(0); 3909 disable_intr(); 3910 switch (how) { 3911 case DMSET: 3912 outb(com->modem_ctl_port, 3913 com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE)); 3914 break; 3915 case DMBIS: 3916 outb(com->modem_ctl_port, com->mcr_image |= mcr); 3917 break; 3918 case DMBIC: 3919 outb(com->modem_ctl_port, com->mcr_image &= ~mcr); 3920 break; 3921 } 3922 enable_intr(); 3923 return (0); 3924} 3925 3926static void 3927siosettimeout() 3928{ 3929 struct com_s *com; 3930 bool_t someopen; 3931 int unit; 3932 3933 /* 3934 * Set our timeout period to 1 second if no polled devices are open. 3935 * Otherwise set it to max(1/200, 1/hz). 3936 * Enable timeouts iff some device is open. 3937 */ 3938 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3939 sio_timeout = hz; 3940 someopen = FALSE; 3941 for (unit = 0; unit < sio_numunits; ++unit) { 3942 com = com_addr(unit); 3943 if (com != NULL && com->tp != NULL 3944 && com->tp->t_state & TS_ISOPEN && !com->gone) { 3945 someopen = TRUE; 3946 if (com->poll || com->poll_output) { 3947 sio_timeout = hz > 200 ? hz / 200 : 1; 3948 break; 3949 } 3950 } 3951 } 3952 if (someopen) { 3953 sio_timeouts_until_log = hz / sio_timeout; 3954 sio_timeout_handle = timeout(comwakeup, (void *)NULL, 3955 sio_timeout); 3956 } else { 3957 /* Flush error messages, if any. */ 3958 sio_timeouts_until_log = 1; 3959 comwakeup((void *)NULL); 3960 untimeout(comwakeup, (void *)NULL, sio_timeout_handle); 3961 } 3962} 3963 3964static void 3965comwakeup(chan) 3966 void *chan; 3967{ 3968 struct com_s *com; 3969 int unit; 3970 3971 sio_timeout_handle = timeout(comwakeup, (void *)NULL, sio_timeout); 3972 3973 /* 3974 * Recover from lost output interrupts. 3975 * Poll any lines that don't use interrupts. 3976 */ 3977 for (unit = 0; unit < sio_numunits; ++unit) { 3978 com = com_addr(unit); 3979 if (com != NULL && !com->gone 3980 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) { 3981 disable_intr(); 3982 siointr1(com); 3983 enable_intr(); 3984 } 3985 } 3986 3987 /* 3988 * Check for and log errors, but not too often. 3989 */ 3990 if (--sio_timeouts_until_log > 0) 3991 return; 3992 sio_timeouts_until_log = hz / sio_timeout; 3993 for (unit = 0; unit < sio_numunits; ++unit) { 3994 int errnum; 3995 3996 com = com_addr(unit); 3997 if (com == NULL) 3998 continue; 3999 if (com->gone) 4000 continue; 4001 for (errnum = 0; errnum < CE_NTYPES; ++errnum) { 4002 u_int delta; 4003 u_long total; 4004 4005 disable_intr(); 4006 delta = com->delta_error_counts[errnum]; 4007 com->delta_error_counts[errnum] = 0; 4008 enable_intr(); 4009 if (delta == 0) 4010 continue; 4011 total = com->error_counts[errnum] += delta; 4012 log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n", 4013 unit, delta, error_desc[errnum], 4014 delta == 1 ? "" : "s", total); 4015 } 4016 } 4017} 4018 4019#ifdef PC98 4020/* commint is called when modem control line changes */ 4021static void 4022commint(dev_t dev) 4023{ 4024 register struct tty *tp; 4025 int stat,delta; 4026 struct com_s *com; 4027 int mynor,unit; 4028 4029 mynor = minor(dev); 4030 unit = MINOR_TO_UNIT(mynor); 4031 com = com_addr(unit); 4032 tp = com->tp; 4033 4034 stat = com_tiocm_get(com); 4035 delta = com_tiocm_get_delta(com); 4036 4037 if (com->state & CS_CTS_OFLOW) { 4038 if (stat & TIOCM_CTS) 4039 com->state |= CS_ODEVREADY; 4040 else 4041 com->state &= ~CS_ODEVREADY; 4042 } 4043 if ((delta & TIOCM_CAR) && (mynor & CALLOUT_MASK) == 0) { 4044 if (stat & TIOCM_CAR ) 4045 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 4046 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 4047 /* negate DTR, RTS */ 4048 com_tiocm_bic(com, (tp->t_cflag & HUPCL) ? 4049 TIOCM_DTR|TIOCM_RTS|TIOCM_LE : TIOCM_LE ); 4050 /* disable IENABLE */ 4051 com_int_TxRx_disable( com ); 4052 } 4053 } 4054} 4055#endif 4056 4057static void 4058disc_optim(tp, t, com) 4059 struct tty *tp; 4060 struct termios *t; 4061 struct com_s *com; 4062{ 4063 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON)) 4064 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK)) 4065 && (!(t->c_iflag & PARMRK) 4066 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK)) 4067 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) 4068 && linesw[tp->t_line].l_rint == ttyinput) 4069 tp->t_state |= TS_CAN_BYPASS_L_RINT; 4070 else 4071 tp->t_state &= ~TS_CAN_BYPASS_L_RINT; 4072 com->hotchar = linesw[tp->t_line].l_hotchar; 4073} 4074 4075/* 4076 * Following are all routines needed for SIO to act as console 4077 */ 4078#include <sys/cons.h> 4079 4080struct siocnstate { 4081 u_char dlbl; 4082 u_char dlbh; 4083 u_char ier; 4084 u_char cfcr; 4085 u_char mcr; 4086}; 4087 4088static speed_t siocngetspeed __P((Port_t, struct speedtab *)); 4089static void siocnclose __P((struct siocnstate *sp, Port_t iobase)); 4090static void siocnopen __P((struct siocnstate *sp, Port_t iobase, int speed)); 4091static void siocntxwait __P((Port_t iobase)); 4092 4093static cn_probe_t siocnprobe; 4094static cn_init_t siocninit; 4095static cn_checkc_t siocncheckc; 4096static cn_getc_t siocngetc; 4097static cn_putc_t siocnputc; 4098 4099#ifdef __i386__ 4100CONS_DRIVER(sio, siocnprobe, siocninit, NULL, siocngetc, siocncheckc, 4101 siocnputc, NULL); 4102#endif 4103 4104/* To get the GDB related variables */ 4105#if DDB > 0 4106#include <ddb/ddb.h> 4107#endif 4108 4109static void 4110siocntxwait(iobase) 4111 Port_t iobase; 4112{ 4113 int timo; 4114 4115 /* 4116 * Wait for any pending transmission to finish. Required to avoid 4117 * the UART lockup bug when the speed is changed, and for normal 4118 * transmits. 4119 */ 4120 timo = 100000; 4121 while ((inb(iobase + com_lsr) & (LSR_TSRE | LSR_TXRDY)) 4122 != (LSR_TSRE | LSR_TXRDY) && --timo != 0) 4123 ; 4124} 4125 4126/* 4127 * Read the serial port specified and try to figure out what speed 4128 * it's currently running at. We're assuming the serial port has 4129 * been initialized and is basicly idle. This routine is only intended 4130 * to be run at system startup. 4131 * 4132 * If the value read from the serial port doesn't make sense, return 0. 4133 */ 4134 4135static speed_t 4136siocngetspeed(iobase, table) 4137 Port_t iobase; 4138 struct speedtab *table; 4139{ 4140 int code; 4141 u_char dlbh; 4142 u_char dlbl; 4143 u_char cfcr; 4144 4145 cfcr = inb(iobase + com_cfcr); 4146 outb(iobase + com_cfcr, CFCR_DLAB | cfcr); 4147 4148 dlbl = inb(iobase + com_dlbl); 4149 dlbh = inb(iobase + com_dlbh); 4150 4151 outb(iobase + com_cfcr, cfcr); 4152 4153 code = dlbh << 8 | dlbl; 4154 4155 for (; table->sp_speed != -1; table++) 4156 if (table->sp_code == code) 4157 return (table->sp_speed); 4158 4159 return 0; /* didn't match anything sane */ 4160} 4161 4162static void 4163siocnopen(sp, iobase, speed) 4164 struct siocnstate *sp; 4165 Port_t iobase; 4166 int speed; 4167{ 4168 int divisor; 4169 u_char dlbh; 4170 u_char dlbl; 4171 4172 /* 4173 * Save all the device control registers except the fifo register 4174 * and set our default ones (cs8 -parenb speed=comdefaultrate). 4175 * We can't save the fifo register since it is read-only. 4176 */ 4177 sp->ier = inb(iobase + com_ier); 4178 outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */ 4179 siocntxwait(iobase); 4180 sp->cfcr = inb(iobase + com_cfcr); 4181 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 4182 sp->dlbl = inb(iobase + com_dlbl); 4183 sp->dlbh = inb(iobase + com_dlbh); 4184 /* 4185 * Only set the divisor registers if they would change, since on 4186 * some 16550 incompatibles (Startech), setting them clears the 4187 * data input register. This also reduces the effects of the 4188 * UMC8669F bug. 4189 */ 4190 divisor = ttspeedtab(speed, comspeedtab); 4191 dlbl = divisor & 0xFF; 4192 if (sp->dlbl != dlbl) 4193 outb(iobase + com_dlbl, dlbl); 4194 dlbh = (u_int) divisor >> 8; 4195 if (sp->dlbh != dlbh) 4196 outb(iobase + com_dlbh, dlbh); 4197 outb(iobase + com_cfcr, CFCR_8BITS); 4198 sp->mcr = inb(iobase + com_mcr); 4199 /* 4200 * We don't want interrupts, but must be careful not to "disable" 4201 * them by clearing the MCR_IENABLE bit, since that might cause 4202 * an interrupt by floating the IRQ line. 4203 */ 4204 outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS); 4205} 4206 4207static void 4208siocnclose(sp, iobase) 4209 struct siocnstate *sp; 4210 Port_t iobase; 4211{ 4212 /* 4213 * Restore the device control registers. 4214 */ 4215 siocntxwait(iobase); 4216 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS); 4217 if (sp->dlbl != inb(iobase + com_dlbl)) 4218 outb(iobase + com_dlbl, sp->dlbl); 4219 if (sp->dlbh != inb(iobase + com_dlbh)) 4220 outb(iobase + com_dlbh, sp->dlbh); 4221 outb(iobase + com_cfcr, sp->cfcr); 4222 /* 4223 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them. 4224 */ 4225 outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS); 4226 outb(iobase + com_ier, sp->ier); 4227} 4228 4229static void 4230siocnprobe(cp) 4231 struct consdev *cp; 4232{ 4233 speed_t boot_speed; 4234 u_char cfcr; 4235 int s, unit; 4236 struct siocnstate sp; 4237 4238 /* 4239 * Find our first enabled console, if any. If it is a high-level 4240 * console device, then initialize it and return successfully. 4241 * If it is a low-level console device, then initialize it and 4242 * return unsuccessfully. It must be initialized in both cases 4243 * for early use by console drivers and debuggers. Initializing 4244 * the hardware is not necessary in all cases, since the i/o 4245 * routines initialize it on the fly, but it is necessary if 4246 * input might arrive while the hardware is switched back to an 4247 * uninitialized state. We can't handle multiple console devices 4248 * yet because our low-level routines don't take a device arg. 4249 * We trust the user to set the console flags properly so that we 4250 * don't need to probe. 4251 */ 4252 cp->cn_pri = CN_DEAD; 4253 4254 for (unit = 0; unit < 16; unit++) { /* XXX need to know how many */ 4255 int flags; 4256 int disabled; 4257 if (resource_int_value("sio", unit, "disabled", &disabled) == 0) { 4258 if (disabled) 4259 continue; 4260 } 4261 if (resource_int_value("sio", unit, "flags", &flags)) 4262 continue; 4263 if (COM_CONSOLE(flags) || COM_DEBUGGER(flags)) { 4264 int port; 4265 Port_t iobase; 4266 4267 if (resource_int_value("sio", unit, "port", &port)) 4268 continue; 4269 iobase = port; 4270 s = spltty(); 4271 if (boothowto & RB_SERIAL) { 4272 boot_speed = siocngetspeed(iobase, comspeedtab); 4273 if (boot_speed) 4274 comdefaultrate = boot_speed; 4275 } 4276 4277 /* 4278 * Initialize the divisor latch. We can't rely on 4279 * siocnopen() to do this the first time, since it 4280 * avoids writing to the latch if the latch appears 4281 * to have the correct value. Also, if we didn't 4282 * just read the speed from the hardware, then we 4283 * need to set the speed in hardware so that 4284 * switching it later is null. 4285 */ 4286 cfcr = inb(iobase + com_cfcr); 4287 outb(iobase + com_cfcr, CFCR_DLAB | cfcr); 4288 outb(iobase + com_dlbl, 4289 COMBRD(comdefaultrate) & 0xff); 4290 outb(iobase + com_dlbh, 4291 (u_int) COMBRD(comdefaultrate) >> 8); 4292 outb(iobase + com_cfcr, cfcr); 4293 4294 siocnopen(&sp, iobase, comdefaultrate); 4295 4296 splx(s); 4297 if (COM_CONSOLE(flags) && !COM_LLCONSOLE(flags)) { 4298 cp->cn_dev = makedev(CDEV_MAJOR, unit); 4299 cp->cn_pri = COM_FORCECONSOLE(flags) 4300 || boothowto & RB_SERIAL 4301 ? CN_REMOTE : CN_NORMAL; 4302 siocniobase = iobase; 4303 siocnunit = unit; 4304 } 4305 if (COM_DEBUGGER(flags)) { 4306 printf("sio%d: gdb debugging port\n", unit); 4307 siogdbiobase = iobase; 4308 siogdbunit = unit; 4309#if DDB > 0 4310 gdbdev = makedev(CDEV_MAJOR, unit); 4311 gdb_getc = siocngetc; 4312 gdb_putc = siocnputc; 4313#endif 4314 } 4315 } 4316 } 4317#ifdef __i386__ 4318#if DDB > 0 4319 /* 4320 * XXX Ugly Compatability. 4321 * If no gdb port has been specified, set it to be the console 4322 * as some configuration files don't specify the gdb port. 4323 */ 4324 if (gdbdev == NODEV && (boothowto & RB_GDB)) { 4325 printf("Warning: no GDB port specified. Defaulting to sio%d.\n", 4326 siocnunit); 4327 printf("Set flag 0x80 on desired GDB port in your\n"); 4328 printf("configuration file (currently sio only).\n"); 4329 siogdbiobase = siocniobase; 4330 siogdbunit = siocnunit; 4331 gdbdev = makedev(CDEV_MAJOR, siocnunit); 4332 gdb_getc = siocngetc; 4333 gdb_putc = siocnputc; 4334 } 4335#endif 4336#endif 4337} 4338 4339#ifdef __alpha__ 4340 4341CONS_DRIVER(sio, NULL, NULL, NULL, siocngetc, siocncheckc, siocnputc, NULL); 4342 4343int 4344siocnattach(port, speed) 4345 int port; 4346 int speed; 4347{ 4348 int s; 4349 u_char cfcr; 4350 struct siocnstate sp; 4351 4352 siocniobase = port; 4353 comdefaultrate = speed; 4354 sio_consdev.cn_pri = CN_NORMAL; 4355 sio_consdev.cn_dev = makedev(CDEV_MAJOR, 0); 4356 4357 s = spltty(); 4358 4359 /* 4360 * Initialize the divisor latch. We can't rely on 4361 * siocnopen() to do this the first time, since it 4362 * avoids writing to the latch if the latch appears 4363 * to have the correct value. Also, if we didn't 4364 * just read the speed from the hardware, then we 4365 * need to set the speed in hardware so that 4366 * switching it later is null. 4367 */ 4368 cfcr = inb(siocniobase + com_cfcr); 4369 outb(siocniobase + com_cfcr, CFCR_DLAB | cfcr); 4370 outb(siocniobase + com_dlbl, 4371 COMBRD(comdefaultrate) & 0xff); 4372 outb(siocniobase + com_dlbh, 4373 (u_int) COMBRD(comdefaultrate) >> 8); 4374 outb(siocniobase + com_cfcr, cfcr); 4375 4376 siocnopen(&sp, siocniobase, comdefaultrate); 4377 splx(s); 4378 4379 cn_tab = &sio_consdev; 4380 return 0; 4381} 4382 4383int 4384siogdbattach(port, speed) 4385 int port; 4386 int speed; 4387{ 4388 int s; 4389 u_char cfcr; 4390 struct siocnstate sp; 4391 4392 siogdbiobase = port; 4393 gdbdefaultrate = speed; 4394 4395 s = spltty(); 4396 4397 /* 4398 * Initialize the divisor latch. We can't rely on 4399 * siocnopen() to do this the first time, since it 4400 * avoids writing to the latch if the latch appears 4401 * to have the correct value. Also, if we didn't 4402 * just read the speed from the hardware, then we 4403 * need to set the speed in hardware so that 4404 * switching it later is null. 4405 */ 4406 cfcr = inb(siogdbiobase + com_cfcr); 4407 outb(siogdbiobase + com_cfcr, CFCR_DLAB | cfcr); 4408 outb(siogdbiobase + com_dlbl, 4409 COMBRD(gdbdefaultrate) & 0xff); 4410 outb(siogdbiobase + com_dlbh, 4411 (u_int) COMBRD(gdbdefaultrate) >> 8); 4412 outb(siogdbiobase + com_cfcr, cfcr); 4413 4414 siocnopen(&sp, siogdbiobase, gdbdefaultrate); 4415 splx(s); 4416 4417 return 0; 4418} 4419 4420#endif 4421 4422static void 4423siocninit(cp) 4424 struct consdev *cp; 4425{ 4426 comconsole = DEV_TO_UNIT(cp->cn_dev); 4427} 4428 4429static int 4430siocncheckc(dev) 4431 dev_t dev; 4432{ 4433 int c; 4434 Port_t iobase; 4435 int s; 4436 struct siocnstate sp; 4437 4438 if (minor(dev) == siogdbunit) 4439 iobase = siogdbiobase; 4440 else 4441 iobase = siocniobase; 4442 s = spltty(); 4443 siocnopen(&sp, iobase, comdefaultrate); 4444 if (inb(iobase + com_lsr) & LSR_RXRDY) 4445 c = inb(iobase + com_data); 4446 else 4447 c = -1; 4448 siocnclose(&sp, iobase); 4449 splx(s); 4450 return (c); 4451} 4452 4453 4454int 4455siocngetc(dev) 4456 dev_t dev; 4457{ 4458 int c; 4459 Port_t iobase; 4460 int s; 4461 struct siocnstate sp; 4462 4463 if (minor(dev) == siogdbunit) 4464 iobase = siogdbiobase; 4465 else 4466 iobase = siocniobase; 4467 s = spltty(); 4468 siocnopen(&sp, iobase, comdefaultrate); 4469 while (!(inb(iobase + com_lsr) & LSR_RXRDY)) 4470 ; 4471 c = inb(iobase + com_data); 4472 siocnclose(&sp, iobase); 4473 splx(s); 4474 return (c); 4475} 4476 4477void 4478siocnputc(dev, c) 4479 dev_t dev; 4480 int c; 4481{ 4482 int s; 4483 struct siocnstate sp; 4484 Port_t iobase; 4485 4486 if (minor(dev) == siogdbunit) 4487 iobase = siogdbiobase; 4488 else 4489 iobase = siocniobase; 4490 s = spltty(); 4491 siocnopen(&sp, iobase, comdefaultrate); 4492 siocntxwait(iobase); 4493 outb(iobase + com_data, c); 4494 siocnclose(&sp, iobase); 4495 splx(s); 4496} 4497 4498#ifdef __alpha__ 4499int 4500siogdbgetc() 4501{ 4502 int c; 4503 Port_t iobase; 4504 int s; 4505 struct siocnstate sp; 4506 4507 iobase = siogdbiobase; 4508 s = spltty(); 4509 siocnopen(&sp, iobase, gdbdefaultrate); 4510 while (!(inb(iobase + com_lsr) & LSR_RXRDY)) 4511 ; 4512 c = inb(iobase + com_data); 4513 siocnclose(&sp, iobase); 4514 splx(s); 4515 return (c); 4516} 4517 4518void 4519siogdbputc(c) 4520 int c; 4521{ 4522 int s; 4523 struct siocnstate sp; 4524 4525 s = spltty(); 4526 siocnopen(&sp, siogdbiobase, gdbdefaultrate); 4527 siocntxwait(siogdbiobase); 4528 outb(siogdbiobase + com_data, c); 4529 siocnclose(&sp, siogdbiobase); 4530 splx(s); 4531} 4532#endif 4533 4534DRIVER_MODULE(sio, isa, sio_isa_driver, sio_devclass, 0, 0); 4535#if NCARD > 0 4536DRIVER_MODULE(sio, pccard, sio_pccard_driver, sio_devclass, 0, 0); 4537#endif 4538 4539#ifdef PC98 4540/* 4541 * pc98 local function 4542 */ 4543 4544static void 4545com_tiocm_set(struct com_s *com, int msr) 4546{ 4547 int s; 4548 int tmp = 0; 4549 int mask = CMD8251_TxEN|CMD8251_RxEN|CMD8251_DTR|CMD8251_RTS; 4550 4551 s=spltty(); 4552 com->pc98_prev_modem_status = ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ) 4553 | ( com->pc98_prev_modem_status & ~(TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4554 tmp |= (CMD8251_TxEN|CMD8251_RxEN); 4555 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4556 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4557 pc98_i8251_clear_or_cmd( com, mask, tmp ); 4558 splx(s); 4559} 4560 4561static void 4562com_tiocm_bis(struct com_s *com, int msr) 4563{ 4564 int s; 4565 int tmp = 0; 4566 4567 s=spltty(); 4568 com->pc98_prev_modem_status |= ( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4569 tmp |= CMD8251_TxEN|CMD8251_RxEN; 4570 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4571 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4572 4573 pc98_i8251_or_cmd( com, tmp ); 4574 splx(s); 4575} 4576 4577static void 4578com_tiocm_bic(struct com_s *com, int msr) 4579{ 4580 int s; 4581 int tmp = msr; 4582 4583 s=spltty(); 4584 com->pc98_prev_modem_status &= ~( msr & (TIOCM_LE|TIOCM_DTR|TIOCM_RTS) ); 4585 if ( msr & TIOCM_DTR ) tmp |= CMD8251_DTR; 4586 if ( msr & TIOCM_RTS ) tmp |= CMD8251_RTS; 4587 4588 pc98_i8251_clear_cmd( com, tmp ); 4589 splx(s); 4590} 4591 4592static int 4593com_tiocm_get(struct com_s *com) 4594{ 4595 return( com->pc98_prev_modem_status ); 4596} 4597 4598static int 4599com_tiocm_get_delta(struct com_s *com) 4600{ 4601 int tmp; 4602 4603 tmp = com->pc98_modem_delta; 4604 com->pc98_modem_delta = 0; 4605 return( tmp ); 4606} 4607 4608/* convert to TIOCM_?? ( ioctl.h ) */ 4609static int 4610pc98_get_modem_status(struct com_s *com) 4611{ 4612 register int msr; 4613 4614 msr = com->pc98_prev_modem_status 4615 & ~(TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 4616 if (com->pc98_8251fifo_enable) { 4617 int stat2; 4618 4619 stat2 = inb(I8251F_msr); 4620 if ( stat2 & CICSCDF_CD ) msr |= TIOCM_CAR; 4621 if ( stat2 & CICSCDF_CI ) msr |= TIOCM_RI; 4622 if ( stat2 & CICSCDF_DR ) msr |= TIOCM_DSR; 4623 if ( stat2 & CICSCDF_CS ) msr |= TIOCM_CTS; 4624#if COM_CARRIER_DETECT_EMULATE 4625 if ( msr & (TIOCM_DSR|TIOCM_CTS) ) { 4626 msr |= TIOCM_CAR; 4627 } 4628#endif 4629 } else { 4630 int stat, stat2; 4631 4632 stat = inb(com->sts_port); 4633 stat2 = inb(com->in_modem_port); 4634 if ( !(stat2 & CICSCD_CD) ) msr |= TIOCM_CAR; 4635 if ( !(stat2 & CICSCD_CI) ) msr |= TIOCM_RI; 4636 if ( stat & STS8251_DSR ) msr |= TIOCM_DSR; 4637 if ( !(stat2 & CICSCD_CS) ) msr |= TIOCM_CTS; 4638#if COM_CARRIER_DETECT_EMULATE 4639 if ( msr & (TIOCM_DSR|TIOCM_CTS) ) { 4640 msr |= TIOCM_CAR; 4641 } 4642#endif 4643 } 4644 return(msr); 4645} 4646 4647static void 4648pc98_check_msr(void* chan) 4649{ 4650 int msr, delta; 4651 int s; 4652 register struct tty *tp; 4653 struct com_s *com; 4654 int mynor; 4655 int unit; 4656 dev_t dev; 4657 4658 dev=(dev_t)chan; 4659 mynor = minor(dev); 4660 unit = MINOR_TO_UNIT(mynor); 4661 com = com_addr(unit); 4662 tp = com->tp; 4663 4664 s = spltty(); 4665 msr = pc98_get_modem_status(com); 4666 /* make change flag */ 4667 delta = msr ^ com->pc98_prev_modem_status; 4668 if ( delta & TIOCM_CAR ) { 4669 if ( com->modem_car_chg_timer ) { 4670 if ( -- com->modem_car_chg_timer ) 4671 msr ^= TIOCM_CAR; 4672 } else { 4673 if ((com->modem_car_chg_timer = (msr & TIOCM_CAR) ? 4674 DCD_ON_RECOGNITION : DCD_OFF_TOLERANCE) != 0) 4675 msr ^= TIOCM_CAR; 4676 } 4677 } else 4678 com->modem_car_chg_timer = 0; 4679 delta = ( msr ^ com->pc98_prev_modem_status ) & 4680 (TIOCM_CAR|TIOCM_RI|TIOCM_DSR|TIOCM_CTS); 4681 com->pc98_prev_modem_status = msr; 4682 delta = ( com->pc98_modem_delta |= delta ); 4683 splx(s); 4684 if ( com->modem_checking || (tp->t_state & (TS_ISOPEN)) ) { 4685 if ( delta ) { 4686 commint(dev); 4687 } 4688 timeout(pc98_check_msr, (caddr_t)dev, 4689 PC98_CHECK_MODEM_INTERVAL); 4690 } else { 4691 com->modem_checking = 0; 4692 } 4693} 4694 4695static void 4696pc98_msrint_start(dev_t dev) 4697{ 4698 struct com_s *com; 4699 int mynor; 4700 int unit; 4701 int s = spltty(); 4702 4703 mynor = minor(dev); 4704 unit = MINOR_TO_UNIT(mynor); 4705 com = com_addr(unit); 4706 /* modem control line check routine envoke interval is 1/10 sec */ 4707 if ( com->modem_checking == 0 ) { 4708 com->pc98_prev_modem_status = pc98_get_modem_status(com); 4709 com->pc98_modem_delta = 0; 4710 timeout(pc98_check_msr, (caddr_t)dev, 4711 PC98_CHECK_MODEM_INTERVAL); 4712 com->modem_checking = 1; 4713 } 4714 splx(s); 4715} 4716 4717static void 4718pc98_disable_i8251_interrupt(struct com_s *com, int mod) 4719{ 4720 /* disable interrupt */ 4721 register int tmp; 4722 4723 mod |= ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4724 COM_INT_DISABLE 4725 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4726 outb( com->intr_ctrl_port, (com->intr_enable&=~mod) | tmp ); 4727 COM_INT_ENABLE 4728} 4729 4730static void 4731pc98_enable_i8251_interrupt(struct com_s *com, int mod) 4732{ 4733 register int tmp; 4734 4735 COM_INT_DISABLE 4736 tmp = inb( com->intr_ctrl_port ) & ~(IEN_Tx|IEN_TxEMP|IEN_Rx); 4737 outb( com->intr_ctrl_port, (com->intr_enable|=mod) | tmp ); 4738 COM_INT_ENABLE 4739} 4740 4741static int 4742pc98_check_i8251_interrupt(struct com_s *com) 4743{ 4744 return ( com->intr_enable & 0x07 ); 4745} 4746 4747static void 4748pc98_i8251_clear_cmd(struct com_s *com, int x) 4749{ 4750 int tmp; 4751 4752 COM_INT_DISABLE 4753 tmp = com->pc98_prev_siocmd & ~(x); 4754 if (com->pc98_8251fifo_enable) 4755 outb(I8251F_fcr, 0); 4756 outb(com->cmd_port, tmp); 4757 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4758 if (com->pc98_8251fifo_enable) 4759 outb(I8251F_fcr, CTRL8251F_ENABLE); 4760 COM_INT_ENABLE 4761} 4762 4763static void 4764pc98_i8251_or_cmd(struct com_s *com, int x) 4765{ 4766 int tmp; 4767 4768 COM_INT_DISABLE 4769 if (com->pc98_8251fifo_enable) 4770 outb(I8251F_fcr, 0); 4771 tmp = com->pc98_prev_siocmd | (x); 4772 outb(com->cmd_port, tmp); 4773 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4774 if (com->pc98_8251fifo_enable) 4775 outb(I8251F_fcr, CTRL8251F_ENABLE); 4776 COM_INT_ENABLE 4777} 4778 4779static void 4780pc98_i8251_set_cmd(struct com_s *com, int x) 4781{ 4782 int tmp; 4783 4784 COM_INT_DISABLE 4785 if (com->pc98_8251fifo_enable) 4786 outb(I8251F_fcr, 0); 4787 tmp = (x); 4788 outb(com->cmd_port, tmp); 4789 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4790 if (com->pc98_8251fifo_enable) 4791 outb(I8251F_fcr, CTRL8251F_ENABLE); 4792 COM_INT_ENABLE 4793} 4794 4795static void 4796pc98_i8251_clear_or_cmd(struct com_s *com, int clr, int x) 4797{ 4798 int tmp; 4799 COM_INT_DISABLE 4800 if (com->pc98_8251fifo_enable) 4801 outb(I8251F_fcr, 0); 4802 tmp = com->pc98_prev_siocmd & ~(clr); 4803 tmp |= (x); 4804 outb(com->cmd_port, tmp); 4805 com->pc98_prev_siocmd = tmp & ~(CMD8251_ER|CMD8251_RESET|CMD8251_EH); 4806 if (com->pc98_8251fifo_enable) 4807 outb(I8251F_fcr, CTRL8251F_ENABLE); 4808 COM_INT_ENABLE 4809} 4810 4811static int 4812pc98_i8251_get_cmd(struct com_s *com) 4813{ 4814 return com->pc98_prev_siocmd; 4815} 4816 4817static int 4818pc98_i8251_get_mod(struct com_s *com) 4819{ 4820 return com->pc98_prev_siomod; 4821} 4822 4823static void 4824pc98_i8251_reset(struct com_s *com, int mode, int command) 4825{ 4826 if (com->pc98_8251fifo_enable) 4827 outb(I8251F_fcr, 0); 4828 outb(com->cmd_port, 0); /* dummy */ 4829 DELAY(2); 4830 outb(com->cmd_port, 0); /* dummy */ 4831 DELAY(2); 4832 outb(com->cmd_port, 0); /* dummy */ 4833 DELAY(2); 4834 outb(com->cmd_port, CMD8251_RESET); /* internal reset */ 4835 DELAY(2); 4836 outb(com->cmd_port, mode ); /* mode register */ 4837 com->pc98_prev_siomod = mode; 4838 DELAY(2); 4839 pc98_i8251_set_cmd( com, (command|CMD8251_ER) ); 4840 DELAY(10); 4841 if (com->pc98_8251fifo_enable) 4842 outb(I8251F_fcr, CTRL8251F_ENABLE | 4843 CTRL8251F_XMT_RST | CTRL8251F_RCV_RST); 4844} 4845 4846static void 4847pc98_check_sysclock(void) 4848{ 4849 /* get system clock from port */ 4850 if ( pc98_machine_type & M_8M ) { 4851 /* 8 MHz system & H98 */ 4852 sysclock = 8; 4853 } else { 4854 /* 5 MHz system */ 4855 sysclock = 5; 4856 } 4857} 4858 4859static void 4860com_cflag_and_speed_set( struct com_s *com, int cflag, int speed) 4861{ 4862 int cfcr=0, count; 4863 int previnterrupt; 4864 4865 count = pc98_ttspeedtab( com, speed ); 4866 if ( count < 0 ) return; 4867 4868 previnterrupt = pc98_check_i8251_interrupt(com); 4869 pc98_disable_i8251_interrupt( com, IEN_Tx|IEN_TxEMP|IEN_Rx ); 4870 4871 switch ( cflag&CSIZE ) { 4872 case CS5: 4873 cfcr = MOD8251_5BITS; break; 4874 case CS6: 4875 cfcr = MOD8251_6BITS; break; 4876 case CS7: 4877 cfcr = MOD8251_7BITS; break; 4878 case CS8: 4879 cfcr = MOD8251_8BITS; break; 4880 } 4881 if ( cflag&PARENB ) { 4882 if ( cflag&PARODD ) 4883 cfcr |= MOD8251_PODD; 4884 else 4885 cfcr |= MOD8251_PEVEN; 4886 } else 4887 cfcr |= MOD8251_PDISAB; 4888 4889 if ( cflag&CSTOPB ) 4890 cfcr |= MOD8251_STOP2; 4891 else 4892 cfcr |= MOD8251_STOP1; 4893 4894 if ( count & 0x10000 ) 4895 cfcr |= MOD8251_CLKX1; 4896 else 4897 cfcr |= MOD8251_CLKX16; 4898 4899 if (epson_machine_id != 0x20) { /* XXX */ 4900 int tmp; 4901 while (!((tmp = inb(com->sts_port)) & STS8251_TxEMP)) 4902 ; 4903 } 4904 /* set baud rate from ospeed */ 4905 pc98_set_baud_rate( com, count ); 4906 4907 if ( cfcr != pc98_i8251_get_mod(com) ) 4908 pc98_i8251_reset(com, cfcr, pc98_i8251_get_cmd(com) ); 4909 4910 pc98_enable_i8251_interrupt( com, previnterrupt ); 4911} 4912 4913static int 4914pc98_ttspeedtab(struct com_s *com, int speed) 4915{ 4916 int if_type, effect_sp, count = -1, mod; 4917 4918 if_type = com->pc98_if_type & 0x0f; 4919 4920 switch (com->pc98_if_type) { 4921 case COM_IF_INTERNAL: 4922 if (PC98SIO_baud_rate_port(if_type) != -1) { 4923 count = ttspeedtab(speed, if_8251_type[if_type].speedtab); 4924 if (count > 0) { 4925 count |= COM1_EXT_CLOCK; 4926 break; 4927 } 4928 } 4929 4930 /* for *1CLK asynchronous! mode, TEFUTEFU */ 4931 mod = (sysclock == 5) ? 2457600 : 1996800; 4932 effect_sp = ttspeedtab( speed, pc98speedtab ); 4933 if ( effect_sp < 0 ) /* XXX */ 4934 effect_sp = ttspeedtab( (speed - 1), pc98speedtab ); 4935 if ( effect_sp <= 0 ) 4936 return effect_sp; 4937 if ( effect_sp == speed ) 4938 mod /= 16; 4939 if ( mod % effect_sp ) 4940 return(-1); 4941 count = mod / effect_sp; 4942 if ( count > 65535 ) 4943 return(-1); 4944 if ( effect_sp != speed ) 4945 count |= 0x10000; 4946 break; 4947 case COM_IF_PC9861K_1: 4948 case COM_IF_PC9861K_2: 4949 count = 1; 4950 break; 4951 case COM_IF_IND_SS_1: 4952 case COM_IF_IND_SS_2: 4953 case COM_IF_PIO9032B_1: 4954 case COM_IF_PIO9032B_2: 4955 if ( speed == 0 ) return 0; 4956 count = ttspeedtab( speed, if_8251_type[if_type].speedtab ); 4957 break; 4958 case COM_IF_B98_01_1: 4959 case COM_IF_B98_01_2: 4960 if ( speed == 0 ) return 0; 4961 count = ttspeedtab( speed, if_8251_type[if_type].speedtab ); 4962#ifdef B98_01_OLD 4963 if (count == 0 || count == 1) { 4964 count += 4; 4965 count |= 0x20000; /* x1 mode for 76800 and 153600 */ 4966 } 4967#endif 4968 break; 4969 } 4970 4971 return count; 4972} 4973 4974static void 4975pc98_set_baud_rate( struct com_s *com, int count ) 4976{ 4977 int if_type, io, s; 4978 4979 if_type = com->pc98_if_type & 0x0f; 4980 io = com->iobase & 0xff00; 4981 4982 switch (com->pc98_if_type) { 4983 case COM_IF_INTERNAL: 4984 if (PC98SIO_baud_rate_port(if_type) != -1) { 4985 if (count & COM1_EXT_CLOCK) { 4986 outb((Port_t)PC98SIO_baud_rate_port(if_type), count & 0xff); 4987 break; 4988 } else { 4989 outb((Port_t)PC98SIO_baud_rate_port(if_type), 0x09); 4990 } 4991 } 4992 4993 if ( count < 0 ) { 4994 printf( "[ Illegal count : %d ]", count ); 4995 return; 4996 } else if ( count == 0 ) 4997 return; 4998 /* set i8253 */ 4999 s = splclock(); 5000 if (count != 3) 5001 outb( 0x77, 0xb6 ); 5002 else 5003 outb( 0x77, 0xb4 ); 5004 outb( 0x5f, 0); 5005 outb( 0x75, count & 0xff ); 5006 outb( 0x5f, 0); 5007 outb( 0x75, (count >> 8) & 0xff ); 5008 splx(s); 5009 break; 5010 case COM_IF_IND_SS_1: 5011 case COM_IF_IND_SS_2: 5012 outb(io | PC98SIO_intr_ctrl_port(if_type), 0); 5013 outb(io | PC98SIO_baud_rate_port(if_type), 0); 5014 outb(io | PC98SIO_baud_rate_port(if_type), 0xc0); 5015 outb(io | PC98SIO_baud_rate_port(if_type), (count >> 8) | 0x80); 5016 outb(io | PC98SIO_baud_rate_port(if_type), count & 0xff); 5017 break; 5018 case COM_IF_PIO9032B_1: 5019 case COM_IF_PIO9032B_2: 5020 outb(io | PC98SIO_baud_rate_port(if_type), count); 5021 break; 5022 case COM_IF_B98_01_1: 5023 case COM_IF_B98_01_2: 5024 outb(io | PC98SIO_baud_rate_port(if_type), count & 0x0f); 5025#ifdef B98_01_OLD 5026 /* 5027 * Some old B98_01 board should be controlled 5028 * in different way, but this hasn't been tested yet. 5029 */ 5030 outb(io | PC98SIO_func_port(if_type), 5031 (count & 0x20000) ? 0xf0 : 0xf2); 5032#endif 5033 break; 5034 } 5035} 5036static int 5037pc98_check_if_type(device_t dev, struct siodev *iod) 5038{ 5039 int irr, io, if_type, tmp; 5040 static short irq_tab[2][8] = { 5041 { 3, 5, 6, 9, 10, 12, 13, -1}, 5042 { 3, 10, 12, 13, 5, 6, 9, -1} 5043 }; 5044 5045 iod->if_type = if_type = GET_IFTYPE(device_get_flags(dev)); 5046 if ((if_type < 0 || if_type > COM_IF_END1) && 5047 (if_type < 0x10 || if_type > COM_IF_END2)) 5048 return(-1); 5049 if_type &= 0x0f; 5050 iod->irq = 0; 5051 io = isa_get_port(dev) & 0xff00; 5052 5053 if (IS_8251(iod->if_type)) { 5054 if (PC98SIO_func_port(if_type) != -1) { 5055 outb(io | PC98SIO_func_port(if_type), 0xf2); 5056 tmp = ttspeedtab(9600, if_8251_type[if_type].speedtab); 5057 if (tmp != -1 && PC98SIO_baud_rate_port(if_type) != -1) 5058 outb(io | PC98SIO_baud_rate_port(if_type), tmp); 5059 } 5060 5061 iod->cmd = io | PC98SIO_cmd_port(if_type); 5062 iod->sts = io | PC98SIO_sts_port(if_type); 5063 iod->mod = io | PC98SIO_in_modem_port(if_type); 5064 iod->ctrl = io | PC98SIO_intr_ctrl_port(if_type); 5065 5066 if (iod->if_type == COM_IF_INTERNAL) { 5067 iod->irq = 4; 5068 5069 if (pc98_check_8251vfast()) { 5070 PC98SIO_baud_rate_port(if_type) = I8251F_div; 5071 if_8251_type[if_type].speedtab = pc98fast_speedtab; 5072 } 5073 } else { 5074 tmp = inb( iod->mod ) & if_8251_type[if_type].irr_mask; 5075 if ((isa_get_port(dev) & 0xff) == IO_COM2) 5076 iod->irq = irq_tab[0][tmp]; 5077 else 5078 iod->irq = irq_tab[1][tmp]; 5079 } 5080 } else { 5081 irr = if_16550a_type[if_type].irr_read; 5082#ifdef COM_MULTIPORT 5083 if (!COM_ISMULTIPORT(device_get_flags(dev)) || 5084 device_get_unit(dev) == COM_MPMASTER(device_get_flags(dev))) 5085#endif 5086 if (irr != -1) { 5087 tmp = inb(io | irr); 5088 if (isa_get_port(dev) & 0x01) /* XXX depend on RSB-384 */ 5089 iod->irq = irq_tab[1][tmp >> 3]; 5090 else 5091 iod->irq = irq_tab[0][tmp & 0x07]; 5092 } 5093 } 5094 if ( iod->irq == -1 ) return -1; 5095 5096 return 0; 5097} 5098static int 5099pc98_set_ioport(struct com_s *com) 5100{ 5101 int if_type = com->pc98_if_type & 0x0f; 5102 int io = com->iobase & 0xff00; 5103 5104 if (IS_8251(com->pc98_if_type)) { 5105 pc98_check_sysclock(); 5106 com->data_port = io | PC98SIO_data_port(if_type); 5107 com->cmd_port = io | PC98SIO_cmd_port(if_type); 5108 com->sts_port = io | PC98SIO_sts_port(if_type); 5109 com->in_modem_port = io | PC98SIO_in_modem_port(if_type); 5110 com->intr_ctrl_port = io | PC98SIO_intr_ctrl_port(if_type); 5111 5112 return 0; 5113 } 5114 5115 return -1; 5116} 5117static int 5118pc98_check_8251vfast(void) 5119{ 5120 int i; 5121 5122 outb(I8251F_div, 0x8c); 5123 DELAY(10); 5124 for (i = 0; i < 100; i++) { 5125 if ((inb(I8251F_div) & 0x80) != 0) { 5126 i = 0; 5127 break; 5128 } 5129 DELAY(1); 5130 } 5131 outb(I8251F_div, 0); 5132 DELAY(10); 5133 for (; i < 100; i++) { 5134 if ((inb(I8251F_div) & 0x80) == 0) 5135 return 1; 5136 DELAY(1); 5137 } 5138 5139 return 0; 5140} 5141static int 5142pc98_check_8251fifo(void) 5143{ 5144 u_char tmp1, tmp2; 5145 5146 tmp1 = inb(I8251F_iir); 5147 DELAY(10); 5148 tmp2 = inb(I8251F_iir); 5149 if (((tmp1 ^ tmp2) & 0x40) != 0 && ((tmp1 | tmp2) & 0x20) == 0) 5150 return 1; 5151 5152 return 0; 5153} 5154#endif /* PC98 defined */ 5155